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 android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.RequiresPermission; 25 import android.annotation.SdkConstant; 26 import android.annotation.SdkConstant.SdkConstantType; 27 import android.annotation.SuppressLint; 28 import android.annotation.SystemApi; 29 import android.annotation.SystemService; 30 import android.annotation.TestApi; 31 import android.app.NotificationManager; 32 import android.app.PendingIntent; 33 import android.bluetooth.BluetoothCodecConfig; 34 import android.bluetooth.BluetoothDevice; 35 import android.bluetooth.BluetoothProfile; 36 import android.compat.annotation.UnsupportedAppUsage; 37 import android.content.ComponentName; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.media.AudioAttributes.AttributeSystemUsage; 41 import android.media.audiopolicy.AudioPolicy; 42 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; 43 import android.media.audiopolicy.AudioProductStrategy; 44 import android.media.audiopolicy.AudioVolumeGroup; 45 import android.media.audiopolicy.AudioVolumeGroupChangeHandler; 46 import android.media.projection.MediaProjection; 47 import android.media.session.MediaController; 48 import android.media.session.MediaSession; 49 import android.media.session.MediaSessionLegacyHelper; 50 import android.media.session.MediaSessionManager; 51 import android.net.Uri; 52 import android.os.Binder; 53 import android.os.Build; 54 import android.os.Handler; 55 import android.os.IBinder; 56 import android.os.Looper; 57 import android.os.Message; 58 import android.os.Process; 59 import android.os.RemoteException; 60 import android.os.ServiceManager; 61 import android.os.SystemClock; 62 import android.os.UserHandle; 63 import android.provider.Settings; 64 import android.text.TextUtils; 65 import android.util.ArrayMap; 66 import android.util.Log; 67 import android.util.Pair; 68 import android.view.KeyEvent; 69 70 import com.android.internal.annotations.GuardedBy; 71 import com.android.internal.util.Preconditions; 72 73 import java.io.IOException; 74 import java.lang.annotation.Retention; 75 import java.lang.annotation.RetentionPolicy; 76 import java.lang.ref.WeakReference; 77 import java.util.ArrayList; 78 import java.util.Arrays; 79 import java.util.HashMap; 80 import java.util.HashSet; 81 import java.util.Iterator; 82 import java.util.List; 83 import java.util.Map; 84 import java.util.Objects; 85 import java.util.TreeMap; 86 import java.util.concurrent.ConcurrentHashMap; 87 import java.util.concurrent.Executor; 88 89 90 /** 91 * AudioManager provides access to volume and ringer mode control. 92 */ 93 @SystemService(Context.AUDIO_SERVICE) 94 public class AudioManager { 95 96 private Context mOriginalContext; 97 private Context mApplicationContext; 98 private long mVolumeKeyUpTime; 99 private boolean mUseFixedVolumeInitialized; 100 private boolean mUseFixedVolume; 101 private static final String TAG = "AudioManager"; 102 private static final boolean DEBUG = false; 103 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler(); 104 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler = 105 new AudioVolumeGroupChangeHandler(); 106 107 private static WeakReference<Context> sContext; 108 109 /** 110 * Broadcast intent, a hint for applications that audio is about to become 111 * 'noisy' due to a change in audio outputs. For example, this intent may 112 * be sent when a wired headset is unplugged, or when an A2DP audio 113 * sink is disconnected, and the audio system is about to automatically 114 * switch audio route to the speaker. Applications that are controlling 115 * audio streams may consider pausing, reducing volume or some other action 116 * on receipt of this intent so as not to surprise the user with audio 117 * from the speaker. 118 */ 119 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 120 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; 121 122 /** 123 * Sticky broadcast intent action indicating that the ringer mode has 124 * changed. Includes the new ringer mode. 125 * 126 * @see #EXTRA_RINGER_MODE 127 */ 128 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 129 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; 130 131 /** 132 * @hide 133 * Sticky broadcast intent action indicating that the internal ringer mode has 134 * changed. Includes the new ringer mode. 135 * 136 * @see #EXTRA_RINGER_MODE 137 */ 138 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 139 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION = 140 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION"; 141 142 /** 143 * The new ringer mode. 144 * 145 * @see #RINGER_MODE_CHANGED_ACTION 146 * @see #RINGER_MODE_NORMAL 147 * @see #RINGER_MODE_SILENT 148 * @see #RINGER_MODE_VIBRATE 149 */ 150 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; 151 152 /** 153 * Broadcast intent action indicating that the vibrate setting has 154 * changed. Includes the vibrate type and its new setting. 155 * 156 * @see #EXTRA_VIBRATE_TYPE 157 * @see #EXTRA_VIBRATE_SETTING 158 * @deprecated Applications should maintain their own vibrate policy based on 159 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 160 */ 161 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 162 public static final String VIBRATE_SETTING_CHANGED_ACTION = 163 "android.media.VIBRATE_SETTING_CHANGED"; 164 165 /** 166 * @hide Broadcast intent when the volume for a particular stream type changes. 167 * Includes the stream, the new volume and previous volumes. 168 * Notes: 169 * - for internal platform use only, do not make public, 170 * - never used for "remote" volume changes 171 * 172 * @see #EXTRA_VOLUME_STREAM_TYPE 173 * @see #EXTRA_VOLUME_STREAM_VALUE 174 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 175 */ 176 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 177 @UnsupportedAppUsage 178 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; 179 180 /** 181 * @hide Broadcast intent when the devices for a particular stream type changes. 182 * Includes the stream, the new devices and previous devices. 183 * Notes: 184 * - for internal platform use only, do not make public, 185 * - never used for "remote" volume changes 186 * 187 * @see #EXTRA_VOLUME_STREAM_TYPE 188 * @see #EXTRA_VOLUME_STREAM_DEVICES 189 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES 190 * @see #getDevicesForStream 191 */ 192 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 193 public static final String STREAM_DEVICES_CHANGED_ACTION = 194 "android.media.STREAM_DEVICES_CHANGED_ACTION"; 195 196 /** 197 * @hide Broadcast intent when a stream mute state changes. 198 * Includes the stream that changed and the new mute state 199 * 200 * @see #EXTRA_VOLUME_STREAM_TYPE 201 * @see #EXTRA_STREAM_VOLUME_MUTED 202 */ 203 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 204 public static final String STREAM_MUTE_CHANGED_ACTION = 205 "android.media.STREAM_MUTE_CHANGED_ACTION"; 206 207 /** 208 * @hide Broadcast intent when the master mute state changes. 209 * Includes the the new volume 210 * 211 * @see #EXTRA_MASTER_VOLUME_MUTED 212 */ 213 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 214 public static final String MASTER_MUTE_CHANGED_ACTION = 215 "android.media.MASTER_MUTE_CHANGED_ACTION"; 216 217 /** 218 * The new vibrate setting for a particular type. 219 * 220 * @see #VIBRATE_SETTING_CHANGED_ACTION 221 * @see #EXTRA_VIBRATE_TYPE 222 * @see #VIBRATE_SETTING_ON 223 * @see #VIBRATE_SETTING_OFF 224 * @see #VIBRATE_SETTING_ONLY_SILENT 225 * @deprecated Applications should maintain their own vibrate policy based on 226 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 227 */ 228 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; 229 230 /** 231 * The vibrate type whose setting has changed. 232 * 233 * @see #VIBRATE_SETTING_CHANGED_ACTION 234 * @see #VIBRATE_TYPE_NOTIFICATION 235 * @see #VIBRATE_TYPE_RINGER 236 * @deprecated Applications should maintain their own vibrate policy based on 237 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 238 */ 239 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; 240 241 /** 242 * @hide The stream type for the volume changed intent. 243 */ 244 @UnsupportedAppUsage 245 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; 246 247 /** 248 * @hide 249 * The stream type alias for the volume changed intent. 250 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream 251 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also 252 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices, 253 * {@link #STREAM_MUSIC} on others (e.g. a television). 254 */ 255 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS = 256 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS"; 257 258 /** 259 * @hide The volume associated with the stream for the volume changed intent. 260 */ 261 @UnsupportedAppUsage 262 public static final String EXTRA_VOLUME_STREAM_VALUE = 263 "android.media.EXTRA_VOLUME_STREAM_VALUE"; 264 265 /** 266 * @hide The previous volume associated with the stream for the volume changed intent. 267 */ 268 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE = 269 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE"; 270 271 /** 272 * @hide The devices associated with the stream for the stream devices changed intent. 273 */ 274 public static final String EXTRA_VOLUME_STREAM_DEVICES = 275 "android.media.EXTRA_VOLUME_STREAM_DEVICES"; 276 277 /** 278 * @hide The previous devices associated with the stream for the stream devices changed intent. 279 */ 280 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES = 281 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES"; 282 283 /** 284 * @hide The new master volume mute state for the master mute changed intent. 285 * Value is boolean 286 */ 287 public static final String EXTRA_MASTER_VOLUME_MUTED = 288 "android.media.EXTRA_MASTER_VOLUME_MUTED"; 289 290 /** 291 * @hide The new stream volume mute state for the stream mute changed intent. 292 * Value is boolean 293 */ 294 public static final String EXTRA_STREAM_VOLUME_MUTED = 295 "android.media.EXTRA_STREAM_VOLUME_MUTED"; 296 297 /** 298 * Broadcast Action: Wired Headset plugged in or unplugged. 299 * 300 * You <em>cannot</em> receive this through components declared 301 * in manifests, only by explicitly registering for it with 302 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 303 * Context.registerReceiver()}. 304 * 305 * <p>The intent will have the following extra values: 306 * <ul> 307 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> 308 * <li><em>name</em> - Headset type, human readable string </li> 309 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li> 310 * </ul> 311 * </ul> 312 */ 313 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 314 public static final String ACTION_HEADSET_PLUG = 315 "android.intent.action.HEADSET_PLUG"; 316 317 /** 318 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged. 319 * 320 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE}, 321 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}. 322 * <p>It can only be received by explicitly registering for it with 323 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}. 324 */ 325 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 326 public static final String ACTION_HDMI_AUDIO_PLUG = 327 "android.media.action.HDMI_AUDIO_PLUG"; 328 329 /** 330 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in 331 * or unplugged. 332 * An integer value of 1 indicates a plugged-in state, 0 is unplugged. 333 */ 334 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE"; 335 336 /** 337 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels 338 * supported by the HDMI device. 339 * The corresponding integer value is only available when the device is plugged in (as expressed 340 * by {@link #EXTRA_AUDIO_PLUG_STATE}). 341 */ 342 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT"; 343 344 /** 345 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by 346 * the connected HDMI device. 347 * The corresponding array of encoding values is only available when the device is plugged in 348 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in 349 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use 350 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values. 351 */ 352 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS"; 353 354 /** Used to identify the volume of audio streams for phone calls */ 355 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; 356 /** Used to identify the volume of audio streams for system sounds */ 357 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; 358 /** Used to identify the volume of audio streams for the phone ring */ 359 public static final int STREAM_RING = AudioSystem.STREAM_RING; 360 /** Used to identify the volume of audio streams for music playback */ 361 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; 362 /** Used to identify the volume of audio streams for alarms */ 363 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; 364 /** Used to identify the volume of audio streams for notifications */ 365 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; 366 /** @hide Used to identify the volume of audio streams for phone calls when connected 367 * to bluetooth */ 368 @UnsupportedAppUsage 369 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; 370 /** @hide Used to identify the volume of audio streams for enforced system sounds 371 * in certain countries (e.g camera in Japan) */ 372 @UnsupportedAppUsage 373 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED; 374 /** Used to identify the volume of audio streams for DTMF Tones */ 375 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF; 376 /** @hide Used to identify the volume of audio streams exclusively transmitted through the 377 * speaker (TTS) of the device */ 378 @UnsupportedAppUsage 379 public static final int STREAM_TTS = AudioSystem.STREAM_TTS; 380 /** Used to identify the volume of audio streams for accessibility prompts */ 381 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY; 382 /** @hide Used to identify the volume of audio streams for virtual assistant */ 383 @SystemApi 384 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) 385 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT; 386 387 /** Number of audio streams */ 388 /** 389 * @deprecated Do not iterate on volume stream type values. 390 */ 391 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; 392 393 /** 394 * Increase the ringer volume. 395 * 396 * @see #adjustVolume(int, int) 397 * @see #adjustStreamVolume(int, int, int) 398 */ 399 public static final int ADJUST_RAISE = 1; 400 401 /** 402 * Decrease the ringer volume. 403 * 404 * @see #adjustVolume(int, int) 405 * @see #adjustStreamVolume(int, int, int) 406 */ 407 public static final int ADJUST_LOWER = -1; 408 409 /** 410 * Maintain the previous ringer volume. This may be useful when needing to 411 * show the volume toast without actually modifying the volume. 412 * 413 * @see #adjustVolume(int, int) 414 * @see #adjustStreamVolume(int, int, int) 415 */ 416 public static final int ADJUST_SAME = 0; 417 418 /** 419 * Mute the volume. Has no effect if the stream is already muted. 420 * 421 * @see #adjustVolume(int, int) 422 * @see #adjustStreamVolume(int, int, int) 423 */ 424 public static final int ADJUST_MUTE = -100; 425 426 /** 427 * Unmute the volume. Has no effect if the stream is not muted. 428 * 429 * @see #adjustVolume(int, int) 430 * @see #adjustStreamVolume(int, int, int) 431 */ 432 public static final int ADJUST_UNMUTE = 100; 433 434 /** 435 * Toggle the mute state. If muted the stream will be unmuted. If not muted 436 * the stream will be muted. 437 * 438 * @see #adjustVolume(int, int) 439 * @see #adjustStreamVolume(int, int, int) 440 */ 441 public static final int ADJUST_TOGGLE_MUTE = 101; 442 443 /** @hide */ 444 @IntDef(flag = false, prefix = "ADJUST", value = { 445 ADJUST_RAISE, 446 ADJUST_LOWER, 447 ADJUST_SAME, 448 ADJUST_MUTE, 449 ADJUST_UNMUTE, 450 ADJUST_TOGGLE_MUTE } 451 ) 452 @Retention(RetentionPolicy.SOURCE) 453 public @interface VolumeAdjustment {} 454 455 /** @hide */ adjustToString(int adj)456 public static final String adjustToString(int adj) { 457 switch (adj) { 458 case ADJUST_RAISE: return "ADJUST_RAISE"; 459 case ADJUST_LOWER: return "ADJUST_LOWER"; 460 case ADJUST_SAME: return "ADJUST_SAME"; 461 case ADJUST_MUTE: return "ADJUST_MUTE"; 462 case ADJUST_UNMUTE: return "ADJUST_UNMUTE"; 463 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE"; 464 default: return new StringBuilder("unknown adjust mode ").append(adj).toString(); 465 } 466 } 467 468 // Flags should be powers of 2! 469 470 /** 471 * Show a toast containing the current volume. 472 * 473 * @see #adjustStreamVolume(int, int, int) 474 * @see #adjustVolume(int, int) 475 * @see #setStreamVolume(int, int, int) 476 * @see #setRingerMode(int) 477 */ 478 public static final int FLAG_SHOW_UI = 1 << 0; 479 480 /** 481 * Whether to include ringer modes as possible options when changing volume. 482 * For example, if true and volume level is 0 and the volume is adjusted 483 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or 484 * vibrate mode. 485 * <p> 486 * By default this is on for the ring stream. If this flag is included, 487 * this behavior will be present regardless of the stream type being 488 * affected by the ringer mode. 489 * 490 * @see #adjustVolume(int, int) 491 * @see #adjustStreamVolume(int, int, int) 492 */ 493 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; 494 495 /** 496 * Whether to play a sound when changing the volume. 497 * <p> 498 * If this is given to {@link #adjustVolume(int, int)} or 499 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored 500 * in some cases (for example, the decided stream type is not 501 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted 502 * downward). 503 * 504 * @see #adjustStreamVolume(int, int, int) 505 * @see #adjustVolume(int, int) 506 * @see #setStreamVolume(int, int, int) 507 */ 508 public static final int FLAG_PLAY_SOUND = 1 << 2; 509 510 /** 511 * Removes any sounds/vibrate that may be in the queue, or are playing (related to 512 * changing volume). 513 */ 514 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; 515 516 /** 517 * Whether to vibrate if going into the vibrate ringer mode. 518 */ 519 public static final int FLAG_VIBRATE = 1 << 4; 520 521 /** 522 * Indicates to VolumePanel that the volume slider should be disabled as user 523 * cannot change the stream volume 524 * @hide 525 */ 526 public static final int FLAG_FIXED_VOLUME = 1 << 5; 527 528 /** 529 * Indicates the volume set/adjust call is for Bluetooth absolute volume 530 * @hide 531 */ 532 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6; 533 534 /** 535 * Adjusting the volume was prevented due to silent mode, display a hint in the UI. 536 * @hide 537 */ 538 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7; 539 540 /** 541 * Indicates the volume call is for Hdmi Cec system audio volume 542 * @hide 543 */ 544 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8; 545 546 /** 547 * Indicates that this should only be handled if media is actively playing. 548 * @hide 549 */ 550 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; 551 552 /** 553 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders. 554 * @hide 555 */ 556 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; 557 558 /** 559 * Adjusting the volume down from vibrated was prevented, display a hint in the UI. 560 * @hide 561 */ 562 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; 563 564 /** 565 * Adjusting the volume due to a hardware key press. 566 * This flag can be used in the places in order to denote (or check) that a volume adjustment 567 * request is from a hardware key press. (e.g. {@link MediaController}). 568 * @hide 569 */ 570 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 571 public static final int FLAG_FROM_KEY = 1 << 12; 572 573 /** @hide */ 574 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = { 575 ENCODED_SURROUND_OUTPUT_UNKNOWN, 576 ENCODED_SURROUND_OUTPUT_AUTO, 577 ENCODED_SURROUND_OUTPUT_NEVER, 578 ENCODED_SURROUND_OUTPUT_ALWAYS, 579 ENCODED_SURROUND_OUTPUT_MANUAL 580 }) 581 @Retention(RetentionPolicy.SOURCE) 582 public @interface EncodedSurroundOutputMode {} 583 584 /** 585 * The mode for surround sound formats is unknown. 586 */ 587 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1; 588 589 /** 590 * The surround sound formats are available for use if they are detected. This is the default 591 * mode. 592 */ 593 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; 594 595 /** 596 * The surround sound formats are NEVER available, even if they are detected by the hardware. 597 * Those formats will not be reported. 598 */ 599 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1; 600 601 /** 602 * The surround sound formats are ALWAYS available, even if they are not detected by the 603 * hardware. Those formats will be reported as part of the HDMI output capability. 604 * Applications are then free to use either PCM or encoded output. 605 */ 606 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; 607 608 /** 609 * Surround sound formats are available according to the choice of user, even if they are not 610 * detected by the hardware. Those formats will be reported as part of the HDMI output 611 * capability. Applications are then free to use either PCM or encoded output. 612 */ 613 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; 614 615 /** @hide */ 616 @IntDef(flag = true, prefix = "FLAG", value = { 617 FLAG_SHOW_UI, 618 FLAG_ALLOW_RINGER_MODES, 619 FLAG_PLAY_SOUND, 620 FLAG_REMOVE_SOUND_AND_VIBRATE, 621 FLAG_VIBRATE, 622 FLAG_FIXED_VOLUME, 623 FLAG_BLUETOOTH_ABS_VOLUME, 624 FLAG_SHOW_SILENT_HINT, 625 FLAG_HDMI_SYSTEM_AUDIO_VOLUME, 626 FLAG_ACTIVE_MEDIA_ONLY, 627 FLAG_SHOW_UI_WARNINGS, 628 FLAG_SHOW_VIBRATE_HINT, 629 FLAG_FROM_KEY, 630 }) 631 @Retention(RetentionPolicy.SOURCE) 632 public @interface Flags {} 633 634 // The iterator of TreeMap#entrySet() returns the entries in ascending key order. 635 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>(); 636 637 static { FLAG_NAMES.put(FLAG_SHOW_UI, R)638 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI"); FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, R)639 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES"); FLAG_NAMES.put(FLAG_PLAY_SOUND, R)640 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND"); FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, R)641 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE"); FLAG_NAMES.put(FLAG_VIBRATE, R)642 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE"); FLAG_NAMES.put(FLAG_FIXED_VOLUME, R)643 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME"); FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, R)644 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME"); FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, R)645 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT"); FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, R)646 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME"); FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, R)647 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY"); FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, R)648 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS"); FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, R)649 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT"); FLAG_NAMES.put(FLAG_FROM_KEY, R)650 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY"); 651 } 652 653 /** @hide */ flagsToString(int flags)654 public static String flagsToString(int flags) { 655 final StringBuilder sb = new StringBuilder(); 656 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) { 657 final int flag = entry.getKey(); 658 if ((flags & flag) != 0) { 659 if (sb.length() > 0) { 660 sb.append(','); 661 } 662 sb.append(entry.getValue()); 663 flags &= ~flag; 664 } 665 } 666 if (flags != 0) { 667 if (sb.length() > 0) { 668 sb.append(','); 669 } 670 sb.append(flags); 671 } 672 return sb.toString(); 673 } 674 675 /** 676 * Ringer mode that will be silent and will not vibrate. (This overrides the 677 * vibrate setting.) 678 * 679 * @see #setRingerMode(int) 680 * @see #getRingerMode() 681 */ 682 public static final int RINGER_MODE_SILENT = 0; 683 684 /** 685 * Ringer mode that will be silent and will vibrate. (This will cause the 686 * phone ringer to always vibrate, but the notification vibrate to only 687 * vibrate if set.) 688 * 689 * @see #setRingerMode(int) 690 * @see #getRingerMode() 691 */ 692 public static final int RINGER_MODE_VIBRATE = 1; 693 694 /** 695 * Ringer mode that may be audible and may vibrate. It will be audible if 696 * the volume before changing out of this mode was audible. It will vibrate 697 * if the vibrate setting is on. 698 * 699 * @see #setRingerMode(int) 700 * @see #getRingerMode() 701 */ 702 public static final int RINGER_MODE_NORMAL = 2; 703 704 /** 705 * Maximum valid ringer mode value. Values must start from 0 and be contiguous. 706 * @hide 707 */ 708 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; 709 710 /** 711 * Vibrate type that corresponds to the ringer. 712 * 713 * @see #setVibrateSetting(int, int) 714 * @see #getVibrateSetting(int) 715 * @see #shouldVibrate(int) 716 * @deprecated Applications should maintain their own vibrate policy based on 717 * current ringer mode that can be queried via {@link #getRingerMode()}. 718 */ 719 public static final int VIBRATE_TYPE_RINGER = 0; 720 721 /** 722 * Vibrate type that corresponds to notifications. 723 * 724 * @see #setVibrateSetting(int, int) 725 * @see #getVibrateSetting(int) 726 * @see #shouldVibrate(int) 727 * @deprecated Applications should maintain their own vibrate policy based on 728 * current ringer mode that can be queried via {@link #getRingerMode()}. 729 */ 730 public static final int VIBRATE_TYPE_NOTIFICATION = 1; 731 732 /** 733 * Vibrate setting that suggests to never vibrate. 734 * 735 * @see #setVibrateSetting(int, int) 736 * @see #getVibrateSetting(int) 737 * @deprecated Applications should maintain their own vibrate policy based on 738 * current ringer mode that can be queried via {@link #getRingerMode()}. 739 */ 740 public static final int VIBRATE_SETTING_OFF = 0; 741 742 /** 743 * Vibrate setting that suggests to vibrate when possible. 744 * 745 * @see #setVibrateSetting(int, int) 746 * @see #getVibrateSetting(int) 747 * @deprecated Applications should maintain their own vibrate policy based on 748 * current ringer mode that can be queried via {@link #getRingerMode()}. 749 */ 750 public static final int VIBRATE_SETTING_ON = 1; 751 752 /** 753 * Vibrate setting that suggests to only vibrate when in the vibrate ringer 754 * mode. 755 * 756 * @see #setVibrateSetting(int, int) 757 * @see #getVibrateSetting(int) 758 * @deprecated Applications should maintain their own vibrate policy based on 759 * current ringer mode that can be queried via {@link #getRingerMode()}. 760 */ 761 public static final int VIBRATE_SETTING_ONLY_SILENT = 2; 762 763 /** 764 * Suggests using the default stream type. This may not be used in all 765 * places a stream type is needed. 766 */ 767 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; 768 769 private static IAudioService sService; 770 771 /** 772 * @hide 773 * For test purposes only, will throw NPE with some methods that require a Context. 774 */ 775 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) AudioManager()776 public AudioManager() { 777 } 778 779 /** 780 * @hide 781 */ 782 @UnsupportedAppUsage AudioManager(Context context)783 public AudioManager(Context context) { 784 setContext(context); 785 } 786 getContext()787 private Context getContext() { 788 if (mApplicationContext == null) { 789 setContext(mOriginalContext); 790 } 791 if (mApplicationContext != null) { 792 return mApplicationContext; 793 } 794 return mOriginalContext; 795 } 796 setContext(Context context)797 private void setContext(Context context) { 798 mApplicationContext = context.getApplicationContext(); 799 if (mApplicationContext != null) { 800 mOriginalContext = null; 801 } else { 802 mOriginalContext = context; 803 } 804 sContext = new WeakReference<>(context); 805 } 806 807 @UnsupportedAppUsage getService()808 static IAudioService getService() 809 { 810 if (sService != null) { 811 return sService; 812 } 813 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 814 sService = IAudioService.Stub.asInterface(b); 815 return sService; 816 } 817 818 /** 819 * Sends a simulated key event for a media button. 820 * To simulate a key press, you must first send a KeyEvent built with a 821 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP} 822 * action. 823 * <p>The key event will be sent to the current media key event consumer which registered with 824 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}. 825 * @param keyEvent a {@link KeyEvent} instance whose key code is one of 826 * {@link KeyEvent#KEYCODE_MUTE}, 827 * {@link KeyEvent#KEYCODE_HEADSETHOOK}, 828 * {@link KeyEvent#KEYCODE_MEDIA_PLAY}, 829 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE}, 830 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE}, 831 * {@link KeyEvent#KEYCODE_MEDIA_STOP}, 832 * {@link KeyEvent#KEYCODE_MEDIA_NEXT}, 833 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}, 834 * {@link KeyEvent#KEYCODE_MEDIA_REWIND}, 835 * {@link KeyEvent#KEYCODE_MEDIA_RECORD}, 836 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD}, 837 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE}, 838 * {@link KeyEvent#KEYCODE_MEDIA_EJECT}, 839 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}. 840 */ dispatchMediaKeyEvent(KeyEvent keyEvent)841 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 842 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 843 helper.sendMediaButtonEvent(keyEvent, false); 844 } 845 846 /** 847 * @hide 848 */ preDispatchKeyEvent(KeyEvent event, int stream)849 public void preDispatchKeyEvent(KeyEvent event, int stream) { 850 /* 851 * If the user hits another key within the play sound delay, then 852 * cancel the sound 853 */ 854 int keyCode = event.getKeyCode(); 855 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP 856 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE 857 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) { 858 /* 859 * The user has hit another key during the delay (e.g., 300ms) 860 * since the last volume key up, so cancel any sounds. 861 */ 862 adjustSuggestedStreamVolume(ADJUST_SAME, 863 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); 864 } 865 } 866 867 /** 868 * Indicates if the device implements a fixed volume policy. 869 * <p>Some devices may not have volume control and may operate at a fixed volume, 870 * and may not enable muting or changing the volume of audio streams. 871 * This method will return true on such devices. 872 * <p>The following APIs have no effect when volume is fixed: 873 * <ul> 874 * <li> {@link #adjustVolume(int, int)} 875 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)} 876 * <li> {@link #adjustStreamVolume(int, int, int)} 877 * <li> {@link #setStreamVolume(int, int, int)} 878 * <li> {@link #setRingerMode(int)} 879 * <li> {@link #setStreamSolo(int, boolean)} 880 * <li> {@link #setStreamMute(int, boolean)} 881 * </ul> 882 */ isVolumeFixed()883 public boolean isVolumeFixed() { 884 synchronized (this) { 885 try { 886 if (!mUseFixedVolumeInitialized) { 887 mUseFixedVolume = getContext().getResources().getBoolean( 888 com.android.internal.R.bool.config_useFixedVolume); 889 } 890 } catch (Exception e) { 891 } finally { 892 // only ever try once, so always consider initialized even if query failed 893 mUseFixedVolumeInitialized = true; 894 } 895 } 896 return mUseFixedVolume; 897 } 898 899 /** 900 * Adjusts the volume of a particular stream by one step in a direction. 901 * <p> 902 * This method should only be used by applications that replace the platform-wide 903 * management of audio settings or the main telephony application. 904 * <p>This method has no effect if the device implements a fixed volume policy 905 * as indicated by {@link #isVolumeFixed()}. 906 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 907 * unless the app has been granted Do Not Disturb Access. 908 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 909 * 910 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 911 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 912 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 913 * @param direction The direction to adjust the volume. One of 914 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 915 * {@link #ADJUST_SAME}. 916 * @param flags One or more flags. 917 * @see #adjustVolume(int, int) 918 * @see #setStreamVolume(int, int, int) 919 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 920 * and the caller is not granted notification policy access. 921 */ adjustStreamVolume(int streamType, int direction, int flags)922 public void adjustStreamVolume(int streamType, int direction, int flags) { 923 final IAudioService service = getService(); 924 try { 925 service.adjustStreamVolume(streamType, direction, flags, 926 getContext().getOpPackageName()); 927 } catch (RemoteException e) { 928 throw e.rethrowFromSystemServer(); 929 } 930 } 931 932 /** 933 * Adjusts the volume of the most relevant stream. For example, if a call is 934 * active, it will have the highest priority regardless of if the in-call 935 * screen is showing. Another example, if music is playing in the background 936 * and a call is not active, the music stream will be adjusted. 937 * <p> 938 * This method should only be used by applications that replace the 939 * platform-wide management of audio settings or the main telephony 940 * application. 941 * <p> 942 * This method has no effect if the device implements a fixed volume policy 943 * as indicated by {@link #isVolumeFixed()}. 944 * 945 * @param direction The direction to adjust the volume. One of 946 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 947 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 948 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 949 * @param flags One or more flags. 950 * @see #adjustSuggestedStreamVolume(int, int, int) 951 * @see #adjustStreamVolume(int, int, int) 952 * @see #setStreamVolume(int, int, int) 953 * @see #isVolumeFixed() 954 */ adjustVolume(int direction, int flags)955 public void adjustVolume(int direction, int flags) { 956 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 957 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); 958 } 959 960 /** 961 * Adjusts the volume of the most relevant stream, or the given fallback 962 * stream. 963 * <p> 964 * This method should only be used by applications that replace the 965 * platform-wide management of audio settings or the main telephony 966 * application. 967 * <p> 968 * This method has no effect if the device implements a fixed volume policy 969 * as indicated by {@link #isVolumeFixed()}. 970 * 971 * @param direction The direction to adjust the volume. One of 972 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 973 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 974 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 975 * @param suggestedStreamType The stream type that will be used if there 976 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 977 * valid here. 978 * @param flags One or more flags. 979 * @see #adjustVolume(int, int) 980 * @see #adjustStreamVolume(int, int, int) 981 * @see #setStreamVolume(int, int, int) 982 * @see #isVolumeFixed() 983 */ adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags)984 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 985 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 986 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); 987 } 988 989 /** @hide */ 990 @UnsupportedAppUsage 991 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setMasterMute(boolean mute, int flags)992 public void setMasterMute(boolean mute, int flags) { 993 final IAudioService service = getService(); 994 try { 995 service.setMasterMute(mute, flags, getContext().getOpPackageName(), 996 UserHandle.getCallingUserId()); 997 } catch (RemoteException e) { 998 throw e.rethrowFromSystemServer(); 999 } 1000 } 1001 1002 /** 1003 * Returns the current ringtone mode. 1004 * 1005 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, 1006 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1007 * @see #setRingerMode(int) 1008 */ getRingerMode()1009 public int getRingerMode() { 1010 final IAudioService service = getService(); 1011 try { 1012 return service.getRingerModeExternal(); 1013 } catch (RemoteException e) { 1014 throw e.rethrowFromSystemServer(); 1015 } 1016 } 1017 1018 /** 1019 * Checks valid ringer mode values. 1020 * 1021 * @return true if the ringer mode indicated is valid, false otherwise. 1022 * 1023 * @see #setRingerMode(int) 1024 * @hide 1025 */ 1026 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isValidRingerMode(int ringerMode)1027 public static boolean isValidRingerMode(int ringerMode) { 1028 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { 1029 return false; 1030 } 1031 final IAudioService service = getService(); 1032 try { 1033 return service.isValidRingerMode(ringerMode); 1034 } catch (RemoteException e) { 1035 throw e.rethrowFromSystemServer(); 1036 } 1037 } 1038 1039 /** 1040 * Returns the maximum volume index for a particular stream. 1041 * 1042 * @param streamType The stream type whose maximum volume index is returned. 1043 * @return The maximum valid volume index for the stream. 1044 * @see #getStreamVolume(int) 1045 */ getStreamMaxVolume(int streamType)1046 public int getStreamMaxVolume(int streamType) { 1047 final IAudioService service = getService(); 1048 try { 1049 return service.getStreamMaxVolume(streamType); 1050 } catch (RemoteException e) { 1051 throw e.rethrowFromSystemServer(); 1052 } 1053 } 1054 1055 /** 1056 * Returns the minimum volume index for a particular stream. 1057 * @param streamType The stream type whose minimum volume index is returned. Must be one of 1058 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, 1059 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, 1060 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}. 1061 * @return The minimum valid volume index for the stream. 1062 * @see #getStreamVolume(int) 1063 */ getStreamMinVolume(int streamType)1064 public int getStreamMinVolume(int streamType) { 1065 if (!isPublicStreamType(streamType)) { 1066 throw new IllegalArgumentException("Invalid stream type " + streamType); 1067 } 1068 return getStreamMinVolumeInt(streamType); 1069 } 1070 1071 /** 1072 * @hide 1073 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type. 1074 * @param streamType The stream type whose minimum volume index is returned. 1075 * @return The minimum valid volume index for the stream. 1076 * @see #getStreamVolume(int) 1077 */ getStreamMinVolumeInt(int streamType)1078 public int getStreamMinVolumeInt(int streamType) { 1079 final IAudioService service = getService(); 1080 try { 1081 return service.getStreamMinVolume(streamType); 1082 } catch (RemoteException e) { 1083 throw e.rethrowFromSystemServer(); 1084 } 1085 } 1086 1087 /** 1088 * Returns the current volume index for a particular stream. 1089 * 1090 * @param streamType The stream type whose volume index is returned. 1091 * @return The current volume index for the stream. 1092 * @see #getStreamMaxVolume(int) 1093 * @see #setStreamVolume(int, int, int) 1094 */ getStreamVolume(int streamType)1095 public int getStreamVolume(int streamType) { 1096 final IAudioService service = getService(); 1097 try { 1098 return service.getStreamVolume(streamType); 1099 } catch (RemoteException e) { 1100 throw e.rethrowFromSystemServer(); 1101 } 1102 } 1103 1104 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h 1105 private static final float VOLUME_MIN_DB = -758.0f; 1106 1107 /** @hide */ 1108 @IntDef(flag = false, prefix = "STREAM", value = { 1109 STREAM_VOICE_CALL, 1110 STREAM_SYSTEM, 1111 STREAM_RING, 1112 STREAM_MUSIC, 1113 STREAM_ALARM, 1114 STREAM_NOTIFICATION, 1115 STREAM_DTMF, 1116 STREAM_ACCESSIBILITY } 1117 ) 1118 @Retention(RetentionPolicy.SOURCE) 1119 public @interface PublicStreamTypes {} 1120 1121 /** 1122 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on 1123 * the given type of audio output device. 1124 * @param streamType stream type for which the volume is queried. 1125 * @param index the volume index for which the volume is queried. The index value must be 1126 * between the minimum and maximum index values for the given stream type (see 1127 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}). 1128 * @param deviceType the type of audio output device for which volume is queried. 1129 * @return a volume expressed in dB. 1130 * A negative value indicates the audio signal is attenuated. A typical maximum value 1131 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is 1132 * reflected by a value of {@link Float#NEGATIVE_INFINITY}. 1133 */ getStreamVolumeDb(@ublicStreamTypes int streamType, int index, @AudioDeviceInfo.AudioDeviceTypeOut int deviceType)1134 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index, 1135 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 1136 if (!isPublicStreamType(streamType)) { 1137 throw new IllegalArgumentException("Invalid stream type " + streamType); 1138 } 1139 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) { 1140 throw new IllegalArgumentException("Invalid stream volume index " + index); 1141 } 1142 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) { 1143 throw new IllegalArgumentException("Invalid audio output device type " + deviceType); 1144 } 1145 final float gain = AudioSystem.getStreamVolumeDB(streamType, index, 1146 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType)); 1147 if (gain <= VOLUME_MIN_DB) { 1148 return Float.NEGATIVE_INFINITY; 1149 } else { 1150 return gain; 1151 } 1152 } 1153 isPublicStreamType(int streamType)1154 private static boolean isPublicStreamType(int streamType) { 1155 switch (streamType) { 1156 case STREAM_VOICE_CALL: 1157 case STREAM_SYSTEM: 1158 case STREAM_RING: 1159 case STREAM_MUSIC: 1160 case STREAM_ALARM: 1161 case STREAM_NOTIFICATION: 1162 case STREAM_DTMF: 1163 case STREAM_ACCESSIBILITY: 1164 return true; 1165 default: 1166 return false; 1167 } 1168 } 1169 1170 /** 1171 * Get last audible volume before stream was muted. 1172 * 1173 * @hide 1174 */ 1175 @UnsupportedAppUsage getLastAudibleStreamVolume(int streamType)1176 public int getLastAudibleStreamVolume(int streamType) { 1177 final IAudioService service = getService(); 1178 try { 1179 return service.getLastAudibleStreamVolume(streamType); 1180 } catch (RemoteException e) { 1181 throw e.rethrowFromSystemServer(); 1182 } 1183 } 1184 1185 /** 1186 * Get the stream type whose volume is driving the UI sounds volume. 1187 * UI sounds are screen lock/unlock, camera shutter, key clicks... 1188 * It is assumed that this stream type is also tied to ringer mode changes. 1189 * @hide 1190 */ getUiSoundsStreamType()1191 public int getUiSoundsStreamType() { 1192 final IAudioService service = getService(); 1193 try { 1194 return service.getUiSoundsStreamType(); 1195 } catch (RemoteException e) { 1196 throw e.rethrowFromSystemServer(); 1197 } 1198 } 1199 1200 /** 1201 * Sets the ringer mode. 1202 * <p> 1203 * Silent mode will mute the volume and will not vibrate. Vibrate mode will 1204 * mute the volume and vibrate. Normal mode will be audible and may vibrate 1205 * according to user settings. 1206 * <p>This method has no effect if the device implements a fixed volume policy 1207 * as indicated by {@link #isVolumeFixed()}. 1208 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1209 * unless the app has been granted Do Not Disturb Access. 1210 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1211 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, 1212 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1213 * @see #getRingerMode() 1214 * @see #isVolumeFixed() 1215 */ setRingerMode(int ringerMode)1216 public void setRingerMode(int ringerMode) { 1217 if (!isValidRingerMode(ringerMode)) { 1218 return; 1219 } 1220 final IAudioService service = getService(); 1221 try { 1222 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName()); 1223 } catch (RemoteException e) { 1224 throw e.rethrowFromSystemServer(); 1225 } 1226 } 1227 1228 /** 1229 * Sets the volume index for a particular stream. 1230 * <p>This method has no effect if the device implements a fixed volume policy 1231 * as indicated by {@link #isVolumeFixed()}. 1232 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 1233 * the app has been granted Do Not Disturb Access. 1234 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1235 * @param streamType The stream whose volume index should be set. 1236 * @param index The volume index to set. See 1237 * {@link #getStreamMaxVolume(int)} for the largest valid value. 1238 * @param flags One or more flags. 1239 * @see #getStreamMaxVolume(int) 1240 * @see #getStreamVolume(int) 1241 * @see #isVolumeFixed() 1242 * @throws SecurityException if the volume change triggers a Do Not Disturb change 1243 * and the caller is not granted notification policy access. 1244 */ setStreamVolume(int streamType, int index, int flags)1245 public void setStreamVolume(int streamType, int index, int flags) { 1246 final IAudioService service = getService(); 1247 try { 1248 service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); 1249 } catch (RemoteException e) { 1250 throw e.rethrowFromSystemServer(); 1251 } 1252 } 1253 1254 /** 1255 * Sets the volume index for a particular {@link AudioAttributes}. 1256 * @param attr The {@link AudioAttributes} whose volume index should be set. 1257 * @param index The volume index to set. See 1258 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value 1259 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value. 1260 * @param flags One or more flags. 1261 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1262 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1263 * @see #isVolumeFixed() 1264 * @hide 1265 */ 1266 @SystemApi 1267 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setVolumeIndexForAttributes(@onNull AudioAttributes attr, int index, int flags)1268 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) { 1269 Preconditions.checkNotNull(attr, "attr must not be null"); 1270 final IAudioService service = getService(); 1271 try { 1272 service.setVolumeIndexForAttributes(attr, index, flags, 1273 getContext().getOpPackageName()); 1274 } catch (RemoteException e) { 1275 throw e.rethrowFromSystemServer(); 1276 } 1277 } 1278 1279 /** 1280 * Returns the current volume index for a particular {@link AudioAttributes}. 1281 * 1282 * @param attr The {@link AudioAttributes} whose volume index is returned. 1283 * @return The current volume index for the stream. 1284 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1285 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1286 * @see #setVolumeForAttributes(AudioAttributes, int, int) 1287 * @hide 1288 */ 1289 @SystemApi 1290 @IntRange(from = 0) 1291 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getVolumeIndexForAttributes(@onNull AudioAttributes attr)1292 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1293 Preconditions.checkNotNull(attr, "attr must not be null"); 1294 final IAudioService service = getService(); 1295 try { 1296 return service.getVolumeIndexForAttributes(attr); 1297 } catch (RemoteException e) { 1298 throw e.rethrowFromSystemServer(); 1299 } 1300 } 1301 1302 /** 1303 * Returns the maximum volume index for a particular {@link AudioAttributes}. 1304 * 1305 * @param attr The {@link AudioAttributes} whose maximum volume index is returned. 1306 * @return The maximum valid volume index for the {@link AudioAttributes}. 1307 * @see #getVolumeIndexForAttributes(AudioAttributes) 1308 * @hide 1309 */ 1310 @SystemApi 1311 @IntRange(from = 0) 1312 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getMaxVolumeIndexForAttributes(@onNull AudioAttributes attr)1313 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1314 Preconditions.checkNotNull(attr, "attr must not be null"); 1315 final IAudioService service = getService(); 1316 try { 1317 return service.getMaxVolumeIndexForAttributes(attr); 1318 } catch (RemoteException e) { 1319 throw e.rethrowFromSystemServer(); 1320 } 1321 } 1322 1323 /** 1324 * Returns the minimum volume index for a particular {@link AudioAttributes}. 1325 * 1326 * @param attr The {@link AudioAttributes} whose minimum volume index is returned. 1327 * @return The minimum valid volume index for the {@link AudioAttributes}. 1328 * @see #getVolumeIndexForAttributes(AudioAttributes) 1329 * @hide 1330 */ 1331 @SystemApi 1332 @IntRange(from = 0) 1333 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getMinVolumeIndexForAttributes(@onNull AudioAttributes attr)1334 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1335 Preconditions.checkNotNull(attr, "attr must not be null"); 1336 final IAudioService service = getService(); 1337 try { 1338 return service.getMinVolumeIndexForAttributes(attr); 1339 } catch (RemoteException e) { 1340 throw e.rethrowFromSystemServer(); 1341 } 1342 } 1343 1344 /** 1345 * Set the system usages to be supported on this device. 1346 * @param systemUsages array of system usages to support {@link AttributeSystemUsage} 1347 * @hide 1348 */ 1349 @SystemApi 1350 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setSupportedSystemUsages(@onNull @ttributeSystemUsage int[] systemUsages)1351 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) { 1352 Objects.requireNonNull(systemUsages, "systemUsages must not be null"); 1353 final IAudioService service = getService(); 1354 try { 1355 service.setSupportedSystemUsages(systemUsages); 1356 } catch (RemoteException e) { 1357 throw e.rethrowFromSystemServer(); 1358 } 1359 } 1360 1361 /** 1362 * Get the system usages supported on this device. 1363 * @return array of supported system usages {@link AttributeSystemUsage} 1364 * @hide 1365 */ 1366 @SystemApi 1367 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getSupportedSystemUsages()1368 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() { 1369 final IAudioService service = getService(); 1370 try { 1371 return service.getSupportedSystemUsages(); 1372 } catch (RemoteException e) { 1373 throw e.rethrowFromSystemServer(); 1374 } 1375 } 1376 1377 /** 1378 * Solo or unsolo a particular stream. 1379 * <p> 1380 * Do not use. This method has been deprecated and is now a no-op. 1381 * {@link #requestAudioFocus} should be used for exclusive audio playback. 1382 * 1383 * @param streamType The stream to be soloed/unsoloed. 1384 * @param state The required solo state: true for solo ON, false for solo 1385 * OFF 1386 * @see #isVolumeFixed() 1387 * @deprecated Do not use. If you need exclusive audio playback use 1388 * {@link #requestAudioFocus}. 1389 */ 1390 @Deprecated setStreamSolo(int streamType, boolean state)1391 public void setStreamSolo(int streamType, boolean state) { 1392 Log.w(TAG, "setStreamSolo has been deprecated. Do not use."); 1393 } 1394 1395 /** 1396 * Mute or unmute an audio stream. 1397 * <p> 1398 * This method should only be used by applications that replace the 1399 * platform-wide management of audio settings or the main telephony 1400 * application. 1401 * <p> 1402 * This method has no effect if the device implements a fixed volume policy 1403 * as indicated by {@link #isVolumeFixed()}. 1404 * <p> 1405 * This method was deprecated in API level 22. Prior to API level 22 this 1406 * method had significantly different behavior and should be used carefully. 1407 * The following applies only to pre-22 platforms: 1408 * <ul> 1409 * <li>The mute command is protected against client process death: if a 1410 * process with an active mute request on a stream dies, this stream will be 1411 * unmuted automatically.</li> 1412 * <li>The mute requests for a given stream are cumulative: the AudioManager 1413 * can receive several mute requests from one or more clients and the stream 1414 * will be unmuted only when the same number of unmute requests are 1415 * received.</li> 1416 * <li>For a better user experience, applications MUST unmute a muted stream 1417 * in onPause() and mute is again in onResume() if appropriate.</li> 1418 * </ul> 1419 * 1420 * @param streamType The stream to be muted/unmuted. 1421 * @param state The required mute state: true for mute ON, false for mute 1422 * OFF 1423 * @see #isVolumeFixed() 1424 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with 1425 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead. 1426 */ 1427 @Deprecated setStreamMute(int streamType, boolean state)1428 public void setStreamMute(int streamType, boolean state) { 1429 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead."); 1430 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE; 1431 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1432 adjustSuggestedStreamVolume(direction, streamType, 0); 1433 } else { 1434 adjustStreamVolume(streamType, direction, 0); 1435 } 1436 } 1437 1438 /** 1439 * Returns the current mute state for a particular stream. 1440 * 1441 * @param streamType The stream to get mute state for. 1442 * @return The mute state for the given stream. 1443 * @see #adjustStreamVolume(int, int, int) 1444 */ isStreamMute(int streamType)1445 public boolean isStreamMute(int streamType) { 1446 final IAudioService service = getService(); 1447 try { 1448 return service.isStreamMute(streamType); 1449 } catch (RemoteException e) { 1450 throw e.rethrowFromSystemServer(); 1451 } 1452 } 1453 1454 /** 1455 * get master mute state. 1456 * 1457 * @hide 1458 */ 1459 @UnsupportedAppUsage isMasterMute()1460 public boolean isMasterMute() { 1461 final IAudioService service = getService(); 1462 try { 1463 return service.isMasterMute(); 1464 } catch (RemoteException e) { 1465 throw e.rethrowFromSystemServer(); 1466 } 1467 } 1468 1469 /** 1470 * forces the stream controlled by hard volume keys 1471 * specifying streamType == -1 releases control to the 1472 * logic. 1473 * 1474 * @hide 1475 */ 1476 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) 1477 @UnsupportedAppUsage forceVolumeControlStream(int streamType)1478 public void forceVolumeControlStream(int streamType) { 1479 final IAudioService service = getService(); 1480 try { 1481 service.forceVolumeControlStream(streamType, mICallBack); 1482 } catch (RemoteException e) { 1483 throw e.rethrowFromSystemServer(); 1484 } 1485 } 1486 1487 /** 1488 * Returns whether a particular type should vibrate according to user 1489 * settings and the current ringer mode. 1490 * <p> 1491 * This shouldn't be needed by most clients that use notifications to 1492 * vibrate. The notification manager will not vibrate if the policy doesn't 1493 * allow it, so the client should always set a vibrate pattern and let the 1494 * notification manager control whether or not to actually vibrate. 1495 * 1496 * @param vibrateType The type of vibrate. One of 1497 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1498 * {@link #VIBRATE_TYPE_RINGER}. 1499 * @return Whether the type should vibrate at the instant this method is 1500 * called. 1501 * @see #setVibrateSetting(int, int) 1502 * @see #getVibrateSetting(int) 1503 * @deprecated Applications should maintain their own vibrate policy based on 1504 * current ringer mode that can be queried via {@link #getRingerMode()}. 1505 */ shouldVibrate(int vibrateType)1506 public boolean shouldVibrate(int vibrateType) { 1507 final IAudioService service = getService(); 1508 try { 1509 return service.shouldVibrate(vibrateType); 1510 } catch (RemoteException e) { 1511 throw e.rethrowFromSystemServer(); 1512 } 1513 } 1514 1515 /** 1516 * Returns whether the user's vibrate setting for a vibrate type. 1517 * <p> 1518 * This shouldn't be needed by most clients that want to vibrate, instead 1519 * see {@link #shouldVibrate(int)}. 1520 * 1521 * @param vibrateType The type of vibrate. One of 1522 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1523 * {@link #VIBRATE_TYPE_RINGER}. 1524 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, 1525 * {@link #VIBRATE_SETTING_OFF}, or 1526 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1527 * @see #setVibrateSetting(int, int) 1528 * @see #shouldVibrate(int) 1529 * @deprecated Applications should maintain their own vibrate policy based on 1530 * current ringer mode that can be queried via {@link #getRingerMode()}. 1531 */ getVibrateSetting(int vibrateType)1532 public int getVibrateSetting(int vibrateType) { 1533 final IAudioService service = getService(); 1534 try { 1535 return service.getVibrateSetting(vibrateType); 1536 } catch (RemoteException e) { 1537 throw e.rethrowFromSystemServer(); 1538 } 1539 } 1540 1541 /** 1542 * Sets the setting for when the vibrate type should vibrate. 1543 * <p> 1544 * This method should only be used by applications that replace the platform-wide 1545 * management of audio settings or the main telephony application. 1546 * 1547 * @param vibrateType The type of vibrate. One of 1548 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1549 * {@link #VIBRATE_TYPE_RINGER}. 1550 * @param vibrateSetting The vibrate setting, one of 1551 * {@link #VIBRATE_SETTING_ON}, 1552 * {@link #VIBRATE_SETTING_OFF}, or 1553 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 1554 * @see #getVibrateSetting(int) 1555 * @see #shouldVibrate(int) 1556 * @deprecated Applications should maintain their own vibrate policy based on 1557 * current ringer mode that can be queried via {@link #getRingerMode()}. 1558 */ setVibrateSetting(int vibrateType, int vibrateSetting)1559 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1560 final IAudioService service = getService(); 1561 try { 1562 service.setVibrateSetting(vibrateType, vibrateSetting); 1563 } catch (RemoteException e) { 1564 throw e.rethrowFromSystemServer(); 1565 } 1566 } 1567 1568 /** 1569 * Sets the speakerphone on or off. 1570 * <p> 1571 * This method should only be used by applications that replace the platform-wide 1572 * management of audio settings or the main telephony application. 1573 * 1574 * @param on set <var>true</var> to turn on speakerphone; 1575 * <var>false</var> to turn it off 1576 */ setSpeakerphoneOn(boolean on)1577 public void setSpeakerphoneOn(boolean on){ 1578 final IAudioService service = getService(); 1579 try { 1580 service.setSpeakerphoneOn(mICallBack, on); 1581 } catch (RemoteException e) { 1582 throw e.rethrowFromSystemServer(); 1583 } 1584 } 1585 1586 /** 1587 * Checks whether the speakerphone is on or off. 1588 * 1589 * @return true if speakerphone is on, false if it's off 1590 */ isSpeakerphoneOn()1591 public boolean isSpeakerphoneOn() { 1592 final IAudioService service = getService(); 1593 try { 1594 return service.isSpeakerphoneOn(); 1595 } catch (RemoteException e) { 1596 throw e.rethrowFromSystemServer(); 1597 } 1598 } 1599 1600 /** 1601 * Specifies whether the audio played by this app may or may not be captured by other apps or 1602 * the system. 1603 * 1604 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. 1605 * 1606 * There are multiple ways to set this policy: 1607 * <ul> 1608 * <li> for each track independently, see 1609 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li> 1610 * <li> application-wide at runtime, with this method </li> 1611 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application 1612 * manifest. </li> 1613 * </ul> 1614 * The most restrictive policy is always applied. 1615 * 1616 * See {@link AudioPlaybackCaptureConfiguration} for more details on 1617 * which audio signals can be captured. 1618 * 1619 * @param capturePolicy one of 1620 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, 1621 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, 1622 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. 1623 * @throws RuntimeException if the argument is not a valid value. 1624 */ setAllowedCapturePolicy(@udioAttributes.CapturePolicy int capturePolicy)1625 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) { 1626 // TODO: also pass the package in case multiple packages have the same UID 1627 final IAudioService service = getService(); 1628 try { 1629 int result = service.setAllowedCapturePolicy(capturePolicy); 1630 if (result != AudioSystem.AUDIO_STATUS_OK) { 1631 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); 1632 return; 1633 } 1634 } catch (RemoteException e) { 1635 throw e.rethrowFromSystemServer(); 1636 } 1637 } 1638 1639 /** 1640 * Return the capture policy. 1641 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or 1642 * the default if it was not called. 1643 */ 1644 @AudioAttributes.CapturePolicy getAllowedCapturePolicy()1645 public int getAllowedCapturePolicy() { 1646 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL; 1647 try { 1648 result = getService().getAllowedCapturePolicy(); 1649 } catch (RemoteException e) { 1650 Log.e(TAG, "Failed to query allowed capture policy: " + e); 1651 } 1652 return result; 1653 } 1654 1655 //==================================================================== 1656 // Audio Product Strategy routing 1657 1658 /** 1659 * @hide 1660 * Set the preferred device for a given strategy, i.e. the audio routing to be used by 1661 * this audio strategy. Note that the device may not be available at the time the preferred 1662 * device is set, but it will be used once made available. 1663 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 1664 * this preference for this strategy.</p> 1665 * @param strategy the audio strategy whose routing will be affected 1666 * @param device the audio device to route to when available 1667 * @return true if the operation was successful, false otherwise 1668 */ 1669 @SystemApi 1670 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)1671 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, 1672 @NonNull AudioDeviceAttributes device) { 1673 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device)); 1674 } 1675 1676 /** 1677 * @hide 1678 * Removes the preferred audio device(s) previously set with 1679 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 1680 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}. 1681 * @param strategy the audio strategy whose routing will be affected 1682 * @return true if the operation was successful, false otherwise (invalid strategy, or no 1683 * device set for example) 1684 */ 1685 @SystemApi 1686 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) removePreferredDeviceForStrategy(@onNull AudioProductStrategy strategy)1687 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { 1688 Objects.requireNonNull(strategy); 1689 try { 1690 final int status = 1691 getService().removePreferredDevicesForStrategy(strategy.getId()); 1692 return status == AudioSystem.SUCCESS; 1693 } catch (RemoteException e) { 1694 throw e.rethrowFromSystemServer(); 1695 } 1696 } 1697 1698 /** 1699 * @hide 1700 * Return the preferred device for an audio strategy, previously set with 1701 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 1702 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 1703 * @param strategy the strategy to query 1704 * @return the preferred device for that strategy, if multiple devices are set as preferred 1705 * devices, the first one in the list will be returned. Null will be returned if none was 1706 * ever set or if the strategy is invalid 1707 */ 1708 @SystemApi 1709 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) 1710 @Nullable getPreferredDeviceForStrategy( @onNull AudioProductStrategy strategy)1711 public AudioDeviceAttributes getPreferredDeviceForStrategy( 1712 @NonNull AudioProductStrategy strategy) { 1713 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy); 1714 return devices.isEmpty() ? null : devices.get(0); 1715 } 1716 1717 /** 1718 * @hide 1719 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by 1720 * this audio strategy. Note that the devices may not be available at the time the preferred 1721 * devices is set, but it will be used once made available. 1722 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 1723 * this preference for this strategy.</p> 1724 * Note that the list of devices is not a list ranked by preference, but a list of one or more 1725 * devices used simultaneously to output the same audio signal. 1726 * @param strategy the audio strategy whose routing will be affected 1727 * @param devices a non-empty list of the audio devices to route to when available 1728 * @return true if the operation was successful, false otherwise 1729 */ 1730 @SystemApi 1731 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDevicesForStrategy(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)1732 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy, 1733 @NonNull List<AudioDeviceAttributes> devices) { 1734 Objects.requireNonNull(strategy); 1735 Objects.requireNonNull(devices); 1736 if (devices.isEmpty()) { 1737 throw new IllegalArgumentException( 1738 "Tried to set preferred devices for strategy with a empty list"); 1739 } 1740 for (AudioDeviceAttributes device : devices) { 1741 Objects.requireNonNull(device); 1742 } 1743 try { 1744 final int status = 1745 getService().setPreferredDevicesForStrategy(strategy.getId(), devices); 1746 return status == AudioSystem.SUCCESS; 1747 } catch (RemoteException e) { 1748 throw e.rethrowFromSystemServer(); 1749 } 1750 } 1751 1752 /** 1753 * @hide 1754 * Return the preferred devices for an audio strategy, previously set with 1755 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 1756 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 1757 * @param strategy the strategy to query 1758 * @return the preferred device for that strategy, or null if none was ever set or if the 1759 * strategy is invalid 1760 */ 1761 @SystemApi 1762 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) 1763 @NonNull getPreferredDevicesForStrategy( @onNull AudioProductStrategy strategy)1764 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy( 1765 @NonNull AudioProductStrategy strategy) { 1766 Objects.requireNonNull(strategy); 1767 try { 1768 return getService().getPreferredDevicesForStrategy(strategy.getId()); 1769 } catch (RemoteException e) { 1770 throw e.rethrowFromSystemServer(); 1771 } 1772 } 1773 1774 /** 1775 * @hide 1776 * Interface to be notified of changes in the preferred audio device set for a given audio 1777 * strategy. 1778 * <p>Note that this listener will only be invoked whenever 1779 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 1780 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 1781 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 1782 * preferred device. It will not be invoked directly after registration with 1783 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)} 1784 * to indicate which strategies had preferred devices at the time of registration.</p> 1785 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 1786 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 1787 * @see #getPreferredDeviceForStrategy(AudioProductStrategy) 1788 * @deprecated use #OnPreferredDevicesForStrategyChangedListener 1789 */ 1790 @SystemApi 1791 @Deprecated 1792 public interface OnPreferredDeviceForStrategyChangedListener { 1793 /** 1794 * Called on the listener to indicate that the preferred audio device for the given 1795 * strategy has changed. 1796 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 1797 * @param device <code>null</code> if the preferred device was removed, or the newly set 1798 * preferred audio device 1799 */ onPreferredDeviceForStrategyChanged(@onNull AudioProductStrategy strategy, @Nullable AudioDeviceAttributes device)1800 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy, 1801 @Nullable AudioDeviceAttributes device); 1802 } 1803 1804 /** 1805 * @hide 1806 * Interface to be notified of changes in the preferred audio devices set for a given audio 1807 * strategy. 1808 * <p>Note that this listener will only be invoked whenever 1809 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 1810 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 1811 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 1812 * preferred device(s). It will not be invoked directly after registration with 1813 * {@link #addOnPreferredDevicesForStrategyChangedListener( 1814 * Executor, OnPreferredDevicesForStrategyChangedListener)} 1815 * to indicate which strategies had preferred devices at the time of registration.</p> 1816 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 1817 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List) 1818 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 1819 * @see #getPreferredDeviceForStrategy(AudioProductStrategy) 1820 * @see #getPreferredDevicesForStrategy(AudioProductStrategy) 1821 */ 1822 @SystemApi 1823 public interface OnPreferredDevicesForStrategyChangedListener { 1824 /** 1825 * Called on the listener to indicate that the preferred audio devices for the given 1826 * strategy has changed. 1827 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 1828 * @param devices a list of newly set preferred audio devices 1829 */ onPreferredDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)1830 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, 1831 @NonNull List<AudioDeviceAttributes> devices); 1832 } 1833 1834 /** 1835 * @hide 1836 * Adds a listener for being notified of changes to the strategy-preferred audio device. 1837 * @param executor 1838 * @param listener 1839 * @throws SecurityException if the caller doesn't hold the required permission 1840 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener( 1841 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 1842 */ 1843 @SystemApi 1844 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) 1845 @Deprecated addOnPreferredDeviceForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener)1846 public void addOnPreferredDeviceForStrategyChangedListener( 1847 @NonNull @CallbackExecutor Executor executor, 1848 @NonNull OnPreferredDeviceForStrategyChangedListener listener) 1849 throws SecurityException { 1850 // No-op, the method is deprecated. 1851 } 1852 1853 /** 1854 * @hide 1855 * Removes a previously added listener of changes to the strategy-preferred audio device. 1856 * @param listener 1857 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener( 1858 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 1859 */ 1860 @SystemApi 1861 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) 1862 @Deprecated removeOnPreferredDeviceForStrategyChangedListener( @onNull OnPreferredDeviceForStrategyChangedListener listener)1863 public void removeOnPreferredDeviceForStrategyChangedListener( 1864 @NonNull OnPreferredDeviceForStrategyChangedListener listener) { 1865 // No-op, the method is deprecated. 1866 } 1867 1868 /** 1869 * @hide 1870 * Adds a listener for being notified of changes to the strategy-preferred audio device. 1871 * @param executor 1872 * @param listener 1873 * @throws SecurityException if the caller doesn't hold the required permission 1874 */ 1875 @SystemApi 1876 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForStrategyChangedListener listener)1877 public void addOnPreferredDevicesForStrategyChangedListener( 1878 @NonNull @CallbackExecutor Executor executor, 1879 @NonNull OnPreferredDevicesForStrategyChangedListener listener) 1880 throws SecurityException { 1881 Objects.requireNonNull(executor); 1882 Objects.requireNonNull(listener); 1883 synchronized (mPrefDevListenerLock) { 1884 if (hasPrefDevListener(listener)) { 1885 throw new IllegalArgumentException( 1886 "attempt to call addOnPreferredDevicesForStrategyChangedListener() " 1887 + "on a previously registered listener"); 1888 } 1889 // lazy initialization of the list of strategy-preferred device listener 1890 if (mPrefDevListeners == null) { 1891 mPrefDevListeners = new ArrayList<>(); 1892 } 1893 final int oldCbCount = mPrefDevListeners.size(); 1894 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor)); 1895 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) { 1896 // register binder for callbacks 1897 if (mPrefDevDispatcherStub == null) { 1898 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub(); 1899 } 1900 try { 1901 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub); 1902 } catch (RemoteException e) { 1903 throw e.rethrowFromSystemServer(); 1904 } 1905 } 1906 } 1907 } 1908 1909 /** 1910 * @hide 1911 * Removes a previously added listener of changes to the strategy-preferred audio device. 1912 * @param listener 1913 */ 1914 @SystemApi 1915 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForStrategyChangedListener( @onNull OnPreferredDevicesForStrategyChangedListener listener)1916 public void removeOnPreferredDevicesForStrategyChangedListener( 1917 @NonNull OnPreferredDevicesForStrategyChangedListener listener) { 1918 Objects.requireNonNull(listener); 1919 synchronized (mPrefDevListenerLock) { 1920 if (!removePrefDevListener(listener)) { 1921 throw new IllegalArgumentException( 1922 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() " 1923 + "on an unregistered listener"); 1924 } 1925 if (mPrefDevListeners.size() == 0) { 1926 // unregister binder for callbacks 1927 try { 1928 getService().unregisterStrategyPreferredDevicesDispatcher( 1929 mPrefDevDispatcherStub); 1930 } catch (RemoteException e) { 1931 throw e.rethrowFromSystemServer(); 1932 } finally { 1933 mPrefDevDispatcherStub = null; 1934 mPrefDevListeners = null; 1935 } 1936 } 1937 } 1938 } 1939 1940 1941 private final Object mPrefDevListenerLock = new Object(); 1942 /** 1943 * List of listeners for preferred device for strategy and their associated Executor. 1944 * List is lazy-initialized on first registration 1945 */ 1946 @GuardedBy("mPrefDevListenerLock") 1947 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners; 1948 1949 private static class PrefDevListenerInfo { 1950 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener; 1951 final @NonNull Executor mExecutor; PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe)1952 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) { 1953 mListener = listener; 1954 mExecutor = exe; 1955 } 1956 } 1957 1958 @GuardedBy("mPrefDevListenerLock") 1959 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub; 1960 1961 private final class StrategyPreferredDevicesDispatcherStub 1962 extends IStrategyPreferredDevicesDispatcher.Stub { 1963 1964 @Override dispatchPrefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)1965 public void dispatchPrefDevicesChanged(int strategyId, 1966 @NonNull List<AudioDeviceAttributes> devices) { 1967 // make a shallow copy of listeners so callback is not executed under lock 1968 final ArrayList<PrefDevListenerInfo> prefDevListeners; 1969 synchronized (mPrefDevListenerLock) { 1970 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) { 1971 return; 1972 } 1973 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone(); 1974 } 1975 final AudioProductStrategy strategy = 1976 AudioProductStrategy.getAudioProductStrategyWithId(strategyId); 1977 final long ident = Binder.clearCallingIdentity(); 1978 try { 1979 for (PrefDevListenerInfo info : prefDevListeners) { 1980 info.mExecutor.execute(() -> 1981 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices)); 1982 } 1983 } finally { 1984 Binder.restoreCallingIdentity(ident); 1985 } 1986 } 1987 } 1988 1989 @GuardedBy("mPrefDevListenerLock") getPrefDevListenerInfo( OnPreferredDevicesForStrategyChangedListener listener)1990 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo( 1991 OnPreferredDevicesForStrategyChangedListener listener) { 1992 if (mPrefDevListeners == null) { 1993 return null; 1994 } 1995 for (PrefDevListenerInfo info : mPrefDevListeners) { 1996 if (info.mListener == listener) { 1997 return info; 1998 } 1999 } 2000 return null; 2001 } 2002 2003 @GuardedBy("mPrefDevListenerLock") hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener)2004 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { 2005 return getPrefDevListenerInfo(listener) != null; 2006 } 2007 2008 @GuardedBy("mPrefDevListenerLock") 2009 /** 2010 * @return true if the listener was removed from the list 2011 */ removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener)2012 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { 2013 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener); 2014 if (infoToRemove != null) { 2015 mPrefDevListeners.remove(infoToRemove); 2016 return true; 2017 } 2018 return false; 2019 } 2020 2021 //==================================================================== 2022 // Audio Capture Preset routing 2023 2024 /** 2025 * @hide 2026 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by 2027 * this capture preset. Note that the device may not be available at the time the preferred 2028 * device is set, but it will be used once made available. 2029 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference 2030 * for this capture preset.</p> 2031 * @param capturePreset the audio capture preset whose routing will be affected 2032 * @param device the audio device to route to when available 2033 * @return true if the operation was successful, false otherwise 2034 */ 2035 @SystemApi 2036 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForCapturePreset(@ediaRecorder.SystemSource int capturePreset, @NonNull AudioDeviceAttributes device)2037 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset, 2038 @NonNull AudioDeviceAttributes device) { 2039 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device)); 2040 } 2041 2042 /** 2043 * @hide 2044 * Remove all the preferred audio devices previously set 2045 * @param capturePreset the audio capture preset whose routing will be affected 2046 * @return true if the operation was successful, false otherwise (invalid capture preset, or no 2047 * device set for example) 2048 */ 2049 @SystemApi 2050 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) clearPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2051 public boolean clearPreferredDevicesForCapturePreset( 2052 @MediaRecorder.SystemSource int capturePreset) { 2053 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2054 return false; 2055 } 2056 try { 2057 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset); 2058 return status == AudioSystem.SUCCESS; 2059 } catch (RemoteException e) { 2060 throw e.rethrowFromSystemServer(); 2061 } 2062 } 2063 2064 /** 2065 * @hide 2066 * Return the preferred devices for an audio capture preset, previously set with 2067 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} 2068 * @param capturePreset the capture preset to query 2069 * @return a list that contains preferred devices for that capture preset. 2070 */ 2071 @NonNull 2072 @SystemApi 2073 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2074 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset( 2075 @MediaRecorder.SystemSource int capturePreset) { 2076 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2077 return new ArrayList<AudioDeviceAttributes>(); 2078 } 2079 try { 2080 return getService().getPreferredDevicesForCapturePreset(capturePreset); 2081 } catch (RemoteException e) { 2082 throw e.rethrowFromSystemServer(); 2083 } 2084 } 2085 setPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2086 private boolean setPreferredDevicesForCapturePreset( 2087 @MediaRecorder.SystemSource int capturePreset, 2088 @NonNull List<AudioDeviceAttributes> devices) { 2089 Objects.requireNonNull(devices); 2090 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2091 return false; 2092 } 2093 if (devices.size() != 1) { 2094 throw new IllegalArgumentException( 2095 "Only support setting one preferred devices for capture preset"); 2096 } 2097 for (AudioDeviceAttributes device : devices) { 2098 Objects.requireNonNull(device); 2099 } 2100 try { 2101 final int status = 2102 getService().setPreferredDevicesForCapturePreset(capturePreset, devices); 2103 return status == AudioSystem.SUCCESS; 2104 } catch (RemoteException e) { 2105 throw e.rethrowFromSystemServer(); 2106 } 2107 } 2108 2109 /** 2110 * @hide 2111 * Interface to be notified of changes in the preferred audio devices set for a given capture 2112 * preset. 2113 * <p>Note that this listener will only be invoked whenever 2114 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or 2115 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in 2116 * preferred device. It will not be invoked directly after registration with 2117 * {@link #addOnPreferredDevicesForCapturePresetChangedListener( 2118 * Executor, OnPreferredDevicesForCapturePresetChangedListener)} 2119 * to indicate which strategies had preferred devices at the time of registration.</p> 2120 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) 2121 * @see #clearPreferredDevicesForCapturePreset(int) 2122 * @see #getPreferredDevicesForCapturePreset(int) 2123 */ 2124 @SystemApi 2125 public interface OnPreferredDevicesForCapturePresetChangedListener { 2126 /** 2127 * Called on the listener to indicate that the preferred audio devices for the given 2128 * capture preset has changed. 2129 * @param capturePreset the capture preset whose preferred device changed 2130 * @param devices a list of newly set preferred audio devices 2131 */ onPreferredDevicesForCapturePresetChanged( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2132 void onPreferredDevicesForCapturePresetChanged( 2133 @MediaRecorder.SystemSource int capturePreset, 2134 @NonNull List<AudioDeviceAttributes> devices); 2135 } 2136 2137 /** 2138 * @hide 2139 * Adds a listener for being notified of changes to the capture-preset-preferred audio device. 2140 * @param executor 2141 * @param listener 2142 * @throws SecurityException if the caller doesn't hold the required permission 2143 */ 2144 @SystemApi 2145 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)2146 public void addOnPreferredDevicesForCapturePresetChangedListener( 2147 @NonNull @CallbackExecutor Executor executor, 2148 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) 2149 throws SecurityException { 2150 Objects.requireNonNull(executor); 2151 Objects.requireNonNull(listener); 2152 int status = addOnDevRoleForCapturePresetChangedListener( 2153 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2154 if (status == AudioSystem.ERROR) { 2155 // This must not happen 2156 throw new RuntimeException("Unknown error happened"); 2157 } 2158 if (status == AudioSystem.BAD_VALUE) { 2159 throw new IllegalArgumentException( 2160 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() " 2161 + "on a previously registered listener"); 2162 } 2163 } 2164 2165 /** 2166 * @hide 2167 * Removes a previously added listener of changes to the capture-preset-preferred audio device. 2168 * @param listener 2169 */ 2170 @SystemApi 2171 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForCapturePresetChangedListener( @onNull OnPreferredDevicesForCapturePresetChangedListener listener)2172 public void removeOnPreferredDevicesForCapturePresetChangedListener( 2173 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) { 2174 Objects.requireNonNull(listener); 2175 int status = removeOnDevRoleForCapturePresetChangedListener( 2176 listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2177 if (status == AudioSystem.ERROR) { 2178 // This must not happen 2179 throw new RuntimeException("Unknown error happened"); 2180 } 2181 if (status == AudioSystem.BAD_VALUE) { 2182 throw new IllegalArgumentException( 2183 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() " 2184 + "on an unregistered listener"); 2185 } 2186 } 2187 addOnDevRoleForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull T listener, int deviceRole)2188 private <T> int addOnDevRoleForCapturePresetChangedListener( 2189 @NonNull @CallbackExecutor Executor executor, 2190 @NonNull T listener, int deviceRole) { 2191 Objects.requireNonNull(executor); 2192 Objects.requireNonNull(listener); 2193 DevRoleListeners<T> devRoleListeners = 2194 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2195 if (devRoleListeners == null) { 2196 return AudioSystem.ERROR; 2197 } 2198 synchronized (devRoleListeners.mDevRoleListenersLock) { 2199 if (devRoleListeners.hasDevRoleListener(listener)) { 2200 return AudioSystem.BAD_VALUE; 2201 } 2202 // lazy initialization of the list of device role listener 2203 if (devRoleListeners.mListenerInfos == null) { 2204 devRoleListeners.mListenerInfos = new ArrayList<>(); 2205 } 2206 final int oldCbCount = devRoleListeners.mListenerInfos.size(); 2207 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener)); 2208 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) { 2209 // register binder for callbacks 2210 synchronized (mDevRoleForCapturePresetListenersLock) { 2211 int deviceRoleListenerStatus = mDeviceRoleListenersStatus; 2212 mDeviceRoleListenersStatus |= (1 << deviceRole); 2213 if (deviceRoleListenerStatus != 0) { 2214 // There are already device role changed listeners active. 2215 return AudioSystem.SUCCESS; 2216 } 2217 if (mDevicesRoleForCapturePresetDispatcherStub == null) { 2218 mDevicesRoleForCapturePresetDispatcherStub = 2219 new CapturePresetDevicesRoleDispatcherStub(); 2220 } 2221 try { 2222 getService().registerCapturePresetDevicesRoleDispatcher( 2223 mDevicesRoleForCapturePresetDispatcherStub); 2224 } catch (RemoteException e) { 2225 throw e.rethrowFromSystemServer(); 2226 } 2227 } 2228 } 2229 } 2230 return AudioSystem.SUCCESS; 2231 } 2232 removeOnDevRoleForCapturePresetChangedListener( @onNull T listener, int deviceRole)2233 private <T> int removeOnDevRoleForCapturePresetChangedListener( 2234 @NonNull T listener, int deviceRole) { 2235 Objects.requireNonNull(listener); 2236 DevRoleListeners<T> devRoleListeners = 2237 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2238 if (devRoleListeners == null) { 2239 return AudioSystem.ERROR; 2240 } 2241 synchronized (devRoleListeners.mDevRoleListenersLock) { 2242 if (!devRoleListeners.removeDevRoleListener(listener)) { 2243 return AudioSystem.BAD_VALUE; 2244 } 2245 if (devRoleListeners.mListenerInfos.size() == 0) { 2246 // unregister binder for callbacks 2247 synchronized (mDevRoleForCapturePresetListenersLock) { 2248 mDeviceRoleListenersStatus ^= (1 << deviceRole); 2249 if (mDeviceRoleListenersStatus != 0) { 2250 // There are some other device role changed listeners active. 2251 return AudioSystem.SUCCESS; 2252 } 2253 try { 2254 getService().unregisterCapturePresetDevicesRoleDispatcher( 2255 mDevicesRoleForCapturePresetDispatcherStub); 2256 } catch (RemoteException e) { 2257 throw e.rethrowFromSystemServer(); 2258 } 2259 } 2260 } 2261 } 2262 return AudioSystem.SUCCESS; 2263 } 2264 2265 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{ 2266 put(AudioSystem.DEVICE_ROLE_PREFERRED, 2267 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); 2268 }}; 2269 2270 private class DevRoleListenerInfo<T> { 2271 final @NonNull Executor mExecutor; 2272 final @NonNull T mListener; DevRoleListenerInfo(Executor executor, T listener)2273 DevRoleListenerInfo(Executor executor, T listener) { 2274 mExecutor = executor; 2275 mListener = listener; 2276 } 2277 } 2278 2279 private class DevRoleListeners<T> { 2280 private final Object mDevRoleListenersLock = new Object(); 2281 @GuardedBy("mDevRoleListenersLock") 2282 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos; 2283 2284 @GuardedBy("mDevRoleListenersLock") getDevRoleListenerInfo(T listener)2285 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) { 2286 if (mListenerInfos == null) { 2287 return null; 2288 } 2289 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) { 2290 if (listenerInfo.mListener == listener) { 2291 return listenerInfo; 2292 } 2293 } 2294 return null; 2295 } 2296 2297 @GuardedBy("mDevRoleListenersLock") hasDevRoleListener(T listener)2298 private boolean hasDevRoleListener(T listener) { 2299 return getDevRoleListenerInfo(listener) != null; 2300 } 2301 2302 @GuardedBy("mDevRoleListenersLock") removeDevRoleListener(T listener)2303 private boolean removeDevRoleListener(T listener) { 2304 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener); 2305 if (infoToRemove != null) { 2306 mListenerInfos.remove(infoToRemove); 2307 return true; 2308 } 2309 return false; 2310 } 2311 } 2312 2313 private final Object mDevRoleForCapturePresetListenersLock = new Object(); 2314 /** 2315 * Record if there is a listener added for device role change. If there is a listener added for 2316 * a specified device role change, the bit at position `1 << device_role` is set. 2317 */ 2318 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2319 private int mDeviceRoleListenersStatus = 0; 2320 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2321 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub; 2322 2323 private final class CapturePresetDevicesRoleDispatcherStub 2324 extends ICapturePresetDevicesRoleDispatcher.Stub { 2325 2326 @Override dispatchDevicesRoleChanged( int capturePreset, int role, List<AudioDeviceAttributes> devices)2327 public void dispatchDevicesRoleChanged( 2328 int capturePreset, int role, List<AudioDeviceAttributes> devices) { 2329 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role); 2330 if (listenersObj == null) { 2331 return; 2332 } 2333 switch (role) { 2334 case AudioSystem.DEVICE_ROLE_PREFERRED: { 2335 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener> 2336 listeners = 2337 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>) 2338 listenersObj; 2339 final ArrayList<DevRoleListenerInfo< 2340 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners; 2341 synchronized (listeners.mDevRoleListenersLock) { 2342 if (listeners.mListenerInfos.isEmpty()) { 2343 return; 2344 } 2345 prefDevListeners = (ArrayList<DevRoleListenerInfo< 2346 OnPreferredDevicesForCapturePresetChangedListener>>) 2347 listeners.mListenerInfos.clone(); 2348 } 2349 final long ident = Binder.clearCallingIdentity(); 2350 try { 2351 for (DevRoleListenerInfo< 2352 OnPreferredDevicesForCapturePresetChangedListener> info : 2353 prefDevListeners) { 2354 info.mExecutor.execute(() -> 2355 info.mListener.onPreferredDevicesForCapturePresetChanged( 2356 capturePreset, devices)); 2357 } 2358 } finally { 2359 Binder.restoreCallingIdentity(ident); 2360 } 2361 } break; 2362 default: 2363 break; 2364 } 2365 } 2366 } 2367 2368 //==================================================================== 2369 // Offload query 2370 /** 2371 * Returns whether offloaded playback of an audio format is supported on the device. 2372 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 2373 * is not competing with other software resources. In general, it is supported by dedicated 2374 * hardware, such as audio DSPs. 2375 * <p>Note that this query only provides information about the support of an audio format, 2376 * it does not indicate whether the resources necessary for the offloaded playback are 2377 * available at that instant. 2378 * @param format the audio format (codec, sample rate, channels) being checked. 2379 * @param attributes the {@link AudioAttributes} to be used for playback 2380 * @return true if the given audio format can be offloaded. 2381 */ isOffloadedPlaybackSupported(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2382 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format, 2383 @NonNull AudioAttributes attributes) { 2384 if (format == null) { 2385 throw new NullPointerException("Illegal null AudioFormat"); 2386 } 2387 if (attributes == null) { 2388 throw new NullPointerException("Illegal null AudioAttributes"); 2389 } 2390 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED; 2391 } 2392 2393 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2394 offload playback not supported */ 2395 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED; 2396 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2397 offload playback supported */ 2398 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED; 2399 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 2400 offload playback supported with gapless transitions */ 2401 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 2402 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED; 2403 2404 /** @hide */ 2405 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = { 2406 PLAYBACK_OFFLOAD_NOT_SUPPORTED, 2407 PLAYBACK_OFFLOAD_SUPPORTED, 2408 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED } 2409 ) 2410 @Retention(RetentionPolicy.SOURCE) 2411 public @interface AudioOffloadMode {} 2412 2413 /** 2414 * Returns whether offloaded playback of an audio format is supported on the device or not and 2415 * when supported whether gapless transitions are possible or not. 2416 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 2417 * is not competing with other software resources. In general, it is supported by dedicated 2418 * hardware, such as audio DSPs. 2419 * <p>Note that this query only provides information about the support of an audio format, 2420 * it does not indicate whether the resources necessary for the offloaded playback are 2421 * available at that instant. 2422 * @param format the audio format (codec, sample rate, channels) being checked. 2423 * @param attributes the {@link AudioAttributes} to be used for playback 2424 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported, 2425 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or 2426 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are 2427 * also supported. 2428 */ 2429 @AudioOffloadMode getPlaybackOffloadSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2430 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format, 2431 @NonNull AudioAttributes attributes) { 2432 if (format == null) { 2433 throw new NullPointerException("Illegal null AudioFormat"); 2434 } 2435 if (attributes == null) { 2436 throw new NullPointerException("Illegal null AudioAttributes"); 2437 } 2438 return AudioSystem.getOffloadSupport(format, attributes); 2439 } 2440 2441 //==================================================================== 2442 // Immersive audio 2443 2444 /** 2445 * Return a handle to the optional platform's {@link Spatializer} 2446 * @return the {@code Spatializer} instance. 2447 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect 2448 * on the platform 2449 */ getSpatializer()2450 public @NonNull Spatializer getSpatializer() { 2451 return new Spatializer(this); 2452 } 2453 2454 //==================================================================== 2455 // Bluetooth SCO control 2456 /** 2457 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2458 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE} 2459 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED} 2460 * or {@link #SCO_AUDIO_STATE_CONNECTED} 2461 * 2462 * @see #startBluetoothSco() 2463 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead 2464 */ 2465 @Deprecated 2466 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2467 public static final String ACTION_SCO_AUDIO_STATE_CHANGED = 2468 "android.media.SCO_AUDIO_STATE_CHANGED"; 2469 2470 /** 2471 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2472 * connection state has been updated. 2473 * <p>This intent has two extras: 2474 * <ul> 2475 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li> 2476 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li> 2477 * </ul> 2478 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of: 2479 * <ul> 2480 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li> 2481 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li> 2482 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li> 2483 * </ul> 2484 * @see #startBluetoothSco() 2485 */ 2486 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2487 public static final String ACTION_SCO_AUDIO_STATE_UPDATED = 2488 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; 2489 2490 /** 2491 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or 2492 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state. 2493 */ 2494 public static final String EXTRA_SCO_AUDIO_STATE = 2495 "android.media.extra.SCO_AUDIO_STATE"; 2496 2497 /** 2498 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous 2499 * bluetooth SCO connection state. 2500 */ 2501 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = 2502 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"; 2503 2504 /** 2505 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 2506 * indicating that the SCO audio channel is not established 2507 */ 2508 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; 2509 /** 2510 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE} 2511 * indicating that the SCO audio channel is established 2512 */ 2513 public static final int SCO_AUDIO_STATE_CONNECTED = 1; 2514 /** 2515 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 2516 * indicating that the SCO audio channel is being established 2517 */ 2518 public static final int SCO_AUDIO_STATE_CONNECTING = 2; 2519 /** 2520 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that 2521 * there was an error trying to obtain the state 2522 */ 2523 public static final int SCO_AUDIO_STATE_ERROR = -1; 2524 2525 2526 /** 2527 * Indicates if current platform supports use of SCO for off call use cases. 2528 * Application wanted to use bluetooth SCO audio when the phone is not in call 2529 * must first call this method to make sure that the platform supports this 2530 * feature. 2531 * @return true if bluetooth SCO can be used for audio when not in call 2532 * false otherwise 2533 * @see #startBluetoothSco() 2534 */ isBluetoothScoAvailableOffCall()2535 public boolean isBluetoothScoAvailableOffCall() { 2536 return getContext().getResources().getBoolean( 2537 com.android.internal.R.bool.config_bluetooth_sco_off_call); 2538 } 2539 2540 /** 2541 * Start bluetooth SCO audio connection. 2542 * <p>Requires Permission: 2543 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2544 * <p>This method can be used by applications wanting to send and received audio 2545 * to/from a bluetooth SCO headset while the phone is not in call. 2546 * <p>As the SCO connection establishment can take several seconds, 2547 * applications should not rely on the connection to be available when the method 2548 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} 2549 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}. 2550 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO 2551 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver 2552 * registration. If the state is already CONNECTED, no state change will be received via the 2553 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco() 2554 * so that the connection stays active in case the current initiator stops the connection. 2555 * <p>Unless the connection is already active as described above, the state will always 2556 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection 2557 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected). 2558 * <p>When finished with the SCO connection or if the establishment fails, the application must 2559 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection. 2560 * <p>Even if a SCO connection is established, the following restrictions apply on audio 2561 * output streams so that they can be routed to SCO headset: 2562 * <ul> 2563 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> 2564 * <li> the format must be mono </li> 2565 * <li> the sampling must be 16kHz or 8kHz </li> 2566 * </ul> 2567 * <p>The following restrictions apply on input streams: 2568 * <ul> 2569 * <li> the format must be mono </li> 2570 * <li> the sampling must be 8kHz </li> 2571 * </ul> 2572 * <p>Note that the phone application always has the priority on the usage of the SCO 2573 * connection for telephony. If this method is called while the phone is in call 2574 * it will be ignored. Similarly, if a call is received or sent while an application 2575 * is using the SCO connection, the connection will be lost for the application and NOT 2576 * returned automatically when the call ends. 2577 * <p>NOTE: up to and including API version 2578 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual 2579 * voice call to the bluetooth headset. 2580 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio 2581 * connection is established. 2582 * @see #stopBluetoothSco() 2583 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 2584 */ startBluetoothSco()2585 public void startBluetoothSco(){ 2586 final IAudioService service = getService(); 2587 try { 2588 service.startBluetoothSco(mICallBack, 2589 getContext().getApplicationInfo().targetSdkVersion); 2590 } catch (RemoteException e) { 2591 throw e.rethrowFromSystemServer(); 2592 } 2593 } 2594 2595 /** 2596 * @hide 2597 * Start bluetooth SCO audio connection in virtual call mode. 2598 * <p>Requires Permission: 2599 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2600 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode. 2601 * Telephony and communication applications (VoIP, Video Chat) should preferably select 2602 * virtual call mode. 2603 * Applications using voice input for search or commands should first try raw audio connection 2604 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of 2605 * failure. 2606 * @see #startBluetoothSco() 2607 * @see #stopBluetoothSco() 2608 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 2609 */ 2610 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) startBluetoothScoVirtualCall()2611 public void startBluetoothScoVirtualCall() { 2612 final IAudioService service = getService(); 2613 try { 2614 service.startBluetoothScoVirtualCall(mICallBack); 2615 } catch (RemoteException e) { 2616 throw e.rethrowFromSystemServer(); 2617 } 2618 } 2619 2620 /** 2621 * Stop bluetooth SCO audio connection. 2622 * <p>Requires Permission: 2623 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2624 * <p>This method must be called by applications having requested the use of 2625 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO 2626 * connection or if connection fails. 2627 * @see #startBluetoothSco() 2628 */ 2629 // Also used for connections started with {@link #startBluetoothScoVirtualCall()} stopBluetoothSco()2630 public void stopBluetoothSco(){ 2631 final IAudioService service = getService(); 2632 try { 2633 service.stopBluetoothSco(mICallBack); 2634 } catch (RemoteException e) { 2635 throw e.rethrowFromSystemServer(); 2636 } 2637 } 2638 2639 /** 2640 * Request use of Bluetooth SCO headset for communications. 2641 * <p> 2642 * This method should only be used by applications that replace the platform-wide 2643 * management of audio settings or the main telephony application. 2644 * 2645 * @param on set <var>true</var> to use bluetooth SCO for communications; 2646 * <var>false</var> to not use bluetooth SCO for communications 2647 */ setBluetoothScoOn(boolean on)2648 public void setBluetoothScoOn(boolean on){ 2649 final IAudioService service = getService(); 2650 try { 2651 service.setBluetoothScoOn(on); 2652 } catch (RemoteException e) { 2653 throw e.rethrowFromSystemServer(); 2654 } 2655 } 2656 2657 /** 2658 * Checks whether communications use Bluetooth SCO. 2659 * 2660 * @return true if SCO is used for communications; 2661 * false if otherwise 2662 */ isBluetoothScoOn()2663 public boolean isBluetoothScoOn() { 2664 final IAudioService service = getService(); 2665 try { 2666 return service.isBluetoothScoOn(); 2667 } catch (RemoteException e) { 2668 throw e.rethrowFromSystemServer(); 2669 } 2670 } 2671 2672 /** 2673 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth 2674 * headset; <var>false</var> disable A2DP audio 2675 * @deprecated Do not use. 2676 */ setBluetoothA2dpOn(boolean on)2677 @Deprecated public void setBluetoothA2dpOn(boolean on){ 2678 } 2679 2680 /** 2681 * Checks whether a Bluetooth A2DP audio peripheral is connected or not. 2682 * 2683 * @return true if a Bluetooth A2DP peripheral is connected 2684 * false if otherwise 2685 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 2686 */ isBluetoothA2dpOn()2687 public boolean isBluetoothA2dpOn() { 2688 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") 2689 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2690 return true; 2691 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"") 2692 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2693 return true; 2694 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"") 2695 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2696 return true; 2697 } 2698 return false; 2699 } 2700 2701 /** 2702 * Sets audio routing to the wired headset on or off. 2703 * 2704 * @param on set <var>true</var> to route audio to/from wired 2705 * headset; <var>false</var> disable wired headset audio 2706 * @deprecated Do not use. 2707 */ setWiredHeadsetOn(boolean on)2708 @Deprecated public void setWiredHeadsetOn(boolean on){ 2709 } 2710 2711 /** 2712 * Checks whether a wired headset is connected or not. 2713 * <p>This is not a valid indication that audio playback is 2714 * actually over the wired headset as audio routing depends on other conditions. 2715 * 2716 * @return true if a wired headset is connected. 2717 * false if otherwise 2718 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 2719 */ isWiredHeadsetOn()2720 public boolean isWiredHeadsetOn() { 2721 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"") 2722 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 2723 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"") 2724 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 2725 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "") 2726 == AudioSystem.DEVICE_STATE_UNAVAILABLE) { 2727 return false; 2728 } else { 2729 return true; 2730 } 2731 } 2732 2733 /** 2734 * Sets the microphone mute on or off. 2735 * <p> 2736 * This method should only be used by applications that replace the platform-wide 2737 * management of audio settings or the main telephony application. 2738 * 2739 * @param on set <var>true</var> to mute the microphone; 2740 * <var>false</var> to turn mute off 2741 */ setMicrophoneMute(boolean on)2742 public void setMicrophoneMute(boolean on) { 2743 final IAudioService service = getService(); 2744 try { 2745 service.setMicrophoneMute(on, getContext().getOpPackageName(), 2746 UserHandle.getCallingUserId()); 2747 } catch (RemoteException e) { 2748 throw e.rethrowFromSystemServer(); 2749 } 2750 } 2751 2752 /** 2753 * @hide 2754 * Sets the microphone from switch mute on or off. 2755 * <p> 2756 * This method should only be used by InputManager to notify 2757 * Audio Subsystem about Microphone Mute switch state. 2758 * 2759 * @param on set <var>true</var> to mute the microphone; 2760 * <var>false</var> to turn mute off 2761 */ 2762 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setMicrophoneMuteFromSwitch(boolean on)2763 public void setMicrophoneMuteFromSwitch(boolean on) { 2764 final IAudioService service = getService(); 2765 try { 2766 service.setMicrophoneMuteFromSwitch(on); 2767 } catch (RemoteException e) { 2768 throw e.rethrowFromSystemServer(); 2769 } 2770 } 2771 2772 /** 2773 * Checks whether the microphone mute is on or off. 2774 * 2775 * @return true if microphone is muted, false if it's not 2776 */ isMicrophoneMute()2777 public boolean isMicrophoneMute() { 2778 final IAudioService service = getService(); 2779 try { 2780 return service.isMicrophoneMuted(); 2781 } catch (RemoteException e) { 2782 throw e.rethrowFromSystemServer(); 2783 } 2784 } 2785 2786 /** 2787 * Broadcast Action: microphone muting state changed. 2788 * 2789 * You <em>cannot</em> receive this through components declared 2790 * in manifests, only by explicitly registering for it with 2791 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 2792 * Context.registerReceiver()}. 2793 * 2794 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the 2795 * microphone is muted. 2796 */ 2797 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2798 public static final String ACTION_MICROPHONE_MUTE_CHANGED = 2799 "android.media.action.MICROPHONE_MUTE_CHANGED"; 2800 2801 /** 2802 * Broadcast Action: speakerphone state changed. 2803 * 2804 * You <em>cannot</em> receive this through components declared 2805 * in manifests, only by explicitly registering for it with 2806 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 2807 * Context.registerReceiver()}. 2808 * 2809 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the 2810 * speakerphone functionality is enabled or not. 2811 */ 2812 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2813 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = 2814 "android.media.action.SPEAKERPHONE_STATE_CHANGED"; 2815 2816 /** 2817 * Sets the audio mode. 2818 * <p> 2819 * The audio mode encompasses audio routing AND the behavior of 2820 * the telephony layer. Therefore this method should only be used by applications that 2821 * replace the platform-wide management of audio settings or the main telephony application. 2822 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony 2823 * application when it places a phone call, as it will cause signals from the radio layer 2824 * to feed the platform mixer. 2825 * 2826 * @param mode the requested audio mode. 2827 * Informs the HAL about the current audio state so that 2828 * it can route the audio appropriately. 2829 */ setMode(@udioMode int mode)2830 public void setMode(@AudioMode int mode) { 2831 final IAudioService service = getService(); 2832 try { 2833 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); 2834 } catch (RemoteException e) { 2835 throw e.rethrowFromSystemServer(); 2836 } 2837 } 2838 2839 /** 2840 * Returns the current audio mode. 2841 * 2842 * @return the current audio mode. 2843 */ 2844 @AudioMode getMode()2845 public int getMode() { 2846 final IAudioService service = getService(); 2847 try { 2848 int mode = service.getMode(); 2849 int sdk; 2850 try { 2851 sdk = getContext().getApplicationInfo().targetSdkVersion; 2852 } catch (NullPointerException e) { 2853 // some tests don't have a Context 2854 sdk = Build.VERSION.SDK_INT; 2855 } 2856 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { 2857 mode = MODE_IN_CALL; 2858 } 2859 return mode; 2860 } catch (RemoteException e) { 2861 throw e.rethrowFromSystemServer(); 2862 } 2863 } 2864 2865 /** 2866 * Interface definition of a callback that is notified when the audio mode changes 2867 */ 2868 public interface OnModeChangedListener { 2869 /** 2870 * Called on the listener to indicate that the audio mode has changed 2871 * 2872 * @param mode The current audio mode 2873 */ onModeChanged(@udioMode int mode)2874 void onModeChanged(@AudioMode int mode); 2875 } 2876 2877 private final Object mModeListenerLock = new Object(); 2878 /** 2879 * List of listeners for audio mode and their associated Executor. 2880 * List is lazy-initialized on first registration 2881 */ 2882 @GuardedBy("mModeListenerLock") 2883 private @Nullable ArrayList<ModeListenerInfo> mModeListeners; 2884 2885 @GuardedBy("mModeListenerLock") 2886 private ModeDispatcherStub mModeDispatcherStub; 2887 2888 private final class ModeDispatcherStub 2889 extends IAudioModeDispatcher.Stub { 2890 2891 @Override dispatchAudioModeChanged(int mode)2892 public void dispatchAudioModeChanged(int mode) { 2893 // make a shallow copy of listeners so callback is not executed under lock 2894 final ArrayList<ModeListenerInfo> modeListeners; 2895 synchronized (mModeListenerLock) { 2896 if (mModeListeners == null || mModeListeners.size() == 0) { 2897 return; 2898 } 2899 modeListeners = (ArrayList<ModeListenerInfo>) mModeListeners.clone(); 2900 } 2901 final long ident = Binder.clearCallingIdentity(); 2902 try { 2903 for (ModeListenerInfo info : modeListeners) { 2904 info.mExecutor.execute(() -> 2905 info.mListener.onModeChanged(mode)); 2906 } 2907 } finally { 2908 Binder.restoreCallingIdentity(ident); 2909 } 2910 } 2911 } 2912 2913 private static class ModeListenerInfo { 2914 final @NonNull OnModeChangedListener mListener; 2915 final @NonNull Executor mExecutor; 2916 ModeListenerInfo(OnModeChangedListener listener, Executor exe)2917 ModeListenerInfo(OnModeChangedListener listener, Executor exe) { 2918 mListener = listener; 2919 mExecutor = exe; 2920 } 2921 } 2922 2923 @GuardedBy("mModeListenerLock") hasModeListener(OnModeChangedListener listener)2924 private boolean hasModeListener(OnModeChangedListener listener) { 2925 return getModeListenerInfo(listener) != null; 2926 } 2927 2928 @GuardedBy("mModeListenerLock") getModeListenerInfo( OnModeChangedListener listener)2929 private @Nullable ModeListenerInfo getModeListenerInfo( 2930 OnModeChangedListener listener) { 2931 if (mModeListeners == null) { 2932 return null; 2933 } 2934 for (ModeListenerInfo info : mModeListeners) { 2935 if (info.mListener == listener) { 2936 return info; 2937 } 2938 } 2939 return null; 2940 } 2941 2942 2943 @GuardedBy("mModeListenerLock") 2944 /** 2945 * @return true if the listener was removed from the list 2946 */ removeModeListener(OnModeChangedListener listener)2947 private boolean removeModeListener(OnModeChangedListener listener) { 2948 final ModeListenerInfo infoToRemove = getModeListenerInfo(listener); 2949 if (infoToRemove != null) { 2950 mModeListeners.remove(infoToRemove); 2951 return true; 2952 } 2953 return false; 2954 } 2955 2956 /** 2957 * Adds a listener to be notified of changes to the audio mode. 2958 * See {@link #getMode()} 2959 * @param executor 2960 * @param listener 2961 */ addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)2962 public void addOnModeChangedListener( 2963 @NonNull @CallbackExecutor Executor executor, 2964 @NonNull OnModeChangedListener listener) { 2965 Objects.requireNonNull(executor); 2966 Objects.requireNonNull(listener); 2967 synchronized (mModeListenerLock) { 2968 if (hasModeListener(listener)) { 2969 throw new IllegalArgumentException("attempt to call addOnModeChangedListener() " 2970 + "on a previously registered listener"); 2971 } 2972 // lazy initialization of the list of strategy-preferred device listener 2973 if (mModeListeners == null) { 2974 mModeListeners = new ArrayList<>(); 2975 } 2976 final int oldCbCount = mModeListeners.size(); 2977 mModeListeners.add(new ModeListenerInfo(listener, executor)); 2978 if (oldCbCount == 0) { 2979 // register binder for callbacks 2980 if (mModeDispatcherStub == null) { 2981 mModeDispatcherStub = new ModeDispatcherStub(); 2982 } 2983 try { 2984 getService().registerModeDispatcher(mModeDispatcherStub); 2985 } catch (RemoteException e) { 2986 throw e.rethrowFromSystemServer(); 2987 } 2988 } 2989 } 2990 } 2991 2992 /** 2993 * Removes a previously added listener for changes to audio mode. 2994 * See {@link #getMode()} 2995 * @param listener 2996 */ removeOnModeChangedListener(@onNull OnModeChangedListener listener)2997 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) { 2998 Objects.requireNonNull(listener); 2999 synchronized (mModeListenerLock) { 3000 if (!removeModeListener(listener)) { 3001 throw new IllegalArgumentException("attempt to call removeOnModeChangedListener() " 3002 + "on an unregistered listener"); 3003 } 3004 if (mModeListeners.size() == 0) { 3005 // unregister binder for callbacks 3006 try { 3007 getService().unregisterModeDispatcher(mModeDispatcherStub); 3008 } catch (RemoteException e) { 3009 throw e.rethrowFromSystemServer(); 3010 } finally { 3011 mModeDispatcherStub = null; 3012 mModeListeners = null; 3013 } 3014 } 3015 } 3016 } 3017 3018 /** 3019 * Indicates if the platform supports a special call screening and call monitoring mode. 3020 * <p> 3021 * When this mode is supported, it is possible to perform call screening and monitoring 3022 * functions while other use cases like music or movie playback are active. 3023 * <p> 3024 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in 3025 * call screening mode. 3026 * <p> 3027 * If call screening mode is not supported, setting mode to 3028 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by 3029 * {@link #getMode()}. 3030 * @return true if call screening mode is supported, false otherwise. 3031 */ isCallScreeningModeSupported()3032 public boolean isCallScreeningModeSupported() { 3033 final IAudioService service = getService(); 3034 try { 3035 return service.isCallScreeningModeSupported(); 3036 } catch (RemoteException e) { 3037 throw e.rethrowFromSystemServer(); 3038 } 3039 } 3040 3041 /* modes for setMode/getMode/setRoute/getRoute */ 3042 /** 3043 * Audio harware modes. 3044 */ 3045 /** 3046 * Invalid audio mode. 3047 */ 3048 public static final int MODE_INVALID = AudioSystem.MODE_INVALID; 3049 /** 3050 * Current audio mode. Used to apply audio routing to current mode. 3051 */ 3052 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; 3053 /** 3054 * Normal audio mode: not ringing and no call established. 3055 */ 3056 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; 3057 /** 3058 * Ringing audio mode. An incoming is being signaled. 3059 */ 3060 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; 3061 /** 3062 * In call audio mode. A telephony call is established. 3063 */ 3064 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; 3065 /** 3066 * In communication audio mode. An audio/video chat or VoIP call is established. 3067 */ 3068 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; 3069 /** 3070 * Call screening in progress. Call is connected and audio is accessible to call 3071 * screening applications but other audio use cases are still possible. 3072 */ 3073 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; 3074 3075 /** @hide */ 3076 @IntDef(flag = false, prefix = "MODE_", value = { 3077 MODE_NORMAL, 3078 MODE_RINGTONE, 3079 MODE_IN_CALL, 3080 MODE_IN_COMMUNICATION, 3081 MODE_CALL_SCREENING } 3082 ) 3083 @Retention(RetentionPolicy.SOURCE) 3084 public @interface AudioMode {} 3085 3086 /* Routing bits for setRouting/getRouting API */ 3087 /** 3088 * Routing audio output to earpiece 3089 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3090 * setBluetoothScoOn() methods instead. 3091 */ 3092 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; 3093 /** 3094 * Routing audio output to speaker 3095 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3096 * setBluetoothScoOn() methods instead. 3097 */ 3098 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; 3099 /** 3100 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} 3101 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3102 * setBluetoothScoOn() methods instead. 3103 */ 3104 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; 3105 /** 3106 * Routing audio output to bluetooth SCO 3107 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3108 * setBluetoothScoOn() methods instead. 3109 */ 3110 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; 3111 /** 3112 * Routing audio output to headset 3113 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3114 * setBluetoothScoOn() methods instead. 3115 */ 3116 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; 3117 /** 3118 * Routing audio output to bluetooth A2DP 3119 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3120 * setBluetoothScoOn() methods instead. 3121 */ 3122 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; 3123 /** 3124 * Used for mask parameter of {@link #setRouting(int,int,int)}. 3125 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3126 * setBluetoothScoOn() methods instead. 3127 */ 3128 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; 3129 3130 /** 3131 * Sets the audio routing for a specified mode 3132 * 3133 * @param mode audio mode to change route. E.g., MODE_RINGTONE. 3134 * @param routes bit vector of routes requested, created from one or 3135 * more of ROUTE_xxx types. Set bits indicate that route should be on 3136 * @param mask bit vector of routes to change, created from one or more of 3137 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged 3138 * 3139 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3140 * setBluetoothScoOn() methods instead. 3141 */ 3142 @Deprecated setRouting(int mode, int routes, int mask)3143 public void setRouting(int mode, int routes, int mask) { 3144 } 3145 3146 /** 3147 * Returns the current audio routing bit vector for a specified mode. 3148 * 3149 * @param mode audio mode to get route (e.g., MODE_RINGTONE) 3150 * @return an audio route bit vector that can be compared with ROUTE_xxx 3151 * bits 3152 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(), 3153 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead. 3154 */ 3155 @Deprecated getRouting(int mode)3156 public int getRouting(int mode) { 3157 return -1; 3158 } 3159 3160 /** 3161 * Checks whether any music is active. 3162 * 3163 * @return true if any music tracks are active. 3164 */ isMusicActive()3165 public boolean isMusicActive() { 3166 final IAudioService service = getService(); 3167 try { 3168 return service.isMusicActive(false /*remotely*/); 3169 } catch (RemoteException e) { 3170 throw e.rethrowFromSystemServer(); 3171 } 3172 } 3173 3174 /** 3175 * @hide 3176 * Checks whether any music or media is actively playing on a remote device (e.g. wireless 3177 * display). Note that BT audio sinks are not considered remote devices. 3178 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device 3179 */ 3180 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isMusicActiveRemotely()3181 public boolean isMusicActiveRemotely() { 3182 final IAudioService service = getService(); 3183 try { 3184 return service.isMusicActive(true /*remotely*/); 3185 } catch (RemoteException e) { 3186 throw e.rethrowFromSystemServer(); 3187 } 3188 } 3189 3190 /** 3191 * @hide 3192 * Checks whether the current audio focus is exclusive. 3193 * @return true if the top of the audio focus stack requested focus 3194 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} 3195 */ isAudioFocusExclusive()3196 public boolean isAudioFocusExclusive() { 3197 final IAudioService service = getService(); 3198 try { 3199 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; 3200 } catch (RemoteException e) { 3201 throw e.rethrowFromSystemServer(); 3202 } 3203 } 3204 3205 /** 3206 * Return a new audio session identifier not associated with any player or effect. 3207 * An audio session identifier is a system wide unique identifier for a set of audio streams 3208 * (one or more mixed together). 3209 * <p>The primary use of the audio session ID is to associate audio effects to audio players, 3210 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio 3211 * session ID will be applied to the mixed audio content of the players that share the same 3212 * audio session. 3213 * <p>This method can for instance be used when creating one of the 3214 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect, 3215 * or to specify a session for a speech synthesis utterance 3216 * in {@link android.speech.tts.TextToSpeech.Engine}. 3217 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the 3218 * system failed to generate a new session, a condition in which audio playback or recording 3219 * will subsequently fail as well. 3220 */ generateAudioSessionId()3221 public int generateAudioSessionId() { 3222 int session = AudioSystem.newAudioSessionId(); 3223 if (session > 0) { 3224 return session; 3225 } else { 3226 Log.e(TAG, "Failure to generate a new audio session ID"); 3227 return ERROR; 3228 } 3229 } 3230 3231 /** 3232 * A special audio session ID to indicate that the audio session ID isn't known and the 3233 * framework should generate a new value. This can be used when building a new 3234 * {@link AudioTrack} instance with 3235 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}. 3236 */ 3237 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE; 3238 3239 3240 /* 3241 * Sets a generic audio configuration parameter. The use of these parameters 3242 * are platform dependant, see libaudio 3243 * 3244 * ** Temporary interface - DO NOT USE 3245 * 3246 * TODO: Replace with a more generic key:value get/set mechanism 3247 * 3248 * param key name of parameter to set. Must not be null. 3249 * param value value of parameter. Must not be null. 3250 */ 3251 /** 3252 * @hide 3253 * @deprecated Use {@link #setParameters(String)} instead 3254 */ setParameter(String key, String value)3255 @Deprecated public void setParameter(String key, String value) { 3256 setParameters(key+"="+value); 3257 } 3258 3259 /** 3260 * Sets a variable number of parameter values to audio hardware. 3261 * 3262 * @param keyValuePairs list of parameters key value pairs in the form: 3263 * key1=value1;key2=value2;... 3264 * 3265 */ setParameters(String keyValuePairs)3266 public void setParameters(String keyValuePairs) { 3267 AudioSystem.setParameters(keyValuePairs); 3268 } 3269 3270 /** 3271 * Gets a variable number of parameter values from audio hardware. 3272 * 3273 * @param keys list of parameters 3274 * @return list of parameters key value pairs in the form: 3275 * key1=value1;key2=value2;... 3276 */ getParameters(String keys)3277 public String getParameters(String keys) { 3278 return AudioSystem.getParameters(keys); 3279 } 3280 3281 /* Sound effect identifiers */ 3282 /** 3283 * Keyboard and direction pad click sound 3284 * @see #playSoundEffect(int) 3285 */ 3286 public static final int FX_KEY_CLICK = 0; 3287 /** 3288 * Focus has moved up 3289 * @see #playSoundEffect(int) 3290 */ 3291 public static final int FX_FOCUS_NAVIGATION_UP = 1; 3292 /** 3293 * Focus has moved down 3294 * @see #playSoundEffect(int) 3295 */ 3296 public static final int FX_FOCUS_NAVIGATION_DOWN = 2; 3297 /** 3298 * Focus has moved left 3299 * @see #playSoundEffect(int) 3300 */ 3301 public static final int FX_FOCUS_NAVIGATION_LEFT = 3; 3302 /** 3303 * Focus has moved right 3304 * @see #playSoundEffect(int) 3305 */ 3306 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; 3307 /** 3308 * IME standard keypress sound 3309 * @see #playSoundEffect(int) 3310 */ 3311 public static final int FX_KEYPRESS_STANDARD = 5; 3312 /** 3313 * IME spacebar keypress sound 3314 * @see #playSoundEffect(int) 3315 */ 3316 public static final int FX_KEYPRESS_SPACEBAR = 6; 3317 /** 3318 * IME delete keypress sound 3319 * @see #playSoundEffect(int) 3320 */ 3321 public static final int FX_KEYPRESS_DELETE = 7; 3322 /** 3323 * IME return_keypress sound 3324 * @see #playSoundEffect(int) 3325 */ 3326 public static final int FX_KEYPRESS_RETURN = 8; 3327 3328 /** 3329 * Invalid keypress sound 3330 * @see #playSoundEffect(int) 3331 */ 3332 public static final int FX_KEYPRESS_INVALID = 9; 3333 3334 /** 3335 * Back sound 3336 * @see #playSoundEffect(int) 3337 */ 3338 public static final int FX_BACK = 10; 3339 3340 /** 3341 * @hide Home sound 3342 * <p> 3343 * To be played by the framework when the home app becomes active if config_enableHomeSound is 3344 * set to true. This is currently only used on TV devices. 3345 * Note that this sound is only available if a sound file is specified in audio_assets.xml. 3346 * @see #playSoundEffect(int) 3347 */ 3348 public static final int FX_HOME = 11; 3349 3350 /** 3351 * @hide Navigation repeat sound 1 3352 * <p> 3353 * To be played by the framework when a focus navigation is repeatedly triggered 3354 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3355 * This is currently only used on TV devices. 3356 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3357 * @see #playSoundEffect(int) 3358 */ 3359 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12; 3360 3361 /** 3362 * @hide Navigation repeat sound 2 3363 * <p> 3364 * To be played by the framework when a focus navigation is repeatedly triggered 3365 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3366 * This is currently only used on TV devices. 3367 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3368 * @see #playSoundEffect(int) 3369 */ 3370 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13; 3371 3372 /** 3373 * @hide Navigation repeat sound 3 3374 * <p> 3375 * To be played by the framework when a focus navigation is repeatedly triggered 3376 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3377 * This is currently only used on TV devices. 3378 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3379 * @see #playSoundEffect(int) 3380 */ 3381 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14; 3382 3383 /** 3384 * @hide Navigation repeat sound 4 3385 * <p> 3386 * To be played by the framework when a focus navigation is repeatedly triggered 3387 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3388 * This is currently only used on TV devices. 3389 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3390 * @see #playSoundEffect(int) 3391 */ 3392 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15; 3393 3394 /** 3395 * @hide Number of sound effects 3396 */ 3397 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3398 public static final int NUM_SOUND_EFFECTS = 16; 3399 3400 /** @hide */ 3401 @IntDef(prefix = { "FX_" }, value = { 3402 FX_KEY_CLICK, 3403 FX_FOCUS_NAVIGATION_UP, 3404 FX_FOCUS_NAVIGATION_DOWN, 3405 FX_FOCUS_NAVIGATION_LEFT, 3406 FX_FOCUS_NAVIGATION_RIGHT, 3407 FX_KEYPRESS_STANDARD, 3408 FX_KEYPRESS_SPACEBAR, 3409 FX_KEYPRESS_DELETE, 3410 FX_KEYPRESS_RETURN, 3411 FX_KEYPRESS_INVALID, 3412 FX_BACK 3413 }) 3414 @Retention(RetentionPolicy.SOURCE) 3415 public @interface SystemSoundEffect {} 3416 3417 /** 3418 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects 3419 */ 3420 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4; 3421 3422 /** 3423 * @hide 3424 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[ 3425 * @return The id of a navigation repeat sound effect or -1 if out of bounds 3426 */ getNthNavigationRepeatSoundEffect(int n)3427 public static int getNthNavigationRepeatSoundEffect(int n) { 3428 switch (n) { 3429 case 0: 3430 return FX_FOCUS_NAVIGATION_REPEAT_1; 3431 case 1: 3432 return FX_FOCUS_NAVIGATION_REPEAT_2; 3433 case 2: 3434 return FX_FOCUS_NAVIGATION_REPEAT_3; 3435 case 3: 3436 return FX_FOCUS_NAVIGATION_REPEAT_4; 3437 default: 3438 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n); 3439 return -1; 3440 } 3441 } 3442 3443 /** 3444 * @hide 3445 */ setNavigationRepeatSoundEffectsEnabled(boolean enabled)3446 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) { 3447 try { 3448 getService().setNavigationRepeatSoundEffectsEnabled(enabled); 3449 } catch (RemoteException e) { 3450 3451 } 3452 } 3453 3454 /** 3455 * @hide 3456 * @return true if the navigation repeat sound effects are enabled 3457 */ areNavigationRepeatSoundEffectsEnabled()3458 public boolean areNavigationRepeatSoundEffectsEnabled() { 3459 try { 3460 return getService().areNavigationRepeatSoundEffectsEnabled(); 3461 } catch (RemoteException e) { 3462 throw e.rethrowFromSystemServer(); 3463 } 3464 } 3465 3466 /** 3467 * @hide 3468 * @param enabled 3469 */ setHomeSoundEffectEnabled(boolean enabled)3470 public void setHomeSoundEffectEnabled(boolean enabled) { 3471 try { 3472 getService().setHomeSoundEffectEnabled(enabled); 3473 } catch (RemoteException e) { 3474 3475 } 3476 } 3477 3478 /** 3479 * @hide 3480 * @return true if the home sound effect is enabled 3481 */ isHomeSoundEffectEnabled()3482 public boolean isHomeSoundEffectEnabled() { 3483 try { 3484 return getService().isHomeSoundEffectEnabled(); 3485 } catch (RemoteException e) { 3486 throw e.rethrowFromSystemServer(); 3487 } 3488 } 3489 3490 /** 3491 * Plays a sound effect (Key clicks, lid open/close...) 3492 * @param effectType The type of sound effect. 3493 * NOTE: This version uses the UI settings to determine 3494 * whether sounds are heard or not. 3495 */ playSoundEffect(@ystemSoundEffect int effectType)3496 public void playSoundEffect(@SystemSoundEffect int effectType) { 3497 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3498 return; 3499 } 3500 3501 if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) { 3502 return; 3503 } 3504 3505 final IAudioService service = getService(); 3506 try { 3507 service.playSoundEffect(effectType); 3508 } catch (RemoteException e) { 3509 throw e.rethrowFromSystemServer(); 3510 } 3511 } 3512 3513 /** 3514 * Plays a sound effect (Key clicks, lid open/close...) 3515 * @param effectType The type of sound effect. 3516 * @param userId The current user to pull sound settings from 3517 * NOTE: This version uses the UI settings to determine 3518 * whether sounds are heard or not. 3519 * @hide 3520 */ playSoundEffect(@ystemSoundEffect int effectType, int userId)3521 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) { 3522 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3523 return; 3524 } 3525 3526 if (!querySoundEffectsEnabled(userId)) { 3527 return; 3528 } 3529 3530 final IAudioService service = getService(); 3531 try { 3532 service.playSoundEffect(effectType); 3533 } catch (RemoteException e) { 3534 throw e.rethrowFromSystemServer(); 3535 } 3536 } 3537 3538 /** 3539 * Plays a sound effect (Key clicks, lid open/close...) 3540 * @param effectType The type of sound effect. 3541 * @param volume Sound effect volume. 3542 * The volume value is a raw scalar so UI controls should be scaled logarithmically. 3543 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. 3544 * NOTE: This version is for applications that have their own 3545 * settings panel for enabling and controlling volume. 3546 */ playSoundEffect(@ystemSoundEffect int effectType, float volume)3547 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) { 3548 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3549 return; 3550 } 3551 3552 final IAudioService service = getService(); 3553 try { 3554 service.playSoundEffectVolume(effectType, volume); 3555 } catch (RemoteException e) { 3556 throw e.rethrowFromSystemServer(); 3557 } 3558 } 3559 3560 /** 3561 * Settings has an in memory cache, so this is fast. 3562 */ querySoundEffectsEnabled(int user)3563 private boolean querySoundEffectsEnabled(int user) { 3564 return Settings.System.getIntForUser(getContext().getContentResolver(), 3565 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0; 3566 } 3567 3568 /** 3569 * Load Sound effects. 3570 * This method must be called when sound effects are enabled. 3571 */ loadSoundEffects()3572 public void loadSoundEffects() { 3573 final IAudioService service = getService(); 3574 try { 3575 service.loadSoundEffects(); 3576 } catch (RemoteException e) { 3577 throw e.rethrowFromSystemServer(); 3578 } 3579 } 3580 3581 /** 3582 * Unload Sound effects. 3583 * This method can be called to free some memory when 3584 * sound effects are disabled. 3585 */ unloadSoundEffects()3586 public void unloadSoundEffects() { 3587 final IAudioService service = getService(); 3588 try { 3589 service.unloadSoundEffects(); 3590 } catch (RemoteException e) { 3591 throw e.rethrowFromSystemServer(); 3592 } 3593 } 3594 3595 /** 3596 * @hide 3597 */ audioFocusToString(int focus)3598 public static String audioFocusToString(int focus) { 3599 switch (focus) { 3600 case AUDIOFOCUS_NONE: 3601 return "AUDIOFOCUS_NONE"; 3602 case AUDIOFOCUS_GAIN: 3603 return "AUDIOFOCUS_GAIN"; 3604 case AUDIOFOCUS_GAIN_TRANSIENT: 3605 return "AUDIOFOCUS_GAIN_TRANSIENT"; 3606 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 3607 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"; 3608 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 3609 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE"; 3610 case AUDIOFOCUS_LOSS: 3611 return "AUDIOFOCUS_LOSS"; 3612 case AUDIOFOCUS_LOSS_TRANSIENT: 3613 return "AUDIOFOCUS_LOSS_TRANSIENT"; 3614 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK. 3615 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"; 3616 default: 3617 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")"; 3618 } 3619 } 3620 3621 /** 3622 * Used to indicate no audio focus has been gained or lost, or requested. 3623 */ 3624 public static final int AUDIOFOCUS_NONE = 0; 3625 3626 /** 3627 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 3628 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3629 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3630 */ 3631 public static final int AUDIOFOCUS_GAIN = 1; 3632 /** 3633 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 3634 * amount of time. Examples of temporary changes are the playback of driving directions, or an 3635 * event notification. 3636 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3637 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3638 */ 3639 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; 3640 /** 3641 * Used to indicate a temporary request of audio focus, anticipated to last a short 3642 * amount of time, and where it is acceptable for other audio applications to keep playing 3643 * after having lowered their output level (also referred to as "ducking"). 3644 * Examples of temporary changes are the playback of driving directions where playback of music 3645 * in the background is acceptable. 3646 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3647 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3648 */ 3649 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; 3650 /** 3651 * Used to indicate a temporary request of audio focus, anticipated to last a short 3652 * amount of time, during which no other applications, or system components, should play 3653 * anything. Examples of exclusive and transient audio focus requests are voice 3654 * memo recording and speech recognition, during which the system shouldn't play any 3655 * notifications, and media playback should have paused. 3656 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3657 */ 3658 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; 3659 /** 3660 * Used to indicate a loss of audio focus of unknown duration. 3661 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3662 */ 3663 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 3664 /** 3665 * Used to indicate a transient loss of audio focus. 3666 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3667 */ 3668 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; 3669 /** 3670 * Used to indicate a transient loss of audio focus where the loser of the audio focus can 3671 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 3672 * the new focus owner doesn't require others to be silent. 3673 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3674 */ 3675 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = 3676 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; 3677 3678 /** 3679 * Interface definition for a callback to be invoked when the audio focus of the system is 3680 * updated. 3681 */ 3682 public interface OnAudioFocusChangeListener { 3683 /** 3684 * Called on the listener to notify it the audio focus for this listener has been changed. 3685 * The focusChange value indicates whether the focus was gained, 3686 * whether the focus was lost, and whether that loss is transient, or whether the new focus 3687 * holder will hold it for an unknown amount of time. 3688 * When losing focus, listeners can use the focus change information to decide what 3689 * behavior to adopt when losing focus. A music player could for instance elect to lower 3690 * the volume of its music stream (duck) for transient focus losses, and pause otherwise. 3691 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN}, 3692 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 3693 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. 3694 */ onAudioFocusChange(int focusChange)3695 public void onAudioFocusChange(int focusChange); 3696 } 3697 3698 /** 3699 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback 3700 */ 3701 private static class FocusRequestInfo { 3702 @NonNull final AudioFocusRequest mRequest; 3703 @Nullable final Handler mHandler; FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)3704 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { 3705 mRequest = afr; 3706 mHandler = handler; 3707 } 3708 } 3709 3710 /** 3711 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, 3712 * to actual listener objects. 3713 */ 3714 @UnsupportedAppUsage 3715 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = 3716 new ConcurrentHashMap<String, FocusRequestInfo>(); 3717 findFocusRequestInfo(String id)3718 private FocusRequestInfo findFocusRequestInfo(String id) { 3719 return mAudioFocusIdListenerMap.get(id); 3720 } 3721 3722 /** 3723 * Handler for events (audio focus change, recording config change) coming from the 3724 * audio service. 3725 */ 3726 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate = 3727 new ServiceEventHandlerDelegate(null); 3728 3729 /** 3730 * Event types 3731 */ 3732 private final static int MSSG_FOCUS_CHANGE = 0; 3733 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1; 3734 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2; 3735 3736 /** 3737 * Helper class to handle the forwarding of audio service events to the appropriate listener 3738 */ 3739 private class ServiceEventHandlerDelegate { 3740 private final Handler mHandler; 3741 ServiceEventHandlerDelegate(Handler handler)3742 ServiceEventHandlerDelegate(Handler handler) { 3743 Looper looper; 3744 if (handler == null) { 3745 if ((looper = Looper.myLooper()) == null) { 3746 looper = Looper.getMainLooper(); 3747 } 3748 } else { 3749 looper = handler.getLooper(); 3750 } 3751 3752 if (looper != null) { 3753 // implement the event handler delegate to receive events from audio service 3754 mHandler = new Handler(looper) { 3755 @Override 3756 public void handleMessage(Message msg) { 3757 switch (msg.what) { 3758 case MSSG_FOCUS_CHANGE: { 3759 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); 3760 if (fri != null) { 3761 final OnAudioFocusChangeListener listener = 3762 fri.mRequest.getOnAudioFocusChangeListener(); 3763 if (listener != null) { 3764 Log.d(TAG, "dispatching onAudioFocusChange(" 3765 + msg.arg1 + ") to " + msg.obj); 3766 listener.onAudioFocusChange(msg.arg1); 3767 } 3768 } 3769 } break; 3770 case MSSG_RECORDING_CONFIG_CHANGE: { 3771 final RecordConfigChangeCallbackData cbData = 3772 (RecordConfigChangeCallbackData) msg.obj; 3773 if (cbData.mCb != null) { 3774 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs); 3775 } 3776 } break; 3777 case MSSG_PLAYBACK_CONFIG_CHANGE: { 3778 final PlaybackConfigChangeCallbackData cbData = 3779 (PlaybackConfigChangeCallbackData) msg.obj; 3780 if (cbData.mCb != null) { 3781 if (DEBUG) { 3782 Log.d(TAG, "dispatching onPlaybackConfigChanged()"); 3783 } 3784 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs); 3785 } 3786 } break; 3787 default: 3788 Log.e(TAG, "Unknown event " + msg.what); 3789 } 3790 } 3791 }; 3792 } else { 3793 mHandler = null; 3794 } 3795 } 3796 getHandler()3797 Handler getHandler() { 3798 return mHandler; 3799 } 3800 } 3801 3802 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { 3803 @Override 3804 public void dispatchAudioFocusChange(int focusChange, String id) { 3805 final FocusRequestInfo fri = findFocusRequestInfo(id); 3806 if (fri != null) { 3807 final OnAudioFocusChangeListener listener = 3808 fri.mRequest.getOnAudioFocusChangeListener(); 3809 if (listener != null) { 3810 final Handler h = (fri.mHandler == null) ? 3811 mServiceEventHandlerDelegate.getHandler() : fri.mHandler; 3812 final Message m = h.obtainMessage( 3813 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, 3814 id/*obj*/); 3815 h.sendMessage(m); 3816 } 3817 } 3818 } 3819 3820 @Override 3821 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) { 3822 synchronized (mFocusRequestsLock) { 3823 // TODO use generation counter as the key instead 3824 final BlockingFocusResultReceiver focusReceiver = 3825 mFocusRequestsAwaitingResult.remove(clientId); 3826 if (focusReceiver != null) { 3827 focusReceiver.notifyResult(requestResult); 3828 } else { 3829 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver"); 3830 } 3831 } 3832 } 3833 }; 3834 getIdForAudioFocusListener(OnAudioFocusChangeListener l)3835 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { 3836 if (l == null) { 3837 return new String(this.toString()); 3838 } else { 3839 return new String(this.toString() + l.toString()); 3840 } 3841 } 3842 3843 /** 3844 * @hide 3845 * Registers a listener to be called when audio focus changes and keeps track of the associated 3846 * focus request (including Handler to use for the listener). 3847 * @param afr the full request parameters 3848 */ registerAudioFocusRequest(@onNull AudioFocusRequest afr)3849 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { 3850 final Handler h = afr.getOnAudioFocusChangeListenerHandler(); 3851 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : 3852 new ServiceEventHandlerDelegate(h).getHandler()); 3853 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 3854 mAudioFocusIdListenerMap.put(key, fri); 3855 } 3856 3857 /** 3858 * @hide 3859 * Causes the specified listener to not be called anymore when focus is gained or lost. 3860 * @param l the listener to unregister. 3861 */ unregisterAudioFocusRequest(OnAudioFocusChangeListener l)3862 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { 3863 // remove locally 3864 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); 3865 } 3866 3867 3868 /** 3869 * A failed focus change request. 3870 */ 3871 public static final int AUDIOFOCUS_REQUEST_FAILED = 0; 3872 /** 3873 * A successful focus change request. 3874 */ 3875 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; 3876 /** 3877 * A focus change request whose granting is delayed: the request was successful, but the 3878 * requester will only be granted audio focus once the condition that prevented immediate 3879 * granting has ended. 3880 * See {@link #requestAudioFocus(AudioFocusRequest)} and 3881 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} 3882 */ 3883 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; 3884 3885 /** @hide */ 3886 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = { 3887 AUDIOFOCUS_REQUEST_FAILED, 3888 AUDIOFOCUS_REQUEST_GRANTED, 3889 AUDIOFOCUS_REQUEST_DELAYED } 3890 ) 3891 @Retention(RetentionPolicy.SOURCE) 3892 public @interface FocusRequestResult {} 3893 3894 /** 3895 * @hide 3896 * code returned when a synchronous focus request on the client-side is to be blocked 3897 * until the external audio focus policy decides on the response for the client 3898 */ 3899 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100; 3900 3901 /** 3902 * Timeout duration in ms when waiting on an external focus policy for the result for a 3903 * focus request 3904 */ 3905 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200; 3906 3907 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id"; 3908 3909 private final Object mFocusRequestsLock = new Object(); 3910 /** 3911 * Map of all receivers of focus request results, one per unresolved focus request. 3912 * Receivers are added before sending the request to the external focus policy, 3913 * and are removed either after receiving the result, or after the timeout. 3914 * This variable is lazily initialized. 3915 */ 3916 @GuardedBy("mFocusRequestsLock") 3917 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult; 3918 3919 3920 /** 3921 * Request audio focus. 3922 * Send a request to obtain the audio focus 3923 * @param l the listener to be notified of audio focus changes 3924 * @param streamType the main audio stream type affected by the focus request 3925 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 3926 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 3927 * for the playback of driving directions, or notifications sounds. 3928 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 3929 * the previous focus owner to keep playing if it ducks its audio output. 3930 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 3931 * that benefits from the system not playing disruptive sounds like notifications, for 3932 * usecases such as voice memo recording, or speech recognition. 3933 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 3934 * as the playback of a song or a video. 3935 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 3936 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)} 3937 */ requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)3938 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { 3939 PlayerBase.deprecateStreamTypeForPlayback(streamType, 3940 "AudioManager", "requestAudioFocus()"); 3941 int status = AUDIOFOCUS_REQUEST_FAILED; 3942 3943 try { 3944 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or 3945 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the 3946 // AUDIOFOCUS_FLAG_DELAY_OK flag 3947 status = requestAudioFocus(l, 3948 new AudioAttributes.Builder() 3949 .setInternalLegacyStreamType(streamType).build(), 3950 durationHint, 3951 0 /* flags, legacy behavior */); 3952 } catch (IllegalArgumentException e) { 3953 Log.e(TAG, "Audio focus request denied due to ", e); 3954 } 3955 3956 return status; 3957 } 3958 3959 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks 3960 /** 3961 * @hide 3962 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be 3963 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when 3964 * the system is in a state where focus cannot change, but be granted focus later when 3965 * this condition ends. 3966 */ 3967 @SystemApi 3968 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0; 3969 /** 3970 * @hide 3971 * Use this flag when requesting audio focus to indicate that the requester 3972 * will pause its media playback (if applicable) when losing audio focus with 3973 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking. 3974 * <br>On some platforms, the ducking may be handled without the application being aware of it 3975 * (i.e. it will not transiently lose focus). For applications that for instance play spoken 3976 * content, such as audio book or podcast players, ducking may never be acceptable, and will 3977 * thus always pause. This flag enables them to be declared as such whenever they request focus. 3978 */ 3979 @SystemApi 3980 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1; 3981 /** 3982 * @hide 3983 * Use this flag to lock audio focus so granting is temporarily disabled. 3984 * <br>This flag can only be used by owners of a registered 3985 * {@link android.media.audiopolicy.AudioPolicy} in 3986 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)} 3987 */ 3988 @SystemApi 3989 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2; 3990 3991 /** 3992 * @hide 3993 * flag set on test API calls, 3994 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}, 3995 * note that it isn't used in conjunction with other flags, it is passed as the single 3996 * value for flags */ 3997 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3; 3998 /** @hide */ 3999 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK 4000 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS; 4001 /** @hide */ 4002 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK 4003 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK; 4004 4005 /** 4006 * Request audio focus. 4007 * See the {@link AudioFocusRequest} for information about the options available to configure 4008 * your request, and notification of focus gain and loss. 4009 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is 4010 * requested. 4011 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4012 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4013 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus 4014 * is requested without building the {@link AudioFocusRequest} with 4015 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to 4016 * {@code true}. 4017 * @throws NullPointerException if passed a null argument 4018 */ requestAudioFocus(@onNull AudioFocusRequest focusRequest)4019 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { 4020 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); 4021 } 4022 4023 /** 4024 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4025 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus 4026 * with {@link #requestAudioFocus(AudioFocusRequest)}. 4027 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4028 * @throws IllegalArgumentException if passed a null argument 4029 */ abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4030 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) { 4031 if (focusRequest == null) { 4032 throw new IllegalArgumentException("Illegal null AudioFocusRequest"); 4033 } 4034 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(), 4035 focusRequest.getAudioAttributes()); 4036 } 4037 4038 /** 4039 * @hide 4040 * Request audio focus. 4041 * Send a request to obtain the audio focus. This method differs from 4042 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express 4043 * that the requester accepts delayed grants of audio focus. 4044 * @param l the listener to be notified of audio focus changes. It is not allowed to be null 4045 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}. 4046 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4047 * requesting audio focus. 4048 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4049 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 4050 * for the playback of driving directions, or notifications sounds. 4051 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4052 * the previous focus owner to keep playing if it ducks its audio output. 4053 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4054 * that benefits from the system not playing disruptive sounds like notifications, for 4055 * usecases such as voice memo recording, or speech recognition. 4056 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4057 * as the playback of a song or a video. 4058 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4059 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}. 4060 * <br>Use 0 when not using any flags for the request, which behaves like 4061 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4062 * focus is granted immediately, or the grant request fails because the system is in a 4063 * state where focus cannot change (e.g. a phone call). 4064 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4065 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4066 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested 4067 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag. 4068 * @throws IllegalArgumentException 4069 */ 4070 @SystemApi 4071 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)4072 public int requestAudioFocus(OnAudioFocusChangeListener l, 4073 @NonNull AudioAttributes requestAttributes, 4074 int durationHint, 4075 int flags) throws IllegalArgumentException { 4076 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) { 4077 throw new IllegalArgumentException("Invalid flags 0x" 4078 + Integer.toHexString(flags).toUpperCase()); 4079 } 4080 return requestAudioFocus(l, requestAttributes, durationHint, 4081 flags & AUDIOFOCUS_FLAGS_APPS, 4082 null /* no AudioPolicy*/); 4083 } 4084 4085 /** 4086 * @hide 4087 * Request or lock audio focus. 4088 * This method is to be used by system components that have registered an 4089 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4090 * so focus granting is temporarily disabled. 4091 * @param l see the description of the same parameter in 4092 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4093 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4094 * requesting audio focus. 4095 * @param durationHint see the description of the same parameter in 4096 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4097 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4098 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}. 4099 * <br>Use 0 when not using any flags for the request, which behaves like 4100 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4101 * focus is granted immediately, or the grant request fails because the system is in a 4102 * state where focus cannot change (e.g. a phone call). 4103 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4104 * focus, or null. 4105 * @return see the description of the same return value in 4106 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4107 * @throws IllegalArgumentException 4108 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} 4109 */ 4110 @SystemApi 4111 @RequiresPermission(anyOf= { 4112 android.Manifest.permission.MODIFY_PHONE_STATE, 4113 android.Manifest.permission.MODIFY_AUDIO_ROUTING 4114 }) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)4115 public int requestAudioFocus(OnAudioFocusChangeListener l, 4116 @NonNull AudioAttributes requestAttributes, 4117 int durationHint, 4118 int flags, 4119 AudioPolicy ap) throws IllegalArgumentException { 4120 // parameter checking 4121 if (requestAttributes == null) { 4122 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 4123 } 4124 if (!AudioFocusRequest.isValidFocusGain(durationHint)) { 4125 throw new IllegalArgumentException("Invalid duration hint"); 4126 } 4127 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) { 4128 throw new IllegalArgumentException("Illegal flags 0x" 4129 + Integer.toHexString(flags).toUpperCase()); 4130 } 4131 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) { 4132 throw new IllegalArgumentException( 4133 "Illegal null focus listener when flagged as accepting delayed focus grant"); 4134 } 4135 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4136 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { 4137 throw new IllegalArgumentException( 4138 "Illegal null focus listener when flagged as pausing instead of ducking"); 4139 } 4140 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { 4141 throw new IllegalArgumentException( 4142 "Illegal null audio policy when locking audio focus"); 4143 } 4144 4145 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint) 4146 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */) 4147 .setAudioAttributes(requestAttributes) 4148 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) 4149 == AUDIOFOCUS_FLAG_DELAY_OK) 4150 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4151 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4152 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) 4153 .build(); 4154 return requestAudioFocus(afr, ap); 4155 } 4156 4157 /** 4158 * @hide 4159 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID. 4160 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4161 * @param afr the parameters of the request 4162 * @param clientFakeId the identifier of the AudioManager the client would be requesting from 4163 * @param clientFakeUid the UID of the client, here an arbitrary int, 4164 * doesn't have to be a real UID 4165 * @param clientTargetSdk the target SDK used by the client 4166 * @return return code indicating status of the request 4167 */ 4168 @TestApi 4169 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4170 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr, 4171 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) { 4172 Objects.requireNonNull(afr); 4173 Objects.requireNonNull(clientFakeId); 4174 try { 4175 return getService().requestAudioFocusForTest(afr.getAudioAttributes(), 4176 afr.getFocusGain(), 4177 mICallBack, 4178 mAudioFocusDispatcher, 4179 clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk); 4180 } catch (RemoteException e) { 4181 throw e.rethrowFromSystemServer(); 4182 } 4183 } 4184 4185 /** 4186 * @hide 4187 * Test API to abandon audio focus for an arbitrary client. 4188 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4189 * @param afr the parameters used for the request 4190 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client 4191 * would be requesting 4192 * @return return code indicating status of the request 4193 */ 4194 @TestApi 4195 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4196 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr, 4197 @NonNull String clientFakeId) { 4198 Objects.requireNonNull(afr); 4199 Objects.requireNonNull(clientFakeId); 4200 try { 4201 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher, 4202 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient"); 4203 } catch (RemoteException e) { 4204 throw e.rethrowFromSystemServer(); 4205 } 4206 } 4207 4208 /** 4209 * @hide 4210 * Return the duration of the fade out applied when a player of the given AudioAttributes 4211 * is losing audio focus 4212 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS} 4213 * @return a duration in ms, 0 indicates no fade out is applied 4214 */ 4215 @TestApi 4216 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4217 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa) 4218 { 4219 Objects.requireNonNull(aa); 4220 try { 4221 return getService().getFadeOutDurationOnFocusLossMillis(aa); 4222 } catch (RemoteException e) { 4223 throw e.rethrowFromSystemServer(); 4224 } 4225 } 4226 4227 /** 4228 * @hide 4229 * Request or lock audio focus. 4230 * This method is to be used by system components that have registered an 4231 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4232 * so focus granting is temporarily disabled. 4233 * @param afr see the description of the same parameter in 4234 * {@link #requestAudioFocus(AudioFocusRequest)} 4235 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4236 * focus, or null. 4237 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4238 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4239 * @throws NullPointerException if the AudioFocusRequest is null 4240 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy 4241 */ 4242 @SystemApi 4243 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)4244 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { 4245 if (afr == null) { 4246 throw new NullPointerException("Illegal null AudioFocusRequest"); 4247 } 4248 // this can only be checked now, not during the creation of the AudioFocusRequest instance 4249 if (afr.locksFocus() && ap == null) { 4250 throw new IllegalArgumentException( 4251 "Illegal null audio policy when locking audio focus"); 4252 } 4253 registerAudioFocusRequest(afr); 4254 final IAudioService service = getService(); 4255 final int status; 4256 int sdk; 4257 try { 4258 sdk = getContext().getApplicationInfo().targetSdkVersion; 4259 } catch (NullPointerException e) { 4260 // some tests don't have a Context 4261 sdk = Build.VERSION.SDK_INT; 4262 } 4263 4264 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 4265 final BlockingFocusResultReceiver focusReceiver; 4266 synchronized (mFocusRequestsLock) { 4267 try { 4268 // TODO status contains result and generation counter for ext policy 4269 status = service.requestAudioFocus(afr.getAudioAttributes(), 4270 afr.getFocusGain(), mICallBack, 4271 mAudioFocusDispatcher, 4272 clientId, 4273 getContext().getOpPackageName() /* package name */, afr.getFlags(), 4274 ap != null ? ap.cb() : null, 4275 sdk); 4276 } catch (RemoteException e) { 4277 throw e.rethrowFromSystemServer(); 4278 } 4279 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 4280 // default path with no external focus policy 4281 return status; 4282 } 4283 if (mFocusRequestsAwaitingResult == null) { 4284 mFocusRequestsAwaitingResult = 4285 new HashMap<String, BlockingFocusResultReceiver>(1); 4286 } 4287 focusReceiver = new BlockingFocusResultReceiver(clientId); 4288 mFocusRequestsAwaitingResult.put(clientId, focusReceiver); 4289 } 4290 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS); 4291 if (DEBUG && !focusReceiver.receivedResult()) { 4292 Log.e(TAG, "requestAudio response from ext policy timed out, denying request"); 4293 } 4294 synchronized (mFocusRequestsLock) { 4295 mFocusRequestsAwaitingResult.remove(clientId); 4296 } 4297 return focusReceiver.requestResult(); 4298 } 4299 4300 // helper class that abstracts out the handling of spurious wakeups in Object.wait() 4301 private static final class SafeWaitObject { 4302 private boolean mQuit = false; 4303 safeNotify()4304 public void safeNotify() { 4305 synchronized (this) { 4306 mQuit = true; 4307 this.notify(); 4308 } 4309 } 4310 safeWait(long millis)4311 public void safeWait(long millis) throws InterruptedException { 4312 final long timeOutTime = java.lang.System.currentTimeMillis() + millis; 4313 synchronized (this) { 4314 while (!mQuit) { 4315 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis(); 4316 if (timeToWait < 0) { break; } 4317 this.wait(timeToWait); 4318 } 4319 } 4320 } 4321 } 4322 4323 private static final class BlockingFocusResultReceiver { 4324 private final SafeWaitObject mLock = new SafeWaitObject(); 4325 @GuardedBy("mLock") 4326 private boolean mResultReceived = false; 4327 // request denied by default (e.g. timeout) 4328 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4329 private final String mFocusClientId; 4330 BlockingFocusResultReceiver(String clientId)4331 BlockingFocusResultReceiver(String clientId) { 4332 mFocusClientId = clientId; 4333 } 4334 receivedResult()4335 boolean receivedResult() { return mResultReceived; } requestResult()4336 int requestResult() { return mFocusRequestResult; } 4337 notifyResult(int requestResult)4338 void notifyResult(int requestResult) { 4339 synchronized (mLock) { 4340 mResultReceived = true; 4341 mFocusRequestResult = requestResult; 4342 mLock.safeNotify(); 4343 } 4344 } 4345 waitForResult(long timeOutMs)4346 public void waitForResult(long timeOutMs) { 4347 synchronized (mLock) { 4348 if (mResultReceived) { 4349 // the result was received before waiting 4350 return; 4351 } 4352 try { 4353 mLock.safeWait(timeOutMs); 4354 } catch (InterruptedException e) { } 4355 } 4356 } 4357 } 4358 4359 /** 4360 * @hide 4361 * Used internally by telephony package to request audio focus. Will cause the focus request 4362 * to be associated with the "voice communication" identifier only used in AudioService 4363 * to identify this use case. 4364 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 4365 * the establishment of the call 4366 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 4367 * media applications resume after a call 4368 */ 4369 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) requestAudioFocusForCall(int streamType, int durationHint)4370 public void requestAudioFocusForCall(int streamType, int durationHint) { 4371 final IAudioService service = getService(); 4372 try { 4373 service.requestAudioFocus(new AudioAttributes.Builder() 4374 .setInternalLegacyStreamType(streamType).build(), 4375 durationHint, mICallBack, null, 4376 AudioSystem.IN_VOICE_COMM_FOCUS_ID, 4377 getContext().getOpPackageName(), 4378 AUDIOFOCUS_FLAG_LOCK, 4379 null /* policy token */, 0 /* sdk n/a here*/); 4380 } catch (RemoteException e) { 4381 throw e.rethrowFromSystemServer(); 4382 } 4383 } 4384 4385 /** 4386 * @hide 4387 * Return the volume ramping time for a sound to be played after the given focus request, 4388 * and to play a sound of the given attributes 4389 * @param focusGain 4390 * @param attr 4391 * @return 4392 */ getFocusRampTimeMs(int focusGain, AudioAttributes attr)4393 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 4394 final IAudioService service = getService(); 4395 try { 4396 return service.getFocusRampTimeMs(focusGain, attr); 4397 } catch (RemoteException e) { 4398 throw e.rethrowFromSystemServer(); 4399 } 4400 } 4401 4402 /** 4403 * @hide 4404 * Set the result to the audio focus request received through 4405 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 4406 * @param afi the information about the focus requester 4407 * @param requestResult the result to the focus request to be passed to the requester 4408 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 4409 */ 4410 @SystemApi 4411 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)4412 public void setFocusRequestResult(@NonNull AudioFocusInfo afi, 4413 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) { 4414 if (afi == null) { 4415 throw new IllegalArgumentException("Illegal null AudioFocusInfo"); 4416 } 4417 if (ap == null) { 4418 throw new IllegalArgumentException("Illegal null AudioPolicy"); 4419 } 4420 final IAudioService service = getService(); 4421 try { 4422 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); 4423 } catch (RemoteException e) { 4424 throw e.rethrowFromSystemServer(); 4425 } 4426 } 4427 4428 /** 4429 * @hide 4430 * Notifies an application with a focus listener of gain or loss of audio focus. 4431 * This method can only be used by owners of an {@link AudioPolicy} configured with 4432 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 4433 * @param afi the recipient of the focus change, that has previously requested audio focus, and 4434 * that was received by the {@code AudioPolicy} through 4435 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 4436 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 4437 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 4438 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 4439 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 4440 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 4441 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 4442 * <br>For the focus gain, the change type should be the same as the app requested. 4443 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 4444 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or 4445 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or 4446 * if there was an error sending the request. 4447 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. 4448 */ 4449 @SystemApi 4450 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)4451 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, 4452 @NonNull AudioPolicy ap) { 4453 if (afi == null) { 4454 throw new NullPointerException("Illegal null AudioFocusInfo"); 4455 } 4456 if (ap == null) { 4457 throw new NullPointerException("Illegal null AudioPolicy"); 4458 } 4459 final IAudioService service = getService(); 4460 try { 4461 return service.dispatchFocusChange(afi, focusChange, ap.cb()); 4462 } catch (RemoteException e) { 4463 throw e.rethrowFromSystemServer(); 4464 } 4465 } 4466 4467 /** 4468 * @hide 4469 * Used internally by telephony package to abandon audio focus, typically after a call or 4470 * when ringing ends and the call is rejected or not answered. 4471 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 4472 */ 4473 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) abandonAudioFocusForCall()4474 public void abandonAudioFocusForCall() { 4475 final IAudioService service = getService(); 4476 try { 4477 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, 4478 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); 4479 } catch (RemoteException e) { 4480 throw e.rethrowFromSystemServer(); 4481 } 4482 } 4483 4484 /** 4485 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4486 * @param l the listener with which focus was requested. 4487 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4488 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 4489 */ abandonAudioFocus(OnAudioFocusChangeListener l)4490 public int abandonAudioFocus(OnAudioFocusChangeListener l) { 4491 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/); 4492 } 4493 4494 /** 4495 * @hide 4496 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4497 * @param l the listener with which focus was requested. 4498 * @param aa the {@link AudioAttributes} with which audio focus was requested 4499 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4500 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 4501 */ 4502 @SystemApi 4503 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would 4504 // have been done by a matching requestAudioFocus abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)4505 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { 4506 int status = AUDIOFOCUS_REQUEST_FAILED; 4507 unregisterAudioFocusRequest(l); 4508 final IAudioService service = getService(); 4509 try { 4510 status = service.abandonAudioFocus(mAudioFocusDispatcher, 4511 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); 4512 } catch (RemoteException e) { 4513 throw e.rethrowFromSystemServer(); 4514 } 4515 return status; 4516 } 4517 4518 //==================================================================== 4519 // Remote Control 4520 /** 4521 * Register a component to be the sole receiver of MEDIA_BUTTON intents. 4522 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 4523 * that will receive the media button intent. This broadcast receiver must be declared 4524 * in the application manifest. The package of the component must match that of 4525 * the context you're registering from. 4526 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 4527 */ 4528 @Deprecated registerMediaButtonEventReceiver(ComponentName eventReceiver)4529 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 4530 if (eventReceiver == null) { 4531 return; 4532 } 4533 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) { 4534 Log.e(TAG, "registerMediaButtonEventReceiver() error: " + 4535 "receiver and context package names don't match"); 4536 return; 4537 } 4538 // construct a PendingIntent for the media button and register it 4539 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4540 // the associated intent will be handled by the component being registered 4541 mediaButtonIntent.setComponent(eventReceiver); 4542 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 4543 0/*requestCode, ignored*/, mediaButtonIntent, 4544 PendingIntent.FLAG_IMMUTABLE); 4545 registerMediaButtonIntent(pi, eventReceiver); 4546 } 4547 4548 /** 4549 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like 4550 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows 4551 * the buttons to go to any PendingIntent. Note that you should only use this form if 4552 * you know you will continue running for the full time until unregistering the 4553 * PendingIntent. 4554 * @param eventReceiver target that will receive media button intents. The PendingIntent 4555 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action 4556 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the 4557 * media button that was pressed. 4558 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 4559 */ 4560 @Deprecated registerMediaButtonEventReceiver(PendingIntent eventReceiver)4561 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { 4562 if (eventReceiver == null) { 4563 return; 4564 } 4565 registerMediaButtonIntent(eventReceiver, null); 4566 } 4567 4568 /** 4569 * @hide 4570 * no-op if (pi == null) or (eventReceiver == null) 4571 */ registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)4572 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) { 4573 if (pi == null) { 4574 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter"); 4575 return; 4576 } 4577 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 4578 helper.addMediaButtonListener(pi, eventReceiver, getContext()); 4579 } 4580 4581 /** 4582 * Unregister the receiver of MEDIA_BUTTON intents. 4583 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 4584 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. 4585 * @deprecated Use {@link MediaSession} instead. 4586 */ 4587 @Deprecated unregisterMediaButtonEventReceiver(ComponentName eventReceiver)4588 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 4589 if (eventReceiver == null) { 4590 return; 4591 } 4592 // construct a PendingIntent for the media button and unregister it 4593 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4594 // the associated intent will be handled by the component being registered 4595 mediaButtonIntent.setComponent(eventReceiver); 4596 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 4597 0/*requestCode, ignored*/, mediaButtonIntent, 4598 PendingIntent.FLAG_IMMUTABLE); 4599 unregisterMediaButtonIntent(pi); 4600 } 4601 4602 /** 4603 * Unregister the receiver of MEDIA_BUTTON intents. 4604 * @param eventReceiver same PendingIntent that was registed with 4605 * {@link #registerMediaButtonEventReceiver(PendingIntent)}. 4606 * @deprecated Use {@link MediaSession} instead. 4607 */ 4608 @Deprecated unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)4609 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { 4610 if (eventReceiver == null) { 4611 return; 4612 } 4613 unregisterMediaButtonIntent(eventReceiver); 4614 } 4615 4616 /** 4617 * @hide 4618 */ unregisterMediaButtonIntent(PendingIntent pi)4619 public void unregisterMediaButtonIntent(PendingIntent pi) { 4620 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 4621 helper.removeMediaButtonListener(pi); 4622 } 4623 4624 /** 4625 * Registers the remote control client for providing information to display on the remote 4626 * controls. 4627 * @param rcClient The remote control client from which remote controls will receive 4628 * information to display. 4629 * @see RemoteControlClient 4630 * @deprecated Use {@link MediaSession} instead. 4631 */ 4632 @Deprecated registerRemoteControlClient(RemoteControlClient rcClient)4633 public void registerRemoteControlClient(RemoteControlClient rcClient) { 4634 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 4635 return; 4636 } 4637 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 4638 } 4639 4640 /** 4641 * Unregisters the remote control client that was providing information to display on the 4642 * remote controls. 4643 * @param rcClient The remote control client to unregister. 4644 * @see #registerRemoteControlClient(RemoteControlClient) 4645 * @deprecated Use {@link MediaSession} instead. 4646 */ 4647 @Deprecated unregisterRemoteControlClient(RemoteControlClient rcClient)4648 public void unregisterRemoteControlClient(RemoteControlClient rcClient) { 4649 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 4650 return; 4651 } 4652 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 4653 } 4654 4655 /** 4656 * Registers a {@link RemoteController} instance for it to receive media 4657 * metadata updates and playback state information from applications using 4658 * {@link RemoteControlClient}, and control their playback. 4659 * <p> 4660 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be 4661 * one of the enabled notification listeners (see 4662 * {@link android.service.notification.NotificationListenerService}). 4663 * 4664 * @param rctlr the object to register. 4665 * @return true if the {@link RemoteController} was successfully registered, 4666 * false if an error occurred, due to an internal system error, or 4667 * insufficient permissions. 4668 * @deprecated Use 4669 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)} 4670 * and {@link MediaController} instead. 4671 */ 4672 @Deprecated registerRemoteController(RemoteController rctlr)4673 public boolean registerRemoteController(RemoteController rctlr) { 4674 if (rctlr == null) { 4675 return false; 4676 } 4677 rctlr.startListeningToSessions(); 4678 return true; 4679 } 4680 4681 /** 4682 * Unregisters a {@link RemoteController}, causing it to no longer receive 4683 * media metadata and playback state information, and no longer be capable 4684 * of controlling playback. 4685 * 4686 * @param rctlr the object to unregister. 4687 * @deprecated Use 4688 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)} 4689 * instead. 4690 */ 4691 @Deprecated unregisterRemoteController(RemoteController rctlr)4692 public void unregisterRemoteController(RemoteController rctlr) { 4693 if (rctlr == null) { 4694 return; 4695 } 4696 rctlr.stopListeningToSessions(); 4697 } 4698 4699 4700 //==================================================================== 4701 // Audio policy 4702 /** 4703 * @hide 4704 * Register the given {@link AudioPolicy}. 4705 * This call is synchronous and blocks until the registration process successfully completed 4706 * or failed to complete. 4707 * @param policy the non-null {@link AudioPolicy} to register. 4708 * @return {@link #ERROR} if there was an error communicating with the registration service 4709 * or if the user doesn't have the required 4710 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission, 4711 * {@link #SUCCESS} otherwise. 4712 */ 4713 @SystemApi 4714 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) registerAudioPolicy(@onNull AudioPolicy policy)4715 public int registerAudioPolicy(@NonNull AudioPolicy policy) { 4716 return registerAudioPolicyStatic(policy); 4717 } 4718 registerAudioPolicyStatic(@onNull AudioPolicy policy)4719 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) { 4720 if (policy == null) { 4721 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 4722 } 4723 final IAudioService service = getService(); 4724 try { 4725 MediaProjection projection = policy.getMediaProjection(); 4726 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), 4727 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(), 4728 policy.isVolumeController(), 4729 projection == null ? null : projection.getProjection()); 4730 if (regId == null) { 4731 return ERROR; 4732 } else { 4733 policy.setRegistration(regId); 4734 } 4735 // successful registration 4736 } catch (RemoteException e) { 4737 throw e.rethrowFromSystemServer(); 4738 } 4739 return SUCCESS; 4740 } 4741 4742 /** 4743 * @hide 4744 * Unregisters an {@link AudioPolicy} asynchronously. 4745 * @param policy the non-null {@link AudioPolicy} to unregister. 4746 */ 4747 @SystemApi 4748 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicyAsync(@onNull AudioPolicy policy)4749 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { 4750 unregisterAudioPolicyAsyncStatic(policy); 4751 } 4752 unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)4753 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) { 4754 if (policy == null) { 4755 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 4756 } 4757 final IAudioService service = getService(); 4758 try { 4759 service.unregisterAudioPolicyAsync(policy.cb()); 4760 policy.reset(); 4761 } catch (RemoteException e) { 4762 throw e.rethrowFromSystemServer(); 4763 } 4764 } 4765 4766 /** 4767 * @hide 4768 * Unregisters an {@link AudioPolicy} synchronously. 4769 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects 4770 * associated with mixes of this policy. 4771 * @param policy the non-null {@link AudioPolicy} to unregister. 4772 */ 4773 @SystemApi 4774 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicy(@onNull AudioPolicy policy)4775 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { 4776 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); 4777 final IAudioService service = getService(); 4778 try { 4779 policy.invalidateCaptorsAndInjectors(); 4780 service.unregisterAudioPolicy(policy.cb()); 4781 policy.reset(); 4782 } catch (RemoteException e) { 4783 throw e.rethrowFromSystemServer(); 4784 } 4785 } 4786 4787 /** 4788 * @hide 4789 * @return true if an AudioPolicy was previously registered 4790 */ 4791 @TestApi hasRegisteredDynamicPolicy()4792 public boolean hasRegisteredDynamicPolicy() { 4793 final IAudioService service = getService(); 4794 try { 4795 return service.hasRegisteredDynamicPolicy(); 4796 } catch (RemoteException e) { 4797 throw e.rethrowFromSystemServer(); 4798 } 4799 } 4800 4801 //==================================================================== 4802 // Notification of playback activity & playback configuration 4803 /** 4804 * Interface for receiving update notifications about the playback activity on the system. 4805 * Extend this abstract class and register it with 4806 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)} 4807 * to be notified. 4808 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current 4809 * configuration. 4810 * @see AudioPlaybackConfiguration 4811 */ 4812 public static abstract class AudioPlaybackCallback { 4813 /** 4814 * Called whenever the playback activity and configuration has changed. 4815 * @param configs list containing the results of 4816 * {@link AudioManager#getActivePlaybackConfigurations()}. 4817 */ onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)4818 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {} 4819 } 4820 4821 private static class AudioPlaybackCallbackInfo { 4822 final AudioPlaybackCallback mCb; 4823 final Handler mHandler; AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)4824 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) { 4825 mCb = cb; 4826 mHandler = handler; 4827 } 4828 } 4829 4830 private final static class PlaybackConfigChangeCallbackData { 4831 final AudioPlaybackCallback mCb; 4832 final List<AudioPlaybackConfiguration> mConfigs; 4833 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)4834 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, 4835 List<AudioPlaybackConfiguration> configs) { 4836 mCb = cb; 4837 mConfigs = configs; 4838 } 4839 } 4840 4841 /** 4842 * Register a callback to be notified of audio playback changes through 4843 * {@link AudioPlaybackCallback} 4844 * @param cb non-null callback to register 4845 * @param handler the {@link Handler} object for the thread on which to execute 4846 * the callback. If <code>null</code>, the {@link Handler} associated with the main 4847 * {@link Looper} will be used. 4848 */ registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)4849 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb, 4850 @Nullable Handler handler) 4851 { 4852 if (cb == null) { 4853 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 4854 } 4855 4856 synchronized(mPlaybackCallbackLock) { 4857 // lazy initialization of the list of playback callbacks 4858 if (mPlaybackCallbackList == null) { 4859 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>(); 4860 } 4861 final int oldCbCount = mPlaybackCallbackList.size(); 4862 if (!hasPlaybackCallback_sync(cb)) { 4863 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb, 4864 new ServiceEventHandlerDelegate(handler).getHandler())); 4865 final int newCbCount = mPlaybackCallbackList.size(); 4866 if ((oldCbCount == 0) && (newCbCount > 0)) { 4867 // register binder for callbacks 4868 try { 4869 getService().registerPlaybackCallback(mPlayCb); 4870 } catch (RemoteException e) { 4871 throw e.rethrowFromSystemServer(); 4872 } 4873 } 4874 } else { 4875 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously" 4876 + "registered callback"); 4877 } 4878 } 4879 } 4880 4881 /** 4882 * Unregister an audio playback callback previously registered with 4883 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 4884 * @param cb non-null callback to unregister 4885 */ unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)4886 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) { 4887 if (cb == null) { 4888 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 4889 } 4890 synchronized(mPlaybackCallbackLock) { 4891 if (mPlaybackCallbackList == null) { 4892 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 4893 + " that was never registered"); 4894 return; 4895 } 4896 final int oldCbCount = mPlaybackCallbackList.size(); 4897 if (removePlaybackCallback_sync(cb)) { 4898 final int newCbCount = mPlaybackCallbackList.size(); 4899 if ((oldCbCount > 0) && (newCbCount == 0)) { 4900 // unregister binder for callbacks 4901 try { 4902 getService().unregisterPlaybackCallback(mPlayCb); 4903 } catch (RemoteException e) { 4904 throw e.rethrowFromSystemServer(); 4905 } 4906 } 4907 } else { 4908 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 4909 + " already unregistered or never registered"); 4910 } 4911 } 4912 } 4913 4914 /** 4915 * Returns the current active audio playback configurations of the device 4916 * @return a non-null list of playback configurations. An empty list indicates there is no 4917 * playback active when queried. 4918 * @see AudioPlaybackConfiguration 4919 */ getActivePlaybackConfigurations()4920 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { 4921 final IAudioService service = getService(); 4922 try { 4923 return service.getActivePlaybackConfigurations(); 4924 } catch (RemoteException e) { 4925 throw e.rethrowFromSystemServer(); 4926 } 4927 } 4928 4929 /** 4930 * All operations on this list are sync'd on mPlaybackCallbackLock. 4931 * List is lazy-initialized in 4932 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 4933 * List can be null. 4934 */ 4935 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList; 4936 private final Object mPlaybackCallbackLock = new Object(); 4937 4938 /** 4939 * Must be called synchronized on mPlaybackCallbackLock 4940 */ hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4941 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 4942 if (mPlaybackCallbackList != null) { 4943 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4944 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 4945 return true; 4946 } 4947 } 4948 } 4949 return false; 4950 } 4951 4952 /** 4953 * Must be called synchronized on mPlaybackCallbackLock 4954 */ removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4955 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 4956 if (mPlaybackCallbackList != null) { 4957 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4958 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 4959 mPlaybackCallbackList.remove(i); 4960 return true; 4961 } 4962 } 4963 } 4964 return false; 4965 } 4966 4967 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { 4968 @Override 4969 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, 4970 boolean flush) { 4971 if (flush) { 4972 Binder.flushPendingCommands(); 4973 } 4974 synchronized(mPlaybackCallbackLock) { 4975 if (mPlaybackCallbackList != null) { 4976 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4977 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i); 4978 if (arci.mHandler != null) { 4979 final Message m = arci.mHandler.obtainMessage( 4980 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/, 4981 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 4982 arci.mHandler.sendMessage(m); 4983 } 4984 } 4985 } 4986 } 4987 } 4988 4989 }; 4990 4991 //==================================================================== 4992 // Notification of recording activity & recording configuration 4993 /** 4994 * Interface for receiving update notifications about the recording configuration. Extend 4995 * this abstract class and register it with 4996 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)} 4997 * to be notified. 4998 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current 4999 * configuration. 5000 * @see AudioRecordingConfiguration 5001 */ 5002 public static abstract class AudioRecordingCallback { 5003 /** 5004 * Called whenever the device recording configuration has changed. 5005 * @param configs list containing the results of 5006 * {@link AudioManager#getActiveRecordingConfigurations()}. 5007 */ onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)5008 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {} 5009 } 5010 5011 private static class AudioRecordingCallbackInfo { 5012 final AudioRecordingCallback mCb; 5013 final Handler mHandler; AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5014 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) { 5015 mCb = cb; 5016 mHandler = handler; 5017 } 5018 } 5019 5020 private final static class RecordConfigChangeCallbackData { 5021 final AudioRecordingCallback mCb; 5022 final List<AudioRecordingConfiguration> mConfigs; 5023 RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5024 RecordConfigChangeCallbackData(AudioRecordingCallback cb, 5025 List<AudioRecordingConfiguration> configs) { 5026 mCb = cb; 5027 mConfigs = configs; 5028 } 5029 } 5030 5031 /** 5032 * Register a callback to be notified of audio recording changes through 5033 * {@link AudioRecordingCallback} 5034 * @param cb non-null callback to register 5035 * @param handler the {@link Handler} object for the thread on which to execute 5036 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5037 * {@link Looper} will be used. 5038 */ registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5039 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, 5040 @Nullable Handler handler) 5041 { 5042 if (cb == null) { 5043 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5044 } 5045 5046 synchronized(mRecordCallbackLock) { 5047 // lazy initialization of the list of recording callbacks 5048 if (mRecordCallbackList == null) { 5049 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>(); 5050 } 5051 final int oldCbCount = mRecordCallbackList.size(); 5052 if (!hasRecordCallback_sync(cb)) { 5053 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb, 5054 new ServiceEventHandlerDelegate(handler).getHandler())); 5055 final int newCbCount = mRecordCallbackList.size(); 5056 if ((oldCbCount == 0) && (newCbCount > 0)) { 5057 // register binder for callbacks 5058 final IAudioService service = getService(); 5059 try { 5060 service.registerRecordingCallback(mRecCb); 5061 } catch (RemoteException e) { 5062 throw e.rethrowFromSystemServer(); 5063 } 5064 } 5065 } else { 5066 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously" 5067 + "registered callback"); 5068 } 5069 } 5070 } 5071 5072 /** 5073 * Unregister an audio recording callback previously registered with 5074 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5075 * @param cb non-null callback to unregister 5076 */ unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5077 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) { 5078 if (cb == null) { 5079 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5080 } 5081 synchronized(mRecordCallbackLock) { 5082 if (mRecordCallbackList == null) { 5083 return; 5084 } 5085 final int oldCbCount = mRecordCallbackList.size(); 5086 if (removeRecordCallback_sync(cb)) { 5087 final int newCbCount = mRecordCallbackList.size(); 5088 if ((oldCbCount > 0) && (newCbCount == 0)) { 5089 // unregister binder for callbacks 5090 final IAudioService service = getService(); 5091 try { 5092 service.unregisterRecordingCallback(mRecCb); 5093 } catch (RemoteException e) { 5094 throw e.rethrowFromSystemServer(); 5095 } 5096 } 5097 } else { 5098 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback" 5099 + " already unregistered or never registered"); 5100 } 5101 } 5102 } 5103 5104 /** 5105 * Returns the current active audio recording configurations of the device. 5106 * @return a non-null list of recording configurations. An empty list indicates there is 5107 * no recording active when queried. 5108 * @see AudioRecordingConfiguration 5109 */ getActiveRecordingConfigurations()5110 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { 5111 final IAudioService service = getService(); 5112 try { 5113 return service.getActiveRecordingConfigurations(); 5114 } catch (RemoteException e) { 5115 throw e.rethrowFromSystemServer(); 5116 } 5117 } 5118 5119 /** 5120 * constants for the recording events, to keep in sync 5121 * with frameworks/av/include/media/AudioPolicy.h 5122 */ 5123 /** @hide */ 5124 public static final int RECORD_CONFIG_EVENT_NONE = -1; 5125 /** @hide */ 5126 public static final int RECORD_CONFIG_EVENT_START = 0; 5127 /** @hide */ 5128 public static final int RECORD_CONFIG_EVENT_STOP = 1; 5129 /** @hide */ 5130 public static final int RECORD_CONFIG_EVENT_UPDATE = 2; 5131 /** @hide */ 5132 public static final int RECORD_CONFIG_EVENT_RELEASE = 3; 5133 /** 5134 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h 5135 */ 5136 /** @hide */ 5137 public static final int RECORD_RIID_INVALID = -1; 5138 /** @hide */ 5139 public static final int RECORDER_STATE_STARTED = 0; 5140 /** @hide */ 5141 public static final int RECORDER_STATE_STOPPED = 1; 5142 5143 /** 5144 * All operations on this list are sync'd on mRecordCallbackLock. 5145 * List is lazy-initialized in 5146 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5147 * List can be null. 5148 */ 5149 private List<AudioRecordingCallbackInfo> mRecordCallbackList; 5150 private final Object mRecordCallbackLock = new Object(); 5151 5152 /** 5153 * Must be called synchronized on mRecordCallbackLock 5154 */ hasRecordCallback_sync(@onNull AudioRecordingCallback cb)5155 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5156 if (mRecordCallbackList != null) { 5157 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5158 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5159 return true; 5160 } 5161 } 5162 } 5163 return false; 5164 } 5165 5166 /** 5167 * Must be called synchronized on mRecordCallbackLock 5168 */ removeRecordCallback_sync(@onNull AudioRecordingCallback cb)5169 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5170 if (mRecordCallbackList != null) { 5171 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5172 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5173 mRecordCallbackList.remove(i); 5174 return true; 5175 } 5176 } 5177 } 5178 return false; 5179 } 5180 5181 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { 5182 @Override 5183 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { 5184 synchronized(mRecordCallbackLock) { 5185 if (mRecordCallbackList != null) { 5186 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5187 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i); 5188 if (arci.mHandler != null) { 5189 final Message m = arci.mHandler.obtainMessage( 5190 MSSG_RECORDING_CONFIG_CHANGE/*what*/, 5191 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 5192 arci.mHandler.sendMessage(m); 5193 } 5194 } 5195 } 5196 } 5197 } 5198 5199 }; 5200 5201 //===================================================================== 5202 5203 /** 5204 * @hide 5205 * Reload audio settings. This method is called by Settings backup 5206 * agent when audio settings are restored and causes the AudioService 5207 * to read and apply restored settings. 5208 */ 5209 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) reloadAudioSettings()5210 public void reloadAudioSettings() { 5211 final IAudioService service = getService(); 5212 try { 5213 service.reloadAudioSettings(); 5214 } catch (RemoteException e) { 5215 throw e.rethrowFromSystemServer(); 5216 } 5217 } 5218 5219 /** 5220 * @hide 5221 * Notifies AudioService that it is connected to an A2DP device that supports absolute volume, 5222 * so that AudioService can send volume change events to the A2DP device, rather than handling 5223 * them. 5224 */ avrcpSupportsAbsoluteVolume(String address, boolean support)5225 public void avrcpSupportsAbsoluteVolume(String address, boolean support) { 5226 final IAudioService service = getService(); 5227 try { 5228 service.avrcpSupportsAbsoluteVolume(address, support); 5229 } catch (RemoteException e) { 5230 throw e.rethrowFromSystemServer(); 5231 } 5232 } 5233 5234 /** 5235 * {@hide} 5236 */ 5237 private final IBinder mICallBack = new Binder(); 5238 5239 /** 5240 * Checks whether the phone is in silent mode, with or without vibrate. 5241 * 5242 * @return true if phone is in silent mode, with or without vibrate. 5243 * 5244 * @see #getRingerMode() 5245 * 5246 * @hide pending API Council approval 5247 */ 5248 @UnsupportedAppUsage isSilentMode()5249 public boolean isSilentMode() { 5250 int ringerMode = getRingerMode(); 5251 boolean silentMode = 5252 (ringerMode == RINGER_MODE_SILENT) || 5253 (ringerMode == RINGER_MODE_VIBRATE); 5254 return silentMode; 5255 } 5256 5257 // This section re-defines new output device constants from AudioSystem, because the AudioSystem 5258 // class is not used by other parts of the framework, which instead use definitions and methods 5259 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. 5260 5261 /** @hide 5262 * The audio device code for representing "no device." */ 5263 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; 5264 /** @hide 5265 * The audio output device code for the small speaker at the front of the device used 5266 * when placing calls. Does not refer to an in-ear headphone without attached microphone, 5267 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a 5268 * {@link #DEVICE_OUT_WIRED_HEADPHONE}. 5269 */ 5270 @UnsupportedAppUsage 5271 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; 5272 /** @hide 5273 * The audio output device code for the built-in speaker */ 5274 @UnsupportedAppUsage 5275 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; 5276 /** @hide 5277 * The audio output device code for a wired headset with attached microphone */ 5278 @UnsupportedAppUsage 5279 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 5280 /** @hide 5281 * The audio output device code for a wired headphone without attached microphone */ 5282 @UnsupportedAppUsage 5283 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 5284 /** @hide 5285 * The audio output device code for a USB headphone with attached microphone */ 5286 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET; 5287 /** @hide 5288 * The audio output device code for generic Bluetooth SCO, for voice */ 5289 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 5290 /** @hide 5291 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and 5292 * Hands-Free Profile (HFP), for voice 5293 */ 5294 @UnsupportedAppUsage 5295 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 5296 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 5297 /** @hide 5298 * The audio output device code for Bluetooth SCO car audio, for voice */ 5299 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 5300 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 5301 /** @hide 5302 * The audio output device code for generic Bluetooth A2DP, for music */ 5303 @UnsupportedAppUsage 5304 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 5305 /** @hide 5306 * The audio output device code for Bluetooth A2DP headphones, for music */ 5307 @UnsupportedAppUsage 5308 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 5309 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; 5310 /** @hide 5311 * The audio output device code for Bluetooth A2DP external speaker, for music */ 5312 @UnsupportedAppUsage 5313 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 5314 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; 5315 /** @hide 5316 * The audio output device code for S/PDIF (legacy) or HDMI 5317 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ 5318 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; 5319 /** @hide 5320 * The audio output device code for HDMI */ 5321 @UnsupportedAppUsage 5322 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; 5323 /** @hide 5324 * The audio output device code for an analog wired headset attached via a 5325 * docking station 5326 */ 5327 @UnsupportedAppUsage 5328 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 5329 /** @hide 5330 * The audio output device code for a digital wired headset attached via a 5331 * docking station 5332 */ 5333 @UnsupportedAppUsage 5334 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; 5335 /** @hide 5336 * The audio output device code for a USB audio accessory. The accessory is in USB host 5337 * mode and the Android device in USB device mode 5338 */ 5339 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; 5340 /** @hide 5341 * The audio output device code for a USB audio device. The device is in USB device 5342 * mode and the Android device in USB host mode 5343 */ 5344 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; 5345 /** @hide 5346 * The audio output device code for projection output. 5347 */ 5348 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 5349 /** @hide 5350 * The audio output device code the telephony voice TX path. 5351 */ 5352 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; 5353 /** @hide 5354 * The audio output device code for an analog jack with line impedance detected. 5355 */ 5356 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; 5357 /** @hide 5358 * The audio output device code for HDMI Audio Return Channel. 5359 */ 5360 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; 5361 /** @hide 5362 * The audio output device code for HDMI enhanced Audio Return Channel. 5363 */ 5364 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC; 5365 /** @hide 5366 * The audio output device code for S/PDIF digital connection. 5367 */ 5368 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; 5369 /** @hide 5370 * The audio output device code for built-in FM transmitter. 5371 */ 5372 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; 5373 /** @hide 5374 * The audio output device code for echo reference injection point. 5375 */ 5376 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; 5377 /** @hide 5378 * The audio output device code for a BLE audio headset. 5379 */ 5380 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; 5381 /** @hide 5382 * The audio output device code for a BLE audio speaker. 5383 */ 5384 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; 5385 /** @hide 5386 * This is not used as a returned value from {@link #getDevicesForStream}, but could be 5387 * used in the future in a set method to select whatever default device is chosen by the 5388 * platform-specific implementation. 5389 */ 5390 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; 5391 5392 /** @hide 5393 * The audio input device code for default built-in microphone 5394 */ 5395 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; 5396 /** @hide 5397 * The audio input device code for a Bluetooth SCO headset 5398 */ 5399 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 5400 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 5401 /** @hide 5402 * The audio input device code for wired headset microphone 5403 */ 5404 public static final int DEVICE_IN_WIRED_HEADSET = 5405 AudioSystem.DEVICE_IN_WIRED_HEADSET; 5406 /** @hide 5407 * The audio input device code for HDMI 5408 */ 5409 public static final int DEVICE_IN_HDMI = 5410 AudioSystem.DEVICE_IN_HDMI; 5411 /** @hide 5412 * The audio input device code for HDMI ARC 5413 */ 5414 public static final int DEVICE_IN_HDMI_ARC = 5415 AudioSystem.DEVICE_IN_HDMI_ARC; 5416 5417 /** @hide 5418 * The audio input device code for HDMI EARC 5419 */ 5420 public static final int DEVICE_IN_HDMI_EARC = 5421 AudioSystem.DEVICE_IN_HDMI_EARC; 5422 5423 /** @hide 5424 * The audio input device code for telephony voice RX path 5425 */ 5426 public static final int DEVICE_IN_TELEPHONY_RX = 5427 AudioSystem.DEVICE_IN_TELEPHONY_RX; 5428 /** @hide 5429 * The audio input device code for built-in microphone pointing to the back 5430 */ 5431 public static final int DEVICE_IN_BACK_MIC = 5432 AudioSystem.DEVICE_IN_BACK_MIC; 5433 /** @hide 5434 * The audio input device code for analog from a docking station 5435 */ 5436 public static final int DEVICE_IN_ANLG_DOCK_HEADSET = 5437 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; 5438 /** @hide 5439 * The audio input device code for digital from a docking station 5440 */ 5441 public static final int DEVICE_IN_DGTL_DOCK_HEADSET = 5442 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; 5443 /** @hide 5444 * The audio input device code for a USB audio accessory. The accessory is in USB host 5445 * mode and the Android device in USB device mode 5446 */ 5447 public static final int DEVICE_IN_USB_ACCESSORY = 5448 AudioSystem.DEVICE_IN_USB_ACCESSORY; 5449 /** @hide 5450 * The audio input device code for a USB audio device. The device is in USB device 5451 * mode and the Android device in USB host mode 5452 */ 5453 public static final int DEVICE_IN_USB_DEVICE = 5454 AudioSystem.DEVICE_IN_USB_DEVICE; 5455 /** @hide 5456 * The audio input device code for a FM radio tuner 5457 */ 5458 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; 5459 /** @hide 5460 * The audio input device code for a TV tuner 5461 */ 5462 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; 5463 /** @hide 5464 * The audio input device code for an analog jack with line impedance detected 5465 */ 5466 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; 5467 /** @hide 5468 * The audio input device code for a S/PDIF digital connection 5469 */ 5470 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; 5471 /** @hide 5472 * The audio input device code for audio loopback 5473 */ 5474 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; 5475 /** @hide 5476 * The audio input device code for an echo reference capture point. 5477 */ 5478 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; 5479 /** @hide 5480 * The audio input device code for a BLE audio headset. 5481 */ 5482 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; 5483 5484 /** 5485 * Return true if the device code corresponds to an output device. 5486 * @hide 5487 */ isOutputDevice(int device)5488 public static boolean isOutputDevice(int device) 5489 { 5490 return (device & AudioSystem.DEVICE_BIT_IN) == 0; 5491 } 5492 5493 /** 5494 * Return true if the device code corresponds to an input device. 5495 * @hide 5496 */ isInputDevice(int device)5497 public static boolean isInputDevice(int device) 5498 { 5499 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN; 5500 } 5501 5502 5503 /** 5504 * Return the enabled devices for the specified output stream type. 5505 * 5506 * @param streamType The stream type to query. One of 5507 * {@link #STREAM_VOICE_CALL}, 5508 * {@link #STREAM_SYSTEM}, 5509 * {@link #STREAM_RING}, 5510 * {@link #STREAM_MUSIC}, 5511 * {@link #STREAM_ALARM}, 5512 * {@link #STREAM_NOTIFICATION}, 5513 * {@link #STREAM_DTMF}, 5514 * {@link #STREAM_ACCESSIBILITY}. 5515 * 5516 * @return The bit-mask "or" of audio output device codes for all enabled devices on this 5517 * stream. Zero or more of 5518 * {@link #DEVICE_OUT_EARPIECE}, 5519 * {@link #DEVICE_OUT_SPEAKER}, 5520 * {@link #DEVICE_OUT_WIRED_HEADSET}, 5521 * {@link #DEVICE_OUT_WIRED_HEADPHONE}, 5522 * {@link #DEVICE_OUT_BLUETOOTH_SCO}, 5523 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET}, 5524 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT}, 5525 * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, 5526 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, 5527 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, 5528 * {@link #DEVICE_OUT_HDMI}, 5529 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, 5530 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. 5531 * {@link #DEVICE_OUT_USB_ACCESSORY}. 5532 * {@link #DEVICE_OUT_USB_DEVICE}. 5533 * {@link #DEVICE_OUT_REMOTE_SUBMIX}. 5534 * {@link #DEVICE_OUT_TELEPHONY_TX}. 5535 * {@link #DEVICE_OUT_LINE}. 5536 * {@link #DEVICE_OUT_HDMI_ARC}. 5537 * {@link #DEVICE_OUT_HDMI_EARC}. 5538 * {@link #DEVICE_OUT_SPDIF}. 5539 * {@link #DEVICE_OUT_FM}. 5540 * {@link #DEVICE_OUT_DEFAULT} is not used here. 5541 * 5542 * The implementation may support additional device codes beyond those listed, so 5543 * the application should ignore any bits which it does not recognize. 5544 * Note that the information may be imprecise when the implementation 5545 * cannot distinguish whether a particular device is enabled. 5546 * 5547 * {@hide} 5548 */ 5549 @UnsupportedAppUsage getDevicesForStream(int streamType)5550 public int getDevicesForStream(int streamType) { 5551 switch (streamType) { 5552 case STREAM_VOICE_CALL: 5553 case STREAM_SYSTEM: 5554 case STREAM_RING: 5555 case STREAM_MUSIC: 5556 case STREAM_ALARM: 5557 case STREAM_NOTIFICATION: 5558 case STREAM_DTMF: 5559 case STREAM_ACCESSIBILITY: 5560 final IAudioService service = getService(); 5561 try { 5562 return service.getDevicesForStream(streamType); 5563 } catch (RemoteException e) { 5564 throw e.rethrowFromSystemServer(); 5565 } 5566 default: 5567 return 0; 5568 } 5569 } 5570 5571 /** 5572 * @hide 5573 * Get the audio devices that would be used for the routing of the given audio attributes. 5574 * @param attributes the {@link AudioAttributes} for which the routing is being queried 5575 * @return an empty list if there was an issue with the request, a list of audio devices 5576 * otherwise (typically one device, except for duplicated paths). 5577 */ 5578 @SystemApi 5579 @RequiresPermission(anyOf = { 5580 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5581 android.Manifest.permission.QUERY_AUDIO_STATE 5582 }) getDevicesForAttributes( @onNull AudioAttributes attributes)5583 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes( 5584 @NonNull AudioAttributes attributes) { 5585 Objects.requireNonNull(attributes); 5586 final IAudioService service = getService(); 5587 try { 5588 return service.getDevicesForAttributes(attributes); 5589 } catch (RemoteException e) { 5590 throw e.rethrowFromSystemServer(); 5591 } 5592 } 5593 5594 /** 5595 * @hide 5596 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as 5597 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not 5598 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}. 5599 */ 5600 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; 5601 /** 5602 * @hide 5603 * Volume behavior for an audio device where a software attenuation is applied 5604 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5605 */ 5606 @SystemApi 5607 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; 5608 /** 5609 * @hide 5610 * Volume behavior for an audio device where the volume is always set to provide no attenuation 5611 * nor gain (e.g. unit gain). 5612 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5613 */ 5614 @SystemApi 5615 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; 5616 /** 5617 * @hide 5618 * Volume behavior for an audio device where the volume is either set to muted, or to provide 5619 * no attenuation nor gain (e.g. unit gain). 5620 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5621 */ 5622 @SystemApi 5623 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; 5624 /** 5625 * @hide 5626 * Volume behavior for an audio device where no software attenuation is applied, and 5627 * the volume is kept synchronized between the host and the device itself through a 5628 * device-specific protocol such as BT AVRCP. 5629 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5630 */ 5631 @SystemApi 5632 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; 5633 /** 5634 * @hide 5635 * Volume behavior for an audio device where no software attenuation is applied, and 5636 * the volume is kept synchronized between the host and the device itself through a 5637 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g. 5638 * normal vs in phone call). 5639 * @see #setMode(int) 5640 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5641 */ 5642 @SystemApi 5643 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; 5644 5645 /** @hide */ 5646 @IntDef({ 5647 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 5648 DEVICE_VOLUME_BEHAVIOR_FULL, 5649 DEVICE_VOLUME_BEHAVIOR_FIXED, 5650 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 5651 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 5652 }) 5653 @Retention(RetentionPolicy.SOURCE) 5654 public @interface DeviceVolumeBehavior {} 5655 5656 /** @hide */ 5657 @IntDef({ 5658 DEVICE_VOLUME_BEHAVIOR_UNSET, 5659 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 5660 DEVICE_VOLUME_BEHAVIOR_FULL, 5661 DEVICE_VOLUME_BEHAVIOR_FIXED, 5662 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 5663 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 5664 }) 5665 @Retention(RetentionPolicy.SOURCE) 5666 public @interface DeviceVolumeBehaviorState {} 5667 5668 /** 5669 * @hide 5670 * Throws IAE on an invalid volume behavior value 5671 * @param volumeBehavior behavior value to check 5672 */ enforceValidVolumeBehavior(int volumeBehavior)5673 public static void enforceValidVolumeBehavior(int volumeBehavior) { 5674 switch (volumeBehavior) { 5675 case DEVICE_VOLUME_BEHAVIOR_VARIABLE: 5676 case DEVICE_VOLUME_BEHAVIOR_FULL: 5677 case DEVICE_VOLUME_BEHAVIOR_FIXED: 5678 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: 5679 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: 5680 return; 5681 default: 5682 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior); 5683 } 5684 } 5685 5686 /** 5687 * @hide 5688 * Sets the volume behavior for an audio output device. 5689 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE 5690 * @see #DEVICE_VOLUME_BEHAVIOR_FULL 5691 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED 5692 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE 5693 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE 5694 * @param device the device to be affected 5695 * @param deviceVolumeBehavior one of the device behaviors 5696 */ 5697 @SystemApi 5698 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)5699 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, 5700 @DeviceVolumeBehavior int deviceVolumeBehavior) { 5701 // verify arguments (validity of device type is enforced in server) 5702 Objects.requireNonNull(device); 5703 enforceValidVolumeBehavior(deviceVolumeBehavior); 5704 // communicate with service 5705 final IAudioService service = getService(); 5706 try { 5707 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior, 5708 mApplicationContext.getOpPackageName()); 5709 } catch (RemoteException e) { 5710 throw e.rethrowFromSystemServer(); 5711 } 5712 } 5713 5714 /** 5715 * @hide 5716 * Returns the volume device behavior for the given audio device 5717 * @param device the audio device 5718 * @return the volume behavior for the device 5719 */ 5720 @SystemApi 5721 @RequiresPermission(anyOf = { 5722 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5723 android.Manifest.permission.QUERY_AUDIO_STATE 5724 }) 5725 public @DeviceVolumeBehavior getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)5726 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { 5727 // verify arguments (validity of device type is enforced in server) 5728 Objects.requireNonNull(device); 5729 // communicate with service 5730 final IAudioService service = getService(); 5731 try { 5732 return service.getDeviceVolumeBehavior(device); 5733 } catch (RemoteException e) { 5734 throw e.rethrowFromSystemServer(); 5735 } 5736 } 5737 5738 /** 5739 * @hide 5740 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}. 5741 */ 5742 @TestApi 5743 @RequiresPermission(anyOf = { 5744 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5745 android.Manifest.permission.QUERY_AUDIO_STATE 5746 }) isFullVolumeDevice()5747 public boolean isFullVolumeDevice() { 5748 final AudioAttributes attributes = new AudioAttributes.Builder() 5749 .setUsage(AudioAttributes.USAGE_MEDIA) 5750 .build(); 5751 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes); 5752 for (AudioDeviceAttributes device : devices) { 5753 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) { 5754 return true; 5755 } 5756 } 5757 return false; 5758 } 5759 5760 /** 5761 * Indicate wired accessory connection state change. 5762 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) 5763 * @param state new connection state: 1 connected, 0 disconnected 5764 * @param name device name 5765 * {@hide} 5766 */ 5767 @UnsupportedAppUsage 5768 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(int type, int state, String address, String name)5769 public void setWiredDeviceConnectionState(int type, int state, String address, String name) { 5770 final IAudioService service = getService(); 5771 try { 5772 service.setWiredDeviceConnectionState(type, state, address, name, 5773 mApplicationContext.getOpPackageName()); 5774 } catch (RemoteException e) { 5775 throw e.rethrowFromSystemServer(); 5776 } 5777 } 5778 5779 /** 5780 * Indicate Hearing Aid connection state change and eventually suppress 5781 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. 5782 * This operation is asynchronous but its execution will still be sequentially scheduled 5783 * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 5784 * * BluetoothDevice, int, int, boolean, int)} and 5785 * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. 5786 * @param device Bluetooth device connected/disconnected 5787 * @param state new connection state (BluetoothProfile.STATE_xxx) 5788 * @param musicDevice Default get system volume for the connecting device. 5789 * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or 5790 * {@link android.bluetooth.BluetoothProfile.HEARING_AID}) 5791 * @param suppressNoisyIntent if true the 5792 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. 5793 * {@hide} 5794 */ setBluetoothHearingAidDeviceConnectionState( BluetoothDevice device, int state, boolean suppressNoisyIntent, int musicDevice)5795 public void setBluetoothHearingAidDeviceConnectionState( 5796 BluetoothDevice device, int state, boolean suppressNoisyIntent, 5797 int musicDevice) { 5798 final IAudioService service = getService(); 5799 try { 5800 service.setBluetoothHearingAidDeviceConnectionState(device, 5801 state, suppressNoisyIntent, musicDevice); 5802 } catch (RemoteException e) { 5803 throw e.rethrowFromSystemServer(); 5804 } 5805 } 5806 5807 /** 5808 * Indicate A2DP source or sink connection state change and eventually suppress 5809 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. 5810 * This operation is asynchronous but its execution will still be sequentially scheduled 5811 * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, 5812 * int, boolean, int)} and 5813 * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. 5814 * @param device Bluetooth device connected/disconnected 5815 * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED} 5816 * or {@link BluetoothProfile#STATE_DISCONNECTED} 5817 * @param profile profile for the A2DP device 5818 * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting. 5819 * (either {@link android.bluetooth.BluetoothProfile.A2DP} or 5820 * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) 5821 * @param suppressNoisyIntent if true the 5822 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. 5823 * {@hide} 5824 */ setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)5825 public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 5826 BluetoothDevice device, int state, 5827 int profile, boolean suppressNoisyIntent, int a2dpVolume) { 5828 final IAudioService service = getService(); 5829 try { 5830 service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, 5831 state, profile, suppressNoisyIntent, a2dpVolume); 5832 } catch (RemoteException e) { 5833 throw e.rethrowFromSystemServer(); 5834 } 5835 } 5836 5837 /** 5838 * Indicate A2DP device configuration has changed. 5839 * This operation is asynchronous but its execution will still be sequentially scheduled 5840 * relative to calls to 5841 * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int, 5842 * boolean, int)} and 5843 * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)} 5844 * @param device Bluetooth device whose configuration has changed. 5845 * {@hide} 5846 */ handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)5847 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { 5848 final IAudioService service = getService(); 5849 try { 5850 service.handleBluetoothA2dpDeviceConfigChange(device); 5851 } catch (RemoteException e) { 5852 throw e.rethrowFromSystemServer(); 5853 } 5854 } 5855 5856 /** {@hide} */ getRingtonePlayer()5857 public IRingtonePlayer getRingtonePlayer() { 5858 try { 5859 return getService().getRingtonePlayer(); 5860 } catch (RemoteException e) { 5861 throw e.rethrowFromSystemServer(); 5862 } 5863 } 5864 5865 /** 5866 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate 5867 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps 5868 * should use this value as a default, and offer the user the option to override it. 5869 * The low latency output stream is typically either the device's primary output stream, 5870 * or another output stream with smaller buffers. 5871 */ 5872 // FIXME Deprecate 5873 public static final String PROPERTY_OUTPUT_SAMPLE_RATE = 5874 "android.media.property.OUTPUT_SAMPLE_RATE"; 5875 5876 /** 5877 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size 5878 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps 5879 * should use this value as a minimum, and offer the user the option to override it. 5880 * The low latency output stream is typically either the device's primary output stream, 5881 * or another output stream with smaller buffers. 5882 */ 5883 // FIXME Deprecate 5884 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = 5885 "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; 5886 5887 /** 5888 * Used as a key for {@link #getProperty} to determine if the default microphone audio source 5889 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 5890 */ 5891 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = 5892 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; 5893 5894 /** 5895 * Used as a key for {@link #getProperty} to determine if the default speaker audio path 5896 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 5897 */ 5898 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = 5899 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; 5900 5901 /** 5902 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is 5903 * available and supported with the expected frequency range and level response. 5904 */ 5905 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = 5906 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED"; 5907 /** 5908 * Returns the value of the property with the specified key. 5909 * @param key One of the strings corresponding to a property key: either 5910 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE}, 5911 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER}, 5912 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, 5913 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or 5914 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}. 5915 * @return A string representing the associated value for that property key, 5916 * or null if there is no value for that key. 5917 */ getProperty(String key)5918 public String getProperty(String key) { 5919 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) { 5920 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate(); 5921 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null; 5922 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) { 5923 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount(); 5924 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null; 5925 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) { 5926 // Will throw a RuntimeException Resources.NotFoundException if this config value is 5927 // not found. 5928 return String.valueOf(getContext().getResources().getBoolean( 5929 com.android.internal.R.bool.config_supportMicNearUltrasound)); 5930 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) { 5931 return String.valueOf(getContext().getResources().getBoolean( 5932 com.android.internal.R.bool.config_supportSpeakerNearUltrasound)); 5933 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) { 5934 return String.valueOf(getContext().getResources().getBoolean( 5935 com.android.internal.R.bool.config_supportAudioSourceUnprocessed)); 5936 } else { 5937 // null or unknown key 5938 return null; 5939 } 5940 } 5941 5942 /** 5943 * @hide 5944 * Sets an additional audio output device delay in milliseconds. 5945 * 5946 * The additional output delay is a request to the output device to 5947 * delay audio presentation (generally with respect to video presentation for better 5948 * synchronization). 5949 * It may not be supported by all output devices, 5950 * and typically increases the audio latency by the amount of additional 5951 * audio delay requested. 5952 * 5953 * If additional audio delay is supported by an audio output device, 5954 * it is expected to be supported for all output streams (and configurations) 5955 * opened on that device. 5956 * 5957 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 5958 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0} 5959 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}. 5960 * @return true if successful, false if the device does not support output device delay 5961 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}. 5962 */ 5963 @SystemApi 5964 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)5965 public boolean setAdditionalOutputDeviceDelay( 5966 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) { 5967 Objects.requireNonNull(device); 5968 try { 5969 return getService().setAdditionalOutputDeviceDelay( 5970 new AudioDeviceAttributes(device), delayMillis); 5971 } catch (RemoteException e) { 5972 throw e.rethrowFromSystemServer(); 5973 } 5974 } 5975 5976 /** 5977 * @hide 5978 * Returns the current additional audio output device delay in milliseconds. 5979 * 5980 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 5981 * @return the additional output device delay. This is a non-negative number. 5982 * {@code 0} is returned if unsupported. 5983 */ 5984 @SystemApi 5985 @IntRange(from = 0) getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)5986 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 5987 Objects.requireNonNull(device); 5988 try { 5989 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device)); 5990 } catch (RemoteException e) { 5991 throw e.rethrowFromSystemServer(); 5992 } 5993 } 5994 5995 /** 5996 * @hide 5997 * Returns the maximum additional audio output device delay in milliseconds. 5998 * 5999 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 6000 * @return the maximum output device delay in milliseconds that can be set. 6001 * This is a non-negative number 6002 * representing the additional audio delay supported for the device. 6003 * {@code 0} is returned if unsupported. 6004 */ 6005 @SystemApi 6006 @IntRange(from = 0) getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)6007 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 6008 Objects.requireNonNull(device); 6009 try { 6010 return getService().getMaxAdditionalOutputDeviceDelay( 6011 new AudioDeviceAttributes(device)); 6012 } catch (RemoteException e) { 6013 throw e.rethrowFromSystemServer(); 6014 } 6015 } 6016 6017 /** 6018 * Returns the estimated latency for the given stream type in milliseconds. 6019 * 6020 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need 6021 * a better solution. 6022 * @hide 6023 */ 6024 @UnsupportedAppUsage getOutputLatency(int streamType)6025 public int getOutputLatency(int streamType) { 6026 return AudioSystem.getOutputLatency(streamType); 6027 } 6028 6029 /** 6030 * Registers a global volume controller interface. Currently limited to SystemUI. 6031 * 6032 * @hide 6033 */ setVolumeController(IVolumeController controller)6034 public void setVolumeController(IVolumeController controller) { 6035 try { 6036 getService().setVolumeController(controller); 6037 } catch (RemoteException e) { 6038 throw e.rethrowFromSystemServer(); 6039 } 6040 } 6041 6042 /** 6043 * Notify audio manager about volume controller visibility changes. 6044 * Currently limited to SystemUI. 6045 * 6046 * @hide 6047 */ notifyVolumeControllerVisible(IVolumeController controller, boolean visible)6048 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) { 6049 try { 6050 getService().notifyVolumeControllerVisible(controller, visible); 6051 } catch (RemoteException e) { 6052 throw e.rethrowFromSystemServer(); 6053 } 6054 } 6055 6056 /** 6057 * Only useful for volume controllers. 6058 * @hide 6059 */ isStreamAffectedByRingerMode(int streamType)6060 public boolean isStreamAffectedByRingerMode(int streamType) { 6061 try { 6062 return getService().isStreamAffectedByRingerMode(streamType); 6063 } catch (RemoteException e) { 6064 throw e.rethrowFromSystemServer(); 6065 } 6066 } 6067 6068 /** 6069 * Only useful for volume controllers. 6070 * @hide 6071 */ isStreamAffectedByMute(int streamType)6072 public boolean isStreamAffectedByMute(int streamType) { 6073 try { 6074 return getService().isStreamAffectedByMute(streamType); 6075 } catch (RemoteException e) { 6076 throw e.rethrowFromSystemServer(); 6077 } 6078 } 6079 6080 /** 6081 * Only useful for volume controllers. 6082 * @hide 6083 */ disableSafeMediaVolume()6084 public void disableSafeMediaVolume() { 6085 try { 6086 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName()); 6087 } catch (RemoteException e) { 6088 throw e.rethrowFromSystemServer(); 6089 } 6090 } 6091 6092 /** 6093 * Only useful for volume controllers. 6094 * @hide 6095 */ 6096 @UnsupportedAppUsage setRingerModeInternal(int ringerMode)6097 public void setRingerModeInternal(int ringerMode) { 6098 try { 6099 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName()); 6100 } catch (RemoteException e) { 6101 throw e.rethrowFromSystemServer(); 6102 } 6103 } 6104 6105 /** 6106 * Only useful for volume controllers. 6107 * @hide 6108 */ 6109 @UnsupportedAppUsage getRingerModeInternal()6110 public int getRingerModeInternal() { 6111 try { 6112 return getService().getRingerModeInternal(); 6113 } catch (RemoteException e) { 6114 throw e.rethrowFromSystemServer(); 6115 } 6116 } 6117 6118 /** 6119 * Only useful for volume controllers. 6120 * @hide 6121 */ setVolumePolicy(VolumePolicy policy)6122 public void setVolumePolicy(VolumePolicy policy) { 6123 try { 6124 getService().setVolumePolicy(policy); 6125 } catch (RemoteException e) { 6126 throw e.rethrowFromSystemServer(); 6127 } 6128 } 6129 6130 /** 6131 * Set Hdmi Cec system audio mode. 6132 * 6133 * @param on whether to be on system audio mode 6134 * @return output device type. 0 (DEVICE_NONE) if failed to set device. 6135 * @hide 6136 */ setHdmiSystemAudioSupported(boolean on)6137 public int setHdmiSystemAudioSupported(boolean on) { 6138 try { 6139 return getService().setHdmiSystemAudioSupported(on); 6140 } catch (RemoteException e) { 6141 throw e.rethrowFromSystemServer(); 6142 } 6143 } 6144 6145 /** 6146 * Returns true if Hdmi Cec system audio mode is supported. 6147 * 6148 * @hide 6149 */ 6150 @SystemApi 6151 @SuppressLint("RequiresPermission") // FIXME is this still used? isHdmiSystemAudioSupported()6152 public boolean isHdmiSystemAudioSupported() { 6153 try { 6154 return getService().isHdmiSystemAudioSupported(); 6155 } catch (RemoteException e) { 6156 throw e.rethrowFromSystemServer(); 6157 } 6158 } 6159 6160 /** 6161 * Return codes for listAudioPorts(), createAudioPatch() ... 6162 */ 6163 6164 /** @hide */ 6165 @SystemApi 6166 public static final int SUCCESS = AudioSystem.SUCCESS; 6167 /** 6168 * A default error code. 6169 */ 6170 public static final int ERROR = AudioSystem.ERROR; 6171 /** @hide 6172 * CANDIDATE FOR PUBLIC API 6173 */ 6174 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 6175 /** @hide 6176 */ 6177 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 6178 /** @hide 6179 */ 6180 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED; 6181 /** @hide 6182 */ 6183 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT; 6184 /** 6185 * An error code indicating that the object reporting it is no longer valid and needs to 6186 * be recreated. 6187 */ 6188 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 6189 6190 /** 6191 * Returns a list of descriptors for all audio ports managed by the audio framework. 6192 * Audio ports are nodes in the audio framework or audio hardware that can be configured 6193 * or connected and disconnected with createAudioPatch() or releaseAudioPatch(). 6194 * See AudioPort for a list of attributes of each audio port. 6195 * @param ports An AudioPort ArrayList where the list will be returned. 6196 * @hide 6197 */ 6198 @UnsupportedAppUsage listAudioPorts(ArrayList<AudioPort> ports)6199 public static int listAudioPorts(ArrayList<AudioPort> ports) { 6200 return updateAudioPortCache(ports, null, null); 6201 } 6202 6203 /** 6204 * Returns a list of descriptors for all audio ports managed by the audio framework as 6205 * it was before the last update calback. 6206 * @param ports An AudioPort ArrayList where the list will be returned. 6207 * @hide 6208 */ listPreviousAudioPorts(ArrayList<AudioPort> ports)6209 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) { 6210 return updateAudioPortCache(null, null, ports); 6211 } 6212 6213 /** 6214 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort) 6215 * @see listAudioPorts(ArrayList<AudioPort>) 6216 * @hide 6217 */ listAudioDevicePorts(ArrayList<AudioDevicePort> devices)6218 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 6219 if (devices == null) { 6220 return ERROR_BAD_VALUE; 6221 } 6222 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 6223 int status = updateAudioPortCache(ports, null, null); 6224 if (status == SUCCESS) { 6225 filterDevicePorts(ports, devices); 6226 } 6227 return status; 6228 } 6229 6230 /** 6231 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort) 6232 * @see listPreviousAudioPorts(ArrayList<AudioPort>) 6233 * @hide 6234 */ listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)6235 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 6236 if (devices == null) { 6237 return ERROR_BAD_VALUE; 6238 } 6239 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 6240 int status = updateAudioPortCache(null, null, ports); 6241 if (status == SUCCESS) { 6242 filterDevicePorts(ports, devices); 6243 } 6244 return status; 6245 } 6246 filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)6247 private static void filterDevicePorts(ArrayList<AudioPort> ports, 6248 ArrayList<AudioDevicePort> devices) { 6249 devices.clear(); 6250 for (int i = 0; i < ports.size(); i++) { 6251 if (ports.get(i) instanceof AudioDevicePort) { 6252 devices.add((AudioDevicePort)ports.get(i)); 6253 } 6254 } 6255 } 6256 6257 /** 6258 * Create a connection between two or more devices. The framework will reject the request if 6259 * device types are not compatible or the implementation does not support the requested 6260 * configuration. 6261 * NOTE: current implementation is limited to one source and one sink per patch. 6262 * @param patch AudioPatch array where the newly created patch will be returned. 6263 * As input, if patch[0] is not null, the specified patch will be replaced by the 6264 * new patch created. This avoids calling releaseAudioPatch() when modifying a 6265 * patch and allows the implementation to optimize transitions. 6266 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE. 6267 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK. 6268 * 6269 * @return - {@link #SUCCESS} if connection is successful. 6270 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed. 6271 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported. 6272 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create 6273 * a patch. 6274 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 6275 * - {@link #ERROR} if patch cannot be connected for any other reason. 6276 * 6277 * patch[0] contains the newly created patch 6278 * @hide 6279 */ 6280 @UnsupportedAppUsage createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)6281 public static int createAudioPatch(AudioPatch[] patch, 6282 AudioPortConfig[] sources, 6283 AudioPortConfig[] sinks) { 6284 return AudioSystem.createAudioPatch(patch, sources, sinks); 6285 } 6286 6287 /** 6288 * Releases an existing audio patch connection. 6289 * @param patch The audio patch to disconnect. 6290 * @return - {@link #SUCCESS} if disconnection is successful. 6291 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist. 6292 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release 6293 * a patch. 6294 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 6295 * - {@link #ERROR} if patch cannot be released for any other reason. 6296 * @hide 6297 */ 6298 @UnsupportedAppUsage releaseAudioPatch(AudioPatch patch)6299 public static int releaseAudioPatch(AudioPatch patch) { 6300 return AudioSystem.releaseAudioPatch(patch); 6301 } 6302 6303 /** 6304 * List all existing connections between audio ports. 6305 * @param patches An AudioPatch array where the list will be returned. 6306 * @hide 6307 */ 6308 @UnsupportedAppUsage listAudioPatches(ArrayList<AudioPatch> patches)6309 public static int listAudioPatches(ArrayList<AudioPatch> patches) { 6310 return updateAudioPortCache(null, patches, null); 6311 } 6312 6313 /** 6314 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by 6315 * AudioGain.buildConfig() 6316 * @hide 6317 */ setAudioPortGain(AudioPort port, AudioGainConfig gain)6318 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) { 6319 if (port == null || gain == null) { 6320 return ERROR_BAD_VALUE; 6321 } 6322 AudioPortConfig activeConfig = port.activeConfig(); 6323 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(), 6324 activeConfig.channelMask(), activeConfig.format(), gain); 6325 config.mConfigMask = AudioPortConfig.GAIN; 6326 return AudioSystem.setAudioPortConfig(config); 6327 } 6328 6329 /** 6330 * Listener registered by client to be notified upon new audio port connections, 6331 * disconnections or attributes update. 6332 * @hide 6333 */ 6334 public interface OnAudioPortUpdateListener { 6335 /** 6336 * Callback method called upon audio port list update. 6337 * @param portList the updated list of audio ports 6338 */ onAudioPortListUpdate(AudioPort[] portList)6339 public void onAudioPortListUpdate(AudioPort[] portList); 6340 6341 /** 6342 * Callback method called upon audio patch list update. 6343 * @param patchList the updated list of audio patches 6344 */ onAudioPatchListUpdate(AudioPatch[] patchList)6345 public void onAudioPatchListUpdate(AudioPatch[] patchList); 6346 6347 /** 6348 * Callback method called when the mediaserver dies 6349 */ onServiceDied()6350 public void onServiceDied(); 6351 } 6352 6353 /** 6354 * Register an audio port list update listener. 6355 * @hide 6356 */ 6357 @UnsupportedAppUsage registerAudioPortUpdateListener(OnAudioPortUpdateListener l)6358 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { 6359 sAudioPortEventHandler.init(); 6360 sAudioPortEventHandler.registerListener(l); 6361 } 6362 6363 /** 6364 * Unregister an audio port list update listener. 6365 * @hide 6366 */ 6367 @UnsupportedAppUsage unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)6368 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) { 6369 sAudioPortEventHandler.unregisterListener(l); 6370 } 6371 6372 // 6373 // AudioPort implementation 6374 // 6375 6376 static final int AUDIOPORT_GENERATION_INIT = 0; 6377 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT); 6378 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); 6379 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); 6380 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); 6381 resetAudioPortGeneration()6382 static int resetAudioPortGeneration() { 6383 int generation; 6384 synchronized (sAudioPortGeneration) { 6385 generation = sAudioPortGeneration; 6386 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 6387 } 6388 return generation; 6389 } 6390 updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)6391 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, 6392 ArrayList<AudioPort> previousPorts) { 6393 sAudioPortEventHandler.init(); 6394 synchronized (sAudioPortGeneration) { 6395 6396 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { 6397 int[] patchGeneration = new int[1]; 6398 int[] portGeneration = new int[1]; 6399 int status; 6400 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>(); 6401 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>(); 6402 6403 do { 6404 newPorts.clear(); 6405 status = AudioSystem.listAudioPorts(newPorts, portGeneration); 6406 if (status != SUCCESS) { 6407 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed"); 6408 return status; 6409 } 6410 newPatches.clear(); 6411 status = AudioSystem.listAudioPatches(newPatches, patchGeneration); 6412 if (status != SUCCESS) { 6413 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed"); 6414 return status; 6415 } 6416 // Loop until patch generation is the same as port generation unless audio ports 6417 // and audio patches are not null. 6418 } while (patchGeneration[0] != portGeneration[0] 6419 && (ports == null || patches == null)); 6420 // If the patch generation doesn't equal port generation, return ERROR here in case 6421 // of mismatch between audio ports and audio patches. 6422 if (patchGeneration[0] != portGeneration[0]) { 6423 return ERROR; 6424 } 6425 6426 for (int i = 0; i < newPatches.size(); i++) { 6427 for (int j = 0; j < newPatches.get(i).sources().length; j++) { 6428 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j], 6429 newPorts); 6430 newPatches.get(i).sources()[j] = portCfg; 6431 } 6432 for (int j = 0; j < newPatches.get(i).sinks().length; j++) { 6433 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j], 6434 newPorts); 6435 newPatches.get(i).sinks()[j] = portCfg; 6436 } 6437 } 6438 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) { 6439 AudioPatch newPatch = i.next(); 6440 boolean hasInvalidPort = false; 6441 for (AudioPortConfig portCfg : newPatch.sources()) { 6442 if (portCfg == null) { 6443 hasInvalidPort = true; 6444 break; 6445 } 6446 } 6447 for (AudioPortConfig portCfg : newPatch.sinks()) { 6448 if (portCfg == null) { 6449 hasInvalidPort = true; 6450 break; 6451 } 6452 } 6453 if (hasInvalidPort) { 6454 // Temporarily remove patches with invalid ports. One who created the patch 6455 // is responsible for dealing with the port change. 6456 i.remove(); 6457 } 6458 } 6459 6460 sPreviousAudioPortsCached = sAudioPortsCached; 6461 sAudioPortsCached = newPorts; 6462 sAudioPatchesCached = newPatches; 6463 sAudioPortGeneration = portGeneration[0]; 6464 } 6465 if (ports != null) { 6466 ports.clear(); 6467 ports.addAll(sAudioPortsCached); 6468 } 6469 if (patches != null) { 6470 patches.clear(); 6471 patches.addAll(sAudioPatchesCached); 6472 } 6473 if (previousPorts != null) { 6474 previousPorts.clear(); 6475 previousPorts.addAll(sPreviousAudioPortsCached); 6476 } 6477 } 6478 return SUCCESS; 6479 } 6480 updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)6481 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) { 6482 AudioPort port = portCfg.port(); 6483 int k; 6484 for (k = 0; k < ports.size(); k++) { 6485 // compare handles because the port returned by JNI is not of the correct 6486 // subclass 6487 if (ports.get(k).handle().equals(port.handle())) { 6488 port = ports.get(k); 6489 break; 6490 } 6491 } 6492 if (k == ports.size()) { 6493 // this hould never happen 6494 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id()); 6495 return null; 6496 } 6497 AudioGainConfig gainCfg = portCfg.gain(); 6498 if (gainCfg != null) { 6499 AudioGain gain = port.gain(gainCfg.index()); 6500 gainCfg = gain.buildConfig(gainCfg.mode(), 6501 gainCfg.channelMask(), 6502 gainCfg.values(), 6503 gainCfg.rampDurationMs()); 6504 } 6505 return port.buildConfig(portCfg.samplingRate(), 6506 portCfg.channelMask(), 6507 portCfg.format(), 6508 gainCfg); 6509 } 6510 6511 private OnAmPortUpdateListener mPortListener = null; 6512 6513 /** 6514 * The message sent to apps when the contents of the device list changes if they provide 6515 * a {@link Handler} object to addOnAudioDeviceConnectionListener(). 6516 */ 6517 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0; 6518 private final static int MSG_DEVICES_DEVICES_ADDED = 1; 6519 private final static int MSG_DEVICES_DEVICES_REMOVED = 2; 6520 6521 /** 6522 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. 6523 */ 6524 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = 6525 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); 6526 6527 /** 6528 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter 6529 * the results list to only those device types they are interested in. 6530 */ 6531 /** 6532 * Specifies to the {@link AudioManager#getDevices(int)} method to include 6533 * source (i.e. input) audio devices. 6534 */ 6535 public static final int GET_DEVICES_INPUTS = 0x0001; 6536 6537 /** 6538 * Specifies to the {@link AudioManager#getDevices(int)} method to include 6539 * sink (i.e. output) audio devices. 6540 */ 6541 public static final int GET_DEVICES_OUTPUTS = 0x0002; 6542 6543 /** @hide */ 6544 @IntDef(flag = true, prefix = "GET_DEVICES", value = { 6545 GET_DEVICES_INPUTS, 6546 GET_DEVICES_OUTPUTS } 6547 ) 6548 @Retention(RetentionPolicy.SOURCE) 6549 public @interface AudioDeviceRole {} 6550 6551 /** 6552 * Specifies to the {@link AudioManager#getDevices(int)} method to include both 6553 * source and sink devices. 6554 */ 6555 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS; 6556 6557 /** 6558 * Determines if a given AudioDevicePort meets the specified filter criteria. 6559 * @param port The port to test. 6560 * @param flags A set of bitflags specifying the criteria to test. 6561 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS} 6562 **/ checkFlags(AudioDevicePort port, int flags)6563 private static boolean checkFlags(AudioDevicePort port, int flags) { 6564 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 || 6565 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; 6566 } 6567 checkTypes(AudioDevicePort port)6568 private static boolean checkTypes(AudioDevicePort port) { 6569 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != 6570 AudioDeviceInfo.TYPE_UNKNOWN; 6571 } 6572 6573 /** 6574 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices 6575 * currently connected to the system and meeting the criteria specified in the 6576 * <code>flags</code> parameter. 6577 * @param flags A set of bitflags specifying the criteria to test. 6578 * @see #GET_DEVICES_OUTPUTS 6579 * @see #GET_DEVICES_INPUTS 6580 * @see #GET_DEVICES_ALL 6581 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 6582 */ getDevices(@udioDeviceRole int flags)6583 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) { 6584 return getDevicesStatic(flags); 6585 } 6586 6587 /** 6588 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo 6589 * objects from the current (internal) AudioDevicePort list. 6590 */ 6591 private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)6592 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { 6593 6594 // figure out how many AudioDeviceInfo we need space for... 6595 int numRecs = 0; 6596 for (AudioDevicePort port : ports) { 6597 if (checkTypes(port) && checkFlags(port, flags)) { 6598 numRecs++; 6599 } 6600 } 6601 6602 // Now load them up... 6603 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; 6604 int slot = 0; 6605 for (AudioDevicePort port : ports) { 6606 if (checkTypes(port) && checkFlags(port, flags)) { 6607 deviceList[slot++] = new AudioDeviceInfo(port); 6608 } 6609 } 6610 6611 return deviceList; 6612 } 6613 6614 /* 6615 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by 6616 * the add/remove callback mechanism to provide a list of the newly added or removed devices 6617 * rather than the whole list and make the app figure it out. 6618 * Note that calling this method with: 6619 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. 6620 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. 6621 */ calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)6622 private static AudioDeviceInfo[] calcListDeltas( 6623 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { 6624 6625 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>(); 6626 6627 AudioDevicePort cur_port = null; 6628 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) { 6629 boolean cur_port_found = false; 6630 cur_port = ports_B.get(cur_index); 6631 for (int prev_index = 0; 6632 prev_index < ports_A.size() && !cur_port_found; 6633 prev_index++) { 6634 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id()); 6635 } 6636 6637 if (!cur_port_found) { 6638 delta_ports.add(cur_port); 6639 } 6640 } 6641 6642 return infoListFromPortList(delta_ports, flags); 6643 } 6644 6645 /** 6646 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently 6647 * connected to the system and meeting the criteria specified in the <code>flags</code> 6648 * parameter. 6649 * This is an internal function. The public API front is getDevices(int). 6650 * @param flags A set of bitflags specifying the criteria to test. 6651 * @see #GET_DEVICES_OUTPUTS 6652 * @see #GET_DEVICES_INPUTS 6653 * @see #GET_DEVICES_ALL 6654 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 6655 * @hide 6656 */ getDevicesStatic(int flags)6657 public static AudioDeviceInfo[] getDevicesStatic(int flags) { 6658 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>(); 6659 int status = AudioManager.listAudioDevicePorts(ports); 6660 if (status != AudioManager.SUCCESS) { 6661 // fail and bail! 6662 return new AudioDeviceInfo[0]; // Always return an array. 6663 } 6664 6665 return infoListFromPortList(ports, flags); 6666 } 6667 6668 /** 6669 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID. 6670 * @param portId The audio port ID to look up for. 6671 * @param flags A set of bitflags specifying the criteria to test. 6672 * @see #GET_DEVICES_OUTPUTS 6673 * @see #GET_DEVICES_INPUTS 6674 * @see #GET_DEVICES_ALL 6675 * @return An AudioDeviceInfo or null if no device with matching port ID is found. 6676 * @hide 6677 */ getDeviceForPortId(int portId, int flags)6678 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) { 6679 if (portId == 0) { 6680 return null; 6681 } 6682 AudioDeviceInfo[] devices = getDevicesStatic(flags); 6683 for (AudioDeviceInfo device : devices) { 6684 if (device.getId() == portId) { 6685 return device; 6686 } 6687 } 6688 return null; 6689 } 6690 6691 /** 6692 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes 6693 * to the set of connected audio devices. 6694 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect 6695 * notifications. 6696 * @param handler Specifies the {@link Handler} object for the thread on which to execute 6697 * the callback. If <code>null</code>, the {@link Handler} associated with the main 6698 * {@link Looper} will be used. 6699 */ registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)6700 public void registerAudioDeviceCallback(AudioDeviceCallback callback, 6701 @Nullable Handler handler) { 6702 synchronized (mDeviceCallbacks) { 6703 if (callback != null && !mDeviceCallbacks.containsKey(callback)) { 6704 if (mDeviceCallbacks.size() == 0) { 6705 if (mPortListener == null) { 6706 mPortListener = new OnAmPortUpdateListener(); 6707 } 6708 registerAudioPortUpdateListener(mPortListener); 6709 } 6710 NativeEventHandlerDelegate delegate = 6711 new NativeEventHandlerDelegate(callback, handler); 6712 mDeviceCallbacks.put(callback, delegate); 6713 broadcastDeviceListChange_sync(delegate.getHandler()); 6714 } 6715 } 6716 } 6717 6718 /** 6719 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered 6720 * to receive notifications of changes to the set of connected audio devices. 6721 * @param callback The {@link AudioDeviceCallback} object that was previously registered 6722 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered. 6723 */ unregisterAudioDeviceCallback(AudioDeviceCallback callback)6724 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { 6725 synchronized (mDeviceCallbacks) { 6726 if (mDeviceCallbacks.containsKey(callback)) { 6727 mDeviceCallbacks.remove(callback); 6728 if (mDeviceCallbacks.size() == 0) { 6729 unregisterAudioPortUpdateListener(mPortListener); 6730 } 6731 } 6732 } 6733 } 6734 6735 /** 6736 * Set port id for microphones by matching device type and address. 6737 * @hide 6738 */ setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)6739 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) { 6740 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 6741 for (int i = microphones.size() - 1; i >= 0; i--) { 6742 boolean foundPortId = false; 6743 for (AudioDeviceInfo device : devices) { 6744 if (device.getPort().type() == microphones.get(i).getInternalDeviceType() 6745 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) { 6746 microphones.get(i).setId(device.getId()); 6747 foundPortId = true; 6748 break; 6749 } 6750 } 6751 if (!foundPortId) { 6752 Log.i(TAG, "Failed to find port id for device with type:" 6753 + microphones.get(i).getType() + " address:" 6754 + microphones.get(i).getAddress()); 6755 microphones.remove(i); 6756 } 6757 } 6758 } 6759 6760 /** 6761 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}. 6762 * @hide 6763 */ microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)6764 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) { 6765 int deviceType = deviceInfo.getType(); 6766 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC 6767 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY 6768 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN 6769 : MicrophoneInfo.LOCATION_PERIPHERAL; 6770 MicrophoneInfo microphone = new MicrophoneInfo( 6771 deviceInfo.getPort().name() + deviceInfo.getId(), 6772 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation, 6773 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN, 6774 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN, 6775 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(), 6776 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN, 6777 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN); 6778 microphone.setId(deviceInfo.getId()); 6779 return microphone; 6780 } 6781 6782 /** 6783 * Add {@link MicrophoneInfo} by device information while filtering certain types. 6784 */ addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)6785 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, 6786 HashSet<Integer> filterTypes) { 6787 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS); 6788 for (AudioDeviceInfo device : devices) { 6789 if (filterTypes.contains(device.getType())) { 6790 continue; 6791 } 6792 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device); 6793 microphones.add(microphone); 6794 } 6795 } 6796 6797 /** 6798 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics 6799 * of all available microphones. The list is empty when no microphones are available 6800 * on the device. An error during the query will result in an IOException being thrown. 6801 * 6802 * @return a list that contains all microphones' characteristics 6803 * @throws IOException if an error occurs. 6804 */ getMicrophones()6805 public List<MicrophoneInfo> getMicrophones() throws IOException { 6806 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>(); 6807 int status = AudioSystem.getMicrophones(microphones); 6808 HashSet<Integer> filterTypes = new HashSet<>(); 6809 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY); 6810 if (status != AudioManager.SUCCESS) { 6811 // fail and populate microphones with unknown characteristics by device information. 6812 if (status != AudioManager.ERROR_INVALID_OPERATION) { 6813 Log.e(TAG, "getMicrophones failed:" + status); 6814 } 6815 Log.i(TAG, "fallback on device info"); 6816 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 6817 return microphones; 6818 } 6819 setPortIdForMicrophones(microphones); 6820 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); 6821 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 6822 return microphones; 6823 } 6824 6825 /** 6826 * Returns a list of audio formats that corresponds to encoding formats 6827 * supported on offload path for A2DP playback. 6828 * 6829 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats 6830 * supported for offload A2DP playback 6831 * @hide 6832 */ getHwOffloadEncodingFormatsSupportedForA2DP()6833 public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() { 6834 ArrayList<Integer> formatsList = new ArrayList<Integer>(); 6835 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>(); 6836 6837 int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList); 6838 if (status != AudioManager.SUCCESS) { 6839 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status); 6840 return codecConfigList; 6841 } 6842 6843 for (Integer format : formatsList) { 6844 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); 6845 if (btSourceCodec 6846 != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 6847 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec)); 6848 } 6849 } 6850 return codecConfigList; 6851 } 6852 6853 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the 6854 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list 6855 // of the ports that exist at the time of the last notification. 6856 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>(); 6857 6858 /** 6859 * Internal method to compute and generate add/remove messages and then send to any 6860 * registered callbacks. Must be called synchronized on mDeviceCallbacks. 6861 */ broadcastDeviceListChange_sync(Handler handler)6862 private void broadcastDeviceListChange_sync(Handler handler) { 6863 int status; 6864 6865 // Get the new current set of ports 6866 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>(); 6867 status = AudioManager.listAudioDevicePorts(current_ports); 6868 if (status != AudioManager.SUCCESS) { 6869 return; 6870 } 6871 6872 if (handler != null) { 6873 // This is the callback for the registration, so send the current list 6874 AudioDeviceInfo[] deviceList = 6875 infoListFromPortList(current_ports, GET_DEVICES_ALL); 6876 handler.sendMessage( 6877 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList)); 6878 } else { 6879 AudioDeviceInfo[] added_devices = 6880 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL); 6881 AudioDeviceInfo[] removed_devices = 6882 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL); 6883 if (added_devices.length != 0 || removed_devices.length != 0) { 6884 for (int i = 0; i < mDeviceCallbacks.size(); i++) { 6885 handler = mDeviceCallbacks.valueAt(i).getHandler(); 6886 if (handler != null) { 6887 if (removed_devices.length != 0) { 6888 handler.sendMessage(Message.obtain(handler, 6889 MSG_DEVICES_DEVICES_REMOVED, 6890 removed_devices)); 6891 } 6892 if (added_devices.length != 0) { 6893 handler.sendMessage(Message.obtain(handler, 6894 MSG_DEVICES_DEVICES_ADDED, 6895 added_devices)); 6896 } 6897 } 6898 } 6899 } 6900 } 6901 6902 mPreviousPorts = current_ports; 6903 } 6904 6905 /** 6906 * Handles Port list update notifications from the AudioManager 6907 */ 6908 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener { 6909 static final String TAG = "OnAmPortUpdateListener"; onAudioPortListUpdate(AudioPort[] portList)6910 public void onAudioPortListUpdate(AudioPort[] portList) { 6911 synchronized (mDeviceCallbacks) { 6912 broadcastDeviceListChange_sync(null); 6913 } 6914 } 6915 6916 /** 6917 * Callback method called upon audio patch list update. 6918 * Note: We don't do anything with Patches at this time, so ignore this notification. 6919 * @param patchList the updated list of audio patches. 6920 */ onAudioPatchListUpdate(AudioPatch[] patchList)6921 public void onAudioPatchListUpdate(AudioPatch[] patchList) {} 6922 6923 /** 6924 * Callback method called when the mediaserver dies 6925 */ onServiceDied()6926 public void onServiceDied() { 6927 synchronized (mDeviceCallbacks) { 6928 broadcastDeviceListChange_sync(null); 6929 } 6930 } 6931 } 6932 6933 6934 /** 6935 * @hide 6936 * Abstract class to receive event notification about audioserver process state. 6937 */ 6938 @SystemApi 6939 public abstract static class AudioServerStateCallback { onAudioServerDown()6940 public void onAudioServerDown() { } onAudioServerUp()6941 public void onAudioServerUp() { } 6942 } 6943 6944 private Executor mAudioServerStateExec; 6945 private AudioServerStateCallback mAudioServerStateCb; 6946 private final Object mAudioServerStateCbLock = new Object(); 6947 6948 private final IAudioServerStateDispatcher mAudioServerStateDispatcher = 6949 new IAudioServerStateDispatcher.Stub() { 6950 @Override 6951 public void dispatchAudioServerStateChange(boolean state) { 6952 Executor exec; 6953 AudioServerStateCallback cb; 6954 6955 synchronized (mAudioServerStateCbLock) { 6956 exec = mAudioServerStateExec; 6957 cb = mAudioServerStateCb; 6958 } 6959 6960 if ((exec == null) || (cb == null)) { 6961 return; 6962 } 6963 if (state) { 6964 exec.execute(() -> cb.onAudioServerUp()); 6965 } else { 6966 exec.execute(() -> cb.onAudioServerDown()); 6967 } 6968 } 6969 }; 6970 6971 /** 6972 * @hide 6973 * Registers a callback for notification of audio server state changes. 6974 * @param executor {@link Executor} to handle the callbacks 6975 * @param stateCallback the callback to receive the audio server state changes 6976 * To remove the callabck, pass a null reference for both executor and stateCallback. 6977 */ 6978 @SystemApi setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)6979 public void setAudioServerStateCallback(@NonNull Executor executor, 6980 @NonNull AudioServerStateCallback stateCallback) { 6981 if (stateCallback == null) { 6982 throw new IllegalArgumentException("Illegal null AudioServerStateCallback"); 6983 } 6984 if (executor == null) { 6985 throw new IllegalArgumentException( 6986 "Illegal null Executor for the AudioServerStateCallback"); 6987 } 6988 6989 synchronized (mAudioServerStateCbLock) { 6990 if (mAudioServerStateCb != null) { 6991 throw new IllegalStateException( 6992 "setAudioServerStateCallback called with already registered callabck"); 6993 } 6994 final IAudioService service = getService(); 6995 try { 6996 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher); 6997 } catch (RemoteException e) { 6998 throw e.rethrowFromSystemServer(); 6999 } 7000 mAudioServerStateExec = executor; 7001 mAudioServerStateCb = stateCallback; 7002 } 7003 } 7004 7005 /** 7006 * @hide 7007 * Unregisters the callback for notification of audio server state changes. 7008 */ 7009 @SystemApi clearAudioServerStateCallback()7010 public void clearAudioServerStateCallback() { 7011 synchronized (mAudioServerStateCbLock) { 7012 if (mAudioServerStateCb != null) { 7013 final IAudioService service = getService(); 7014 try { 7015 service.unregisterAudioServerStateDispatcher( 7016 mAudioServerStateDispatcher); 7017 } catch (RemoteException e) { 7018 throw e.rethrowFromSystemServer(); 7019 } 7020 } 7021 mAudioServerStateExec = null; 7022 mAudioServerStateCb = null; 7023 } 7024 } 7025 7026 /** 7027 * @hide 7028 * Checks if native audioservice is running or not. 7029 * @return true if native audioservice runs, false otherwise. 7030 */ 7031 @SystemApi isAudioServerRunning()7032 public boolean isAudioServerRunning() { 7033 final IAudioService service = getService(); 7034 try { 7035 return service.isAudioServerRunning(); 7036 } catch (RemoteException e) { 7037 throw e.rethrowFromSystemServer(); 7038 } 7039 } 7040 7041 /** 7042 * Sets the surround sound mode. 7043 * 7044 * @return true if successful, otherwise false 7045 */ 7046 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)7047 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) { 7048 try { 7049 return getService().setEncodedSurroundMode(mode); 7050 } catch (RemoteException e) { 7051 throw e.rethrowFromSystemServer(); 7052 } 7053 } 7054 7055 /** 7056 * Gets the surround sound mode. 7057 * 7058 * @return true if successful, otherwise false 7059 */ getEncodedSurroundMode()7060 public @EncodedSurroundOutputMode int getEncodedSurroundMode() { 7061 try { 7062 return getService().getEncodedSurroundMode( 7063 getContext().getApplicationInfo().targetSdkVersion); 7064 } catch (RemoteException e) { 7065 throw e.rethrowFromSystemServer(); 7066 } 7067 } 7068 7069 /** 7070 * @hide 7071 * Returns all surround formats. 7072 * @return a map where the key is a surround format and 7073 * the value indicates the surround format is enabled or not 7074 */ 7075 @TestApi 7076 @NonNull getSurroundFormats()7077 public Map<Integer, Boolean> getSurroundFormats() { 7078 try { 7079 return getService().getSurroundFormats(); 7080 } catch (RemoteException e) { 7081 throw e.rethrowFromSystemServer(); 7082 } 7083 } 7084 7085 /** 7086 * Sets and persists a certain surround format as enabled or not. 7087 * <p> 7088 * This API is called by TvSettings surround sound menu when user enables or disables a 7089 * surround sound format. This setting is persisted as global user setting. 7090 * Applications should revert their changes to surround sound settings unless they intend to 7091 * modify the global user settings across all apps. The framework does not auto-revert an 7092 * application's settings after a lifecycle event. Audio focus is not required to apply these 7093 * settings. 7094 * 7095 * @param enabled the required surround format state, true for enabled, false for disabled 7096 * @return true if successful, otherwise false 7097 */ 7098 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)7099 public boolean setSurroundFormatEnabled( 7100 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { 7101 try { 7102 return getService().setSurroundFormatEnabled(audioFormat, enabled); 7103 } catch (RemoteException e) { 7104 throw e.rethrowFromSystemServer(); 7105 } 7106 } 7107 7108 /** 7109 * Gets whether a certain surround format is enabled or not. 7110 * @param audioFormat a surround format 7111 * 7112 * @return whether the required surround format is enabled 7113 */ isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)7114 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) { 7115 try { 7116 return getService().isSurroundFormatEnabled(audioFormat); 7117 } catch (RemoteException e) { 7118 throw e.rethrowFromSystemServer(); 7119 } 7120 } 7121 7122 /** 7123 * @hide 7124 * Returns all surround formats that are reported by the connected HDMI device. 7125 * The return values are not affected by calling setSurroundFormatEnabled. 7126 * 7127 * @return a list of surround formats 7128 */ 7129 @TestApi 7130 @NonNull getReportedSurroundFormats()7131 public List<Integer> getReportedSurroundFormats() { 7132 try { 7133 return getService().getReportedSurroundFormats(); 7134 } catch (RemoteException e) { 7135 throw e.rethrowFromSystemServer(); 7136 } 7137 } 7138 7139 /** 7140 * Return if audio haptic coupled playback is supported or not. 7141 * 7142 * @return whether audio haptic playback supported. 7143 */ isHapticPlaybackSupported()7144 public static boolean isHapticPlaybackSupported() { 7145 return AudioSystem.isHapticPlaybackSupported(); 7146 } 7147 7148 /** 7149 * @hide 7150 * Introspection API to retrieve audio product strategies. 7151 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 7152 * audio product strategies, which is indexed by a weakly typed index in order to be extended 7153 * by OEM without any needs of AOSP patches. 7154 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product 7155 * strategy refered either by its index or human readable string. It will allow clients 7156 * application to start streaming data using these {@link AudioAttributes} on the selected 7157 * device by Audio Policy Engine. 7158 * @return a (possibly zero-length) array of 7159 * {@see android.media.audiopolicy.AudioProductStrategy} objects. 7160 */ 7161 @SystemApi 7162 @NonNull 7163 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioProductStrategies()7164 public static List<AudioProductStrategy> getAudioProductStrategies() { 7165 final IAudioService service = getService(); 7166 try { 7167 return service.getAudioProductStrategies(); 7168 } catch (RemoteException e) { 7169 throw e.rethrowFromSystemServer(); 7170 } 7171 } 7172 7173 /** 7174 * @hide 7175 * Introspection API to retrieve audio volume groups. 7176 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 7177 * audio volume groups. 7178 * @return a (possibly zero-length) List of 7179 * {@see android.media.audiopolicy.AudioVolumeGroup} objects. 7180 */ 7181 @SystemApi 7182 @NonNull 7183 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioVolumeGroups()7184 public static List<AudioVolumeGroup> getAudioVolumeGroups() { 7185 final IAudioService service = getService(); 7186 try { 7187 return service.getAudioVolumeGroups(); 7188 } catch (RemoteException e) { 7189 throw e.rethrowFromSystemServer(); 7190 } 7191 } 7192 7193 /** 7194 * @hide 7195 * Callback registered by client to be notified upon volume group change. 7196 */ 7197 @SystemApi 7198 public abstract static class VolumeGroupCallback { 7199 /** 7200 * Callback method called upon audio volume group change. 7201 * @param group the group for which the volume has changed 7202 */ onAudioVolumeGroupChanged(int group, int flags)7203 public void onAudioVolumeGroupChanged(int group, int flags) {} 7204 } 7205 7206 /** 7207 * @hide 7208 * Register an audio volume group change listener. 7209 * @param callback the {@link VolumeGroupCallback} to register 7210 */ 7211 @SystemApi registerVolumeGroupCallback( @onNull Executor executor, @NonNull VolumeGroupCallback callback)7212 public void registerVolumeGroupCallback( 7213 @NonNull Executor executor, 7214 @NonNull VolumeGroupCallback callback) { 7215 Preconditions.checkNotNull(executor, "executor must not be null"); 7216 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 7217 sAudioAudioVolumeGroupChangedHandler.init(); 7218 // TODO: make use of executor 7219 sAudioAudioVolumeGroupChangedHandler.registerListener(callback); 7220 } 7221 7222 /** 7223 * @hide 7224 * Unregister an audio volume group change listener. 7225 * @param callback the {@link VolumeGroupCallback} to unregister 7226 */ 7227 @SystemApi unregisterVolumeGroupCallback( @onNull VolumeGroupCallback callback)7228 public void unregisterVolumeGroupCallback( 7229 @NonNull VolumeGroupCallback callback) { 7230 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 7231 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback); 7232 } 7233 7234 /** 7235 * Return if an asset contains haptic channels or not. 7236 * 7237 * @param context the {@link Context} to resolve the uri. 7238 * @param uri the {@link Uri} of the asset. 7239 * @return true if the assert contains haptic channels. 7240 * @hide 7241 */ hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)7242 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) { 7243 MediaExtractor extractor = new MediaExtractor(); 7244 try { 7245 extractor.setDataSource(context, uri, null); 7246 for (int i = 0; i < extractor.getTrackCount(); i++) { 7247 MediaFormat format = extractor.getTrackFormat(i); 7248 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) 7249 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) { 7250 return true; 7251 } 7252 } 7253 } catch (IOException e) { 7254 Log.e(TAG, "hasHapticChannels failure:" + e); 7255 } 7256 return false; 7257 } 7258 7259 /** 7260 * Return if an asset contains haptic channels or not. 7261 * 7262 * @param context the {@link Context} to resolve the uri. 7263 * @param uri the {@link Uri} of the asset. 7264 * @return true if the assert contains haptic channels. 7265 * @hide 7266 */ hasHapticChannels(@ullable Context context, @NonNull Uri uri)7267 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) { 7268 Objects.requireNonNull(uri); 7269 7270 if (context != null) { 7271 return hasHapticChannelsImpl(context, uri); 7272 } 7273 7274 Context cachedContext = sContext.get(); 7275 if (cachedContext != null) { 7276 if (DEBUG) { 7277 Log.d(TAG, "Try to use static context to query if having haptic channels"); 7278 } 7279 return hasHapticChannelsImpl(cachedContext, uri); 7280 } 7281 7282 // Try with audio service context, this may fail to get correct result. 7283 if (DEBUG) { 7284 Log.d(TAG, "Try to use audio service context to query if having haptic channels"); 7285 } 7286 try { 7287 return getService().hasHapticChannels(uri); 7288 } catch (RemoteException e) { 7289 throw e.rethrowFromSystemServer(); 7290 } 7291 } 7292 7293 /** 7294 * Set whether or not there is an active RTT call. 7295 * This method should be called by Telecom service. 7296 * @hide 7297 * TODO: make this a @SystemApi 7298 */ setRttEnabled(boolean rttEnabled)7299 public static void setRttEnabled(boolean rttEnabled) { 7300 try { 7301 getService().setRttEnabled(rttEnabled); 7302 } catch (RemoteException e) { 7303 throw e.rethrowFromSystemServer(); 7304 } 7305 } 7306 7307 /** 7308 * Adjusts the volume of the most relevant stream, or the given fallback 7309 * stream. 7310 * <p> 7311 * This method should only be used by applications that replace the 7312 * platform-wide management of audio settings or the main telephony 7313 * application. 7314 * <p> 7315 * This method has no effect if the device implements a fixed volume policy 7316 * as indicated by {@link #isVolumeFixed()}. 7317 * <p>This API checks if the caller has the necessary permissions based on the provided 7318 * component name, uid, and pid values. 7319 * See {@link #adjustSuggestedStreamVolume(int, int, int)}. 7320 * 7321 * @param suggestedStreamType The stream type that will be used if there 7322 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 7323 * valid here. 7324 * @param direction The direction to adjust the volume. One of 7325 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 7326 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 7327 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 7328 * @param flags One or more flags. 7329 * @param packageName the package name of client application 7330 * @param uid the uid of client application 7331 * @param pid the pid of client application 7332 * @param targetSdkVersion the target sdk version of client application 7333 * @see #adjustVolume(int, int) 7334 * @see #adjustStreamVolume(int, int, int) 7335 * @see #setStreamVolume(int, int, int) 7336 * @see #isVolumeFixed() 7337 * 7338 * @hide 7339 */ 7340 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7341 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags, 7342 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7343 try { 7344 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags, 7345 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7346 } catch (RemoteException e) { 7347 throw e.rethrowFromSystemServer(); 7348 } 7349 } 7350 7351 /** 7352 * Adjusts the volume of a particular stream by one step in a direction. 7353 * <p> 7354 * This method should only be used by applications that replace the platform-wide 7355 * management of audio settings or the main telephony application. 7356 * <p>This method has no effect if the device implements a fixed volume policy 7357 * as indicated by {@link #isVolumeFixed()}. 7358 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 7359 * unless the app has been granted Do Not Disturb Access. 7360 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 7361 * <p>This API checks if the caller has the necessary permissions based on the provided 7362 * component name, uid, and pid values. 7363 * See {@link #adjustStreamVolume(int, int, int)}. 7364 * 7365 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 7366 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 7367 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 7368 * @param direction The direction to adjust the volume. One of 7369 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 7370 * {@link #ADJUST_SAME}. 7371 * @param flags One or more flags. 7372 * @param packageName the package name of client application 7373 * @param uid the uid of client application 7374 * @param pid the pid of client application 7375 * @param targetSdkVersion the target sdk version of client application 7376 * @see #adjustVolume(int, int) 7377 * @see #setStreamVolume(int, int, int) 7378 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 7379 * and the caller is not granted notification policy access. 7380 * 7381 * @hide 7382 */ 7383 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustStreamVolumeForUid(int streamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7384 public void adjustStreamVolumeForUid(int streamType, int direction, int flags, 7385 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7386 try { 7387 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid, 7388 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7389 } catch (RemoteException e) { 7390 throw e.rethrowFromSystemServer(); 7391 } 7392 } 7393 7394 /** 7395 * Sets the volume index for a particular stream. 7396 * <p>This method has no effect if the device implements a fixed volume policy 7397 * as indicated by {@link #isVolumeFixed()}. 7398 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 7399 * the app has been granted Do Not Disturb Access. 7400 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 7401 * <p>This API checks if the caller has the necessary permissions based on the provided 7402 * component name, uid, and pid values. 7403 * See {@link #setStreamVolume(int, int, int)}. 7404 * 7405 * @param streamType The stream whose volume index should be set. 7406 * @param index The volume index to set. See 7407 * {@link #getStreamMaxVolume(int)} for the largest valid value. 7408 * @param flags One or more flags. 7409 * @param packageName the package name of client application 7410 * @param uid the uid of client application 7411 * @param pid the pid of client application 7412 * @param targetSdkVersion the target sdk version of client application 7413 * @see #getStreamMaxVolume(int) 7414 * @see #getStreamVolume(int) 7415 * @see #isVolumeFixed() 7416 * @throws SecurityException if the volume change triggers a Do Not Disturb change 7417 * and the caller is not granted notification policy access. 7418 * 7419 * @hide 7420 */ 7421 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setStreamVolumeForUid(int streamType, int index, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7422 public void setStreamVolumeForUid(int streamType, int index, int flags, 7423 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7424 try { 7425 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid, 7426 UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7427 } catch (RemoteException e) { 7428 throw e.rethrowFromSystemServer(); 7429 } 7430 } 7431 7432 7433 /** @hide 7434 * TODO: make this a @SystemApi */ 7435 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setMultiAudioFocusEnabled(boolean enabled)7436 public void setMultiAudioFocusEnabled(boolean enabled) { 7437 try { 7438 getService().setMultiAudioFocusEnabled(enabled); 7439 } catch (RemoteException e) { 7440 throw e.rethrowFromSystemServer(); 7441 } 7442 } 7443 7444 7445 /** 7446 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID. 7447 * For more details on Hardware A/V synchronization please refer to 7448 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/"> 7449 * media tunneling documentation</a>. 7450 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved. 7451 * @return the HW A/V sync ID for this audio session (an integer different from 0). 7452 * @throws UnsupportedOperationException if HW A/V synchronization is not supported. 7453 */ getAudioHwSyncForSession(int sessionId)7454 public int getAudioHwSyncForSession(int sessionId) { 7455 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId); 7456 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) { 7457 throw new UnsupportedOperationException("HW A/V synchronization is not supported."); 7458 } 7459 return hwSyncId; 7460 } 7461 7462 /** 7463 * Selects the audio device that should be used for communication use cases, for instance voice 7464 * or video calls. This method can be used by voice or video chat applications to select a 7465 * different audio device than the one selected by default by the platform. 7466 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by 7467 * {@link #getAvailableCommunicationDevices()}. 7468 * The selection is active as long as the requesting application process lives, until 7469 * {@link #clearCommunicationDevice} is called or until the device is disconnected. 7470 * It is therefore important for applications to clear the request when a call ends or the 7471 * the requesting activity or service is stopped or destroyed. 7472 * <p>In case of simultaneous requests by multiple applications the priority is given to the 7473 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the 7474 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode 7475 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main 7476 * telephony application with permission 7477 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}. 7478 * <p> If the requested devices is not currently available, the request will be rejected and 7479 * the method will return false. 7480 * <p>This API replaces the following deprecated APIs: 7481 * <ul> 7482 * <li> {@link #startBluetoothSco()} 7483 * <li> {@link #stopBluetoothSco()} 7484 * <li> {@link #setSpeakerphoneOn(boolean)} 7485 * </ul> 7486 * <h4>Example</h4> 7487 * <p>The example below shows how to enable and disable speakerphone mode. 7488 * <pre class="prettyprint"> 7489 * // Get an AudioManager instance 7490 * AudioManager audioManager = Context.getSystemService(AudioManager.class); 7491 * AudioDeviceInfo speakerDevice = null; 7492 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); 7493 * for (AudioDeviceInfo device : devices) { 7494 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { 7495 * speakerDevice = device; 7496 * break; 7497 * } 7498 * } 7499 * if (speakerDevice != null) { 7500 * // Turn speakerphone ON. 7501 * boolean result = audioManager.setCommunicationDevice(speakerDevice); 7502 * if (!result) { 7503 * // Handle error. 7504 * } 7505 * // Turn speakerphone OFF. 7506 * audioManager.clearCommunicationDevice(); 7507 * } 7508 * </pre> 7509 * @param device the requested audio device. 7510 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. 7511 * @throws IllegalArgumentException If an invalid device is specified. 7512 */ setCommunicationDevice(@onNull AudioDeviceInfo device)7513 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { 7514 Objects.requireNonNull(device); 7515 try { 7516 if (device.getId() == 0) { 7517 throw new IllegalArgumentException("In valid device: " + device); 7518 } 7519 return getService().setCommunicationDevice(mICallBack, device.getId()); 7520 } catch (RemoteException e) { 7521 throw e.rethrowFromSystemServer(); 7522 } 7523 } 7524 7525 /** 7526 * Cancels previous communication device selection made with 7527 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 7528 */ clearCommunicationDevice()7529 public void clearCommunicationDevice() { 7530 try { 7531 getService().setCommunicationDevice(mICallBack, 0); 7532 } catch (RemoteException e) { 7533 throw e.rethrowFromSystemServer(); 7534 } 7535 } 7536 7537 /** 7538 * Returns currently selected audio device for communication. 7539 * <p>This API replaces the following deprecated APIs: 7540 * <ul> 7541 * <li> {@link #isBluetoothScoOn()} 7542 * <li> {@link #isSpeakerphoneOn()} 7543 * </ul> 7544 * @return an {@link AudioDeviceInfo} indicating which audio device is 7545 * currently selected for communication use cases. Can be null on platforms 7546 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 7547 * is used. 7548 */ 7549 @Nullable getCommunicationDevice()7550 public AudioDeviceInfo getCommunicationDevice() { 7551 try { 7552 return getDeviceForPortId( 7553 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); 7554 } catch (RemoteException e) { 7555 throw e.rethrowFromSystemServer(); 7556 } 7557 } 7558 7559 /** 7560 * Returns a list of audio devices that can be selected for communication use cases via 7561 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 7562 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). 7563 */ 7564 @NonNull getAvailableCommunicationDevices()7565 public List<AudioDeviceInfo> getAvailableCommunicationDevices() { 7566 try { 7567 ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); 7568 int[] portIds = getService().getAvailableCommunicationDeviceIds(); 7569 for (int portId : portIds) { 7570 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 7571 if (device == null) { 7572 continue; 7573 } 7574 devices.add(device); 7575 } 7576 return devices; 7577 } catch (RemoteException e) { 7578 throw e.rethrowFromSystemServer(); 7579 } 7580 } 7581 7582 /** 7583 * @hide 7584 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided. 7585 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 7586 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 7587 * The method will return null if no device of the provided type is connected. 7588 * If more than one device of the provided type is connected, an object corresponding to the 7589 * first device encountered in the enumeration list will be returned. 7590 * @param deviceType The device device for which an <code>AudioDeviceInfo</code> 7591 * object is queried. 7592 * @return An AudioDeviceInfo object or null if no device with the requested type is connected. 7593 * @throws IllegalArgumentException If an invalid device type is specified. 7594 */ 7595 @TestApi 7596 @Nullable getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)7597 public static AudioDeviceInfo getDeviceInfoFromType( 7598 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 7599 return getDeviceInfoFromTypeAndAddress(deviceType, null); 7600 } 7601 7602 /** 7603 * @hide 7604 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and 7605 * address provided. 7606 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 7607 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 7608 * If a null address is provided, the matching will happen on the type only. 7609 * The method will return null if no device of the provided type and address is connected. 7610 * If more than one device of the provided type is connected, an object corresponding to the 7611 * first device encountered in the enumeration list will be returned. 7612 * @param type The device device for which an <code>AudioDeviceInfo</code> 7613 * object is queried. 7614 * @param address The device address for which an <code>AudioDeviceInfo</code> 7615 * object is queried or null if requesting match on type only. 7616 * @return An AudioDeviceInfo object or null if no matching device is connected. 7617 * @throws IllegalArgumentException If an invalid device type is specified. 7618 */ 7619 @Nullable getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)7620 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( 7621 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { 7622 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); 7623 AudioDeviceInfo deviceForType = null; 7624 for (AudioDeviceInfo device : devices) { 7625 if (device.getType() == type) { 7626 deviceForType = device; 7627 if (address == null || address.equals(device.getAddress())) { 7628 return device; 7629 } 7630 } 7631 } 7632 return deviceForType; 7633 } 7634 7635 /** 7636 * Listener registered by client to be notified upon communication audio device change. 7637 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7638 */ 7639 public interface OnCommunicationDeviceChangedListener { 7640 /** 7641 * Callback method called upon communication audio device change. 7642 * @param device the audio device requested for communication use cases. 7643 * Can be null on platforms not supporting 7644 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 7645 */ onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)7646 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); 7647 } 7648 7649 /** 7650 * Adds a listener for being notified of changes to the communication audio device. 7651 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7652 * @param executor 7653 * @param listener 7654 */ addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)7655 public void addOnCommunicationDeviceChangedListener( 7656 @NonNull @CallbackExecutor Executor executor, 7657 @NonNull OnCommunicationDeviceChangedListener listener) { 7658 Objects.requireNonNull(executor); 7659 Objects.requireNonNull(listener); 7660 synchronized (mCommDevListenerLock) { 7661 if (hasCommDevListener(listener)) { 7662 throw new IllegalArgumentException( 7663 "attempt to call addOnCommunicationDeviceChangedListener() " 7664 + "on a previously registered listener"); 7665 } 7666 // lazy initialization of the list of strategy-preferred device listener 7667 if (mCommDevListeners == null) { 7668 mCommDevListeners = new ArrayList<>(); 7669 } 7670 final int oldCbCount = mCommDevListeners.size(); 7671 mCommDevListeners.add(new CommDevListenerInfo(listener, executor)); 7672 if (oldCbCount == 0 && mCommDevListeners.size() > 0) { 7673 // register binder for callbacks 7674 if (mCommDevDispatcherStub == null) { 7675 mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub(); 7676 } 7677 try { 7678 getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub); 7679 } catch (RemoteException e) { 7680 throw e.rethrowFromSystemServer(); 7681 } 7682 } 7683 } 7684 } 7685 7686 /** 7687 * Removes a previously added listener of changes to the communication audio device. 7688 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7689 * @param listener 7690 */ removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)7691 public void removeOnCommunicationDeviceChangedListener( 7692 @NonNull OnCommunicationDeviceChangedListener listener) { 7693 Objects.requireNonNull(listener); 7694 synchronized (mCommDevListenerLock) { 7695 if (!removeCommDevListener(listener)) { 7696 throw new IllegalArgumentException( 7697 "attempt to call removeOnCommunicationDeviceChangedListener() " 7698 + "on an unregistered listener"); 7699 } 7700 if (mCommDevListeners.size() == 0) { 7701 // unregister binder for callbacks 7702 try { 7703 getService().unregisterCommunicationDeviceDispatcher( 7704 mCommDevDispatcherStub); 7705 } catch (RemoteException e) { 7706 throw e.rethrowFromSystemServer(); 7707 } finally { 7708 mCommDevDispatcherStub = null; 7709 mCommDevListeners = null; 7710 } 7711 } 7712 } 7713 } 7714 7715 private final Object mCommDevListenerLock = new Object(); 7716 /** 7717 * List of listeners for preferred device for strategy and their associated Executor. 7718 * List is lazy-initialized on first registration 7719 */ 7720 @GuardedBy("mCommDevListenerLock") 7721 private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners; 7722 7723 private static class CommDevListenerInfo { 7724 final @NonNull OnCommunicationDeviceChangedListener mListener; 7725 final @NonNull Executor mExecutor; 7726 CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe)7727 CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) { 7728 mListener = listener; 7729 mExecutor = exe; 7730 } 7731 } 7732 7733 @GuardedBy("mCommDevListenerLock") 7734 private CommunicationDeviceDispatcherStub mCommDevDispatcherStub; 7735 7736 private final class CommunicationDeviceDispatcherStub 7737 extends ICommunicationDeviceDispatcher.Stub { 7738 7739 @Override dispatchCommunicationDeviceChanged(int portId)7740 public void dispatchCommunicationDeviceChanged(int portId) { 7741 // make a shallow copy of listeners so callback is not executed under lock 7742 final ArrayList<CommDevListenerInfo> commDevListeners; 7743 synchronized (mCommDevListenerLock) { 7744 if (mCommDevListeners == null || mCommDevListeners.size() == 0) { 7745 return; 7746 } 7747 commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone(); 7748 } 7749 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 7750 final long ident = Binder.clearCallingIdentity(); 7751 try { 7752 for (CommDevListenerInfo info : commDevListeners) { 7753 info.mExecutor.execute(() -> 7754 info.mListener.onCommunicationDeviceChanged(device)); 7755 } 7756 } finally { 7757 Binder.restoreCallingIdentity(ident); 7758 } 7759 } 7760 } 7761 7762 @GuardedBy("mCommDevListenerLock") getCommDevListenerInfo( OnCommunicationDeviceChangedListener listener)7763 private @Nullable CommDevListenerInfo getCommDevListenerInfo( 7764 OnCommunicationDeviceChangedListener listener) { 7765 if (mCommDevListeners == null) { 7766 return null; 7767 } 7768 for (CommDevListenerInfo info : mCommDevListeners) { 7769 if (info.mListener == listener) { 7770 return info; 7771 } 7772 } 7773 return null; 7774 } 7775 7776 @GuardedBy("mCommDevListenerLock") hasCommDevListener(OnCommunicationDeviceChangedListener listener)7777 private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) { 7778 return getCommDevListenerInfo(listener) != null; 7779 } 7780 7781 @GuardedBy("mCommDevListenerLock") 7782 /** 7783 * @return true if the listener was removed from the list 7784 */ removeCommDevListener(OnCommunicationDeviceChangedListener listener)7785 private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) { 7786 final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener); 7787 if (infoToRemove != null) { 7788 mCommDevListeners.remove(infoToRemove); 7789 return true; 7790 } 7791 return false; 7792 } 7793 7794 //--------------------------------------------------------- 7795 // Inner classes 7796 //-------------------- 7797 /** 7798 * Helper class to handle the forwarding of native events to the appropriate listener 7799 * (potentially) handled in a different thread. 7800 */ 7801 private class NativeEventHandlerDelegate { 7802 private final Handler mHandler; 7803 NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)7804 NativeEventHandlerDelegate(final AudioDeviceCallback callback, 7805 Handler handler) { 7806 // find the looper for our new event handler 7807 Looper looper; 7808 if (handler != null) { 7809 looper = handler.getLooper(); 7810 } else { 7811 // no given handler, use the looper the addListener call was called in 7812 looper = Looper.getMainLooper(); 7813 } 7814 7815 // construct the event handler with this looper 7816 if (looper != null) { 7817 // implement the event handler delegate 7818 mHandler = new Handler(looper) { 7819 @Override 7820 public void handleMessage(Message msg) { 7821 switch(msg.what) { 7822 case MSG_DEVICES_CALLBACK_REGISTERED: 7823 case MSG_DEVICES_DEVICES_ADDED: 7824 if (callback != null) { 7825 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj); 7826 } 7827 break; 7828 7829 case MSG_DEVICES_DEVICES_REMOVED: 7830 if (callback != null) { 7831 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj); 7832 } 7833 break; 7834 7835 default: 7836 Log.e(TAG, "Unknown native event type: " + msg.what); 7837 break; 7838 } 7839 } 7840 }; 7841 } else { 7842 mHandler = null; 7843 } 7844 } 7845 getHandler()7846 Handler getHandler() { 7847 return mHandler; 7848 } 7849 } 7850 } 7851