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, "FLAG_SHOW_UI")638 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI"); FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES")639 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES"); FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND")640 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND"); FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE")641 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE"); FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE")642 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE"); FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME")643 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME"); FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME")644 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME"); FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT")645 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT"); FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME")646 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME"); FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY")647 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY"); FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS")648 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS"); FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT")649 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT"); FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY")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 private 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 // Bluetooth SCO control 2443 /** 2444 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2445 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE} 2446 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED} 2447 * or {@link #SCO_AUDIO_STATE_CONNECTED} 2448 * 2449 * @see #startBluetoothSco() 2450 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead 2451 */ 2452 @Deprecated 2453 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2454 public static final String ACTION_SCO_AUDIO_STATE_CHANGED = 2455 "android.media.SCO_AUDIO_STATE_CHANGED"; 2456 2457 /** 2458 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 2459 * connection state has been updated. 2460 * <p>This intent has two extras: 2461 * <ul> 2462 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li> 2463 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li> 2464 * </ul> 2465 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of: 2466 * <ul> 2467 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li> 2468 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li> 2469 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li> 2470 * </ul> 2471 * @see #startBluetoothSco() 2472 */ 2473 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2474 public static final String ACTION_SCO_AUDIO_STATE_UPDATED = 2475 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; 2476 2477 /** 2478 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or 2479 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state. 2480 */ 2481 public static final String EXTRA_SCO_AUDIO_STATE = 2482 "android.media.extra.SCO_AUDIO_STATE"; 2483 2484 /** 2485 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous 2486 * bluetooth SCO connection state. 2487 */ 2488 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = 2489 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"; 2490 2491 /** 2492 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 2493 * indicating that the SCO audio channel is not established 2494 */ 2495 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; 2496 /** 2497 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE} 2498 * indicating that the SCO audio channel is established 2499 */ 2500 public static final int SCO_AUDIO_STATE_CONNECTED = 1; 2501 /** 2502 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 2503 * indicating that the SCO audio channel is being established 2504 */ 2505 public static final int SCO_AUDIO_STATE_CONNECTING = 2; 2506 /** 2507 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that 2508 * there was an error trying to obtain the state 2509 */ 2510 public static final int SCO_AUDIO_STATE_ERROR = -1; 2511 2512 2513 /** 2514 * Indicates if current platform supports use of SCO for off call use cases. 2515 * Application wanted to use bluetooth SCO audio when the phone is not in call 2516 * must first call this method to make sure that the platform supports this 2517 * feature. 2518 * @return true if bluetooth SCO can be used for audio when not in call 2519 * false otherwise 2520 * @see #startBluetoothSco() 2521 */ isBluetoothScoAvailableOffCall()2522 public boolean isBluetoothScoAvailableOffCall() { 2523 return getContext().getResources().getBoolean( 2524 com.android.internal.R.bool.config_bluetooth_sco_off_call); 2525 } 2526 2527 /** 2528 * Start bluetooth SCO audio connection. 2529 * <p>Requires Permission: 2530 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2531 * <p>This method can be used by applications wanting to send and received audio 2532 * to/from a bluetooth SCO headset while the phone is not in call. 2533 * <p>As the SCO connection establishment can take several seconds, 2534 * applications should not rely on the connection to be available when the method 2535 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} 2536 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}. 2537 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO 2538 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver 2539 * registration. If the state is already CONNECTED, no state change will be received via the 2540 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco() 2541 * so that the connection stays active in case the current initiator stops the connection. 2542 * <p>Unless the connection is already active as described above, the state will always 2543 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection 2544 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected). 2545 * <p>When finished with the SCO connection or if the establishment fails, the application must 2546 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection. 2547 * <p>Even if a SCO connection is established, the following restrictions apply on audio 2548 * output streams so that they can be routed to SCO headset: 2549 * <ul> 2550 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> 2551 * <li> the format must be mono </li> 2552 * <li> the sampling must be 16kHz or 8kHz </li> 2553 * </ul> 2554 * <p>The following restrictions apply on input streams: 2555 * <ul> 2556 * <li> the format must be mono </li> 2557 * <li> the sampling must be 8kHz </li> 2558 * </ul> 2559 * <p>Note that the phone application always has the priority on the usage of the SCO 2560 * connection for telephony. If this method is called while the phone is in call 2561 * it will be ignored. Similarly, if a call is received or sent while an application 2562 * is using the SCO connection, the connection will be lost for the application and NOT 2563 * returned automatically when the call ends. 2564 * <p>NOTE: up to and including API version 2565 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual 2566 * voice call to the bluetooth headset. 2567 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio 2568 * connection is established. 2569 * @see #stopBluetoothSco() 2570 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 2571 */ startBluetoothSco()2572 public void startBluetoothSco(){ 2573 final IAudioService service = getService(); 2574 try { 2575 service.startBluetoothSco(mICallBack, 2576 getContext().getApplicationInfo().targetSdkVersion); 2577 } catch (RemoteException e) { 2578 throw e.rethrowFromSystemServer(); 2579 } 2580 } 2581 2582 /** 2583 * @hide 2584 * Start bluetooth SCO audio connection in virtual call mode. 2585 * <p>Requires Permission: 2586 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2587 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode. 2588 * Telephony and communication applications (VoIP, Video Chat) should preferably select 2589 * virtual call mode. 2590 * Applications using voice input for search or commands should first try raw audio connection 2591 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of 2592 * failure. 2593 * @see #startBluetoothSco() 2594 * @see #stopBluetoothSco() 2595 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 2596 */ 2597 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) startBluetoothScoVirtualCall()2598 public void startBluetoothScoVirtualCall() { 2599 final IAudioService service = getService(); 2600 try { 2601 service.startBluetoothScoVirtualCall(mICallBack); 2602 } catch (RemoteException e) { 2603 throw e.rethrowFromSystemServer(); 2604 } 2605 } 2606 2607 /** 2608 * Stop bluetooth SCO audio connection. 2609 * <p>Requires Permission: 2610 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}. 2611 * <p>This method must be called by applications having requested the use of 2612 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO 2613 * connection or if connection fails. 2614 * @see #startBluetoothSco() 2615 */ 2616 // Also used for connections started with {@link #startBluetoothScoVirtualCall()} stopBluetoothSco()2617 public void stopBluetoothSco(){ 2618 final IAudioService service = getService(); 2619 try { 2620 service.stopBluetoothSco(mICallBack); 2621 } catch (RemoteException e) { 2622 throw e.rethrowFromSystemServer(); 2623 } 2624 } 2625 2626 /** 2627 * Request use of Bluetooth SCO headset for communications. 2628 * <p> 2629 * This method should only be used by applications that replace the platform-wide 2630 * management of audio settings or the main telephony application. 2631 * 2632 * @param on set <var>true</var> to use bluetooth SCO for communications; 2633 * <var>false</var> to not use bluetooth SCO for communications 2634 */ setBluetoothScoOn(boolean on)2635 public void setBluetoothScoOn(boolean on){ 2636 final IAudioService service = getService(); 2637 try { 2638 service.setBluetoothScoOn(on); 2639 } catch (RemoteException e) { 2640 throw e.rethrowFromSystemServer(); 2641 } 2642 } 2643 2644 /** 2645 * Checks whether communications use Bluetooth SCO. 2646 * 2647 * @return true if SCO is used for communications; 2648 * false if otherwise 2649 */ isBluetoothScoOn()2650 public boolean isBluetoothScoOn() { 2651 final IAudioService service = getService(); 2652 try { 2653 return service.isBluetoothScoOn(); 2654 } catch (RemoteException e) { 2655 throw e.rethrowFromSystemServer(); 2656 } 2657 } 2658 2659 /** 2660 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth 2661 * headset; <var>false</var> disable A2DP audio 2662 * @deprecated Do not use. 2663 */ setBluetoothA2dpOn(boolean on)2664 @Deprecated public void setBluetoothA2dpOn(boolean on){ 2665 } 2666 2667 /** 2668 * Checks whether a Bluetooth A2DP audio peripheral is connected or not. 2669 * 2670 * @return true if a Bluetooth A2DP peripheral is connected 2671 * false if otherwise 2672 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 2673 */ isBluetoothA2dpOn()2674 public boolean isBluetoothA2dpOn() { 2675 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") 2676 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2677 return true; 2678 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"") 2679 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2680 return true; 2681 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"") 2682 == AudioSystem.DEVICE_STATE_AVAILABLE) { 2683 return true; 2684 } 2685 return false; 2686 } 2687 2688 /** 2689 * Sets audio routing to the wired headset on or off. 2690 * 2691 * @param on set <var>true</var> to route audio to/from wired 2692 * headset; <var>false</var> disable wired headset audio 2693 * @deprecated Do not use. 2694 */ setWiredHeadsetOn(boolean on)2695 @Deprecated public void setWiredHeadsetOn(boolean on){ 2696 } 2697 2698 /** 2699 * Checks whether a wired headset is connected or not. 2700 * <p>This is not a valid indication that audio playback is 2701 * actually over the wired headset as audio routing depends on other conditions. 2702 * 2703 * @return true if a wired headset is connected. 2704 * false if otherwise 2705 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 2706 */ isWiredHeadsetOn()2707 public boolean isWiredHeadsetOn() { 2708 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"") 2709 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 2710 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"") 2711 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 2712 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "") 2713 == AudioSystem.DEVICE_STATE_UNAVAILABLE) { 2714 return false; 2715 } else { 2716 return true; 2717 } 2718 } 2719 2720 /** 2721 * Sets the microphone mute on or off. 2722 * <p> 2723 * This method should only be used by applications that replace the platform-wide 2724 * management of audio settings or the main telephony application. 2725 * 2726 * @param on set <var>true</var> to mute the microphone; 2727 * <var>false</var> to turn mute off 2728 */ setMicrophoneMute(boolean on)2729 public void setMicrophoneMute(boolean on) { 2730 final IAudioService service = getService(); 2731 try { 2732 service.setMicrophoneMute(on, getContext().getOpPackageName(), 2733 UserHandle.getCallingUserId()); 2734 } catch (RemoteException e) { 2735 throw e.rethrowFromSystemServer(); 2736 } 2737 } 2738 2739 /** 2740 * @hide 2741 * Sets the microphone from switch mute on or off. 2742 * <p> 2743 * This method should only be used by InputManager to notify 2744 * Audio Subsystem about Microphone Mute switch state. 2745 * 2746 * @param on set <var>true</var> to mute the microphone; 2747 * <var>false</var> to turn mute off 2748 */ 2749 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setMicrophoneMuteFromSwitch(boolean on)2750 public void setMicrophoneMuteFromSwitch(boolean on) { 2751 final IAudioService service = getService(); 2752 try { 2753 service.setMicrophoneMuteFromSwitch(on); 2754 } catch (RemoteException e) { 2755 throw e.rethrowFromSystemServer(); 2756 } 2757 } 2758 2759 /** 2760 * Checks whether the microphone mute is on or off. 2761 * 2762 * @return true if microphone is muted, false if it's not 2763 */ isMicrophoneMute()2764 public boolean isMicrophoneMute() { 2765 final IAudioService service = getService(); 2766 try { 2767 return service.isMicrophoneMuted(); 2768 } catch (RemoteException e) { 2769 throw e.rethrowFromSystemServer(); 2770 } 2771 } 2772 2773 /** 2774 * Broadcast Action: microphone muting state changed. 2775 * 2776 * You <em>cannot</em> receive this through components declared 2777 * in manifests, only by explicitly registering for it with 2778 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 2779 * Context.registerReceiver()}. 2780 * 2781 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the 2782 * microphone is muted. 2783 */ 2784 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2785 public static final String ACTION_MICROPHONE_MUTE_CHANGED = 2786 "android.media.action.MICROPHONE_MUTE_CHANGED"; 2787 2788 /** 2789 * Broadcast Action: speakerphone state changed. 2790 * 2791 * You <em>cannot</em> receive this through components declared 2792 * in manifests, only by explicitly registering for it with 2793 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 2794 * Context.registerReceiver()}. 2795 * 2796 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the 2797 * speakerphone functionality is enabled or not. 2798 */ 2799 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 2800 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = 2801 "android.media.action.SPEAKERPHONE_STATE_CHANGED"; 2802 2803 /** 2804 * Sets the audio mode. 2805 * <p> 2806 * The audio mode encompasses audio routing AND the behavior of 2807 * the telephony layer. Therefore this method should only be used by applications that 2808 * replace the platform-wide management of audio settings or the main telephony application. 2809 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony 2810 * application when it places a phone call, as it will cause signals from the radio layer 2811 * to feed the platform mixer. 2812 * 2813 * @param mode the requested audio mode. 2814 * Informs the HAL about the current audio state so that 2815 * it can route the audio appropriately. 2816 */ setMode(@udioMode int mode)2817 public void setMode(@AudioMode int mode) { 2818 final IAudioService service = getService(); 2819 try { 2820 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); 2821 } catch (RemoteException e) { 2822 throw e.rethrowFromSystemServer(); 2823 } 2824 } 2825 2826 /** 2827 * Returns the current audio mode. 2828 * 2829 * @return the current audio mode. 2830 */ 2831 @AudioMode getMode()2832 public int getMode() { 2833 final IAudioService service = getService(); 2834 try { 2835 int mode = service.getMode(); 2836 int sdk; 2837 try { 2838 sdk = getContext().getApplicationInfo().targetSdkVersion; 2839 } catch (NullPointerException e) { 2840 // some tests don't have a Context 2841 sdk = Build.VERSION.SDK_INT; 2842 } 2843 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { 2844 mode = MODE_IN_CALL; 2845 } 2846 return mode; 2847 } catch (RemoteException e) { 2848 throw e.rethrowFromSystemServer(); 2849 } 2850 } 2851 2852 /** 2853 * Interface definition of a callback that is notified when the audio mode changes 2854 */ 2855 public interface OnModeChangedListener { 2856 /** 2857 * Called on the listener to indicate that the audio mode has changed 2858 * 2859 * @param mode The current audio mode 2860 */ onModeChanged(@udioMode int mode)2861 void onModeChanged(@AudioMode int mode); 2862 } 2863 2864 private final Object mModeListenerLock = new Object(); 2865 /** 2866 * List of listeners for audio mode and their associated Executor. 2867 * List is lazy-initialized on first registration 2868 */ 2869 @GuardedBy("mModeListenerLock") 2870 private @Nullable ArrayList<ModeListenerInfo> mModeListeners; 2871 2872 @GuardedBy("mModeListenerLock") 2873 private ModeDispatcherStub mModeDispatcherStub; 2874 2875 private final class ModeDispatcherStub 2876 extends IAudioModeDispatcher.Stub { 2877 2878 @Override dispatchAudioModeChanged(int mode)2879 public void dispatchAudioModeChanged(int mode) { 2880 // make a shallow copy of listeners so callback is not executed under lock 2881 final ArrayList<ModeListenerInfo> modeListeners; 2882 synchronized (mModeListenerLock) { 2883 if (mModeListeners == null || mModeListeners.size() == 0) { 2884 return; 2885 } 2886 modeListeners = (ArrayList<ModeListenerInfo>) mModeListeners.clone(); 2887 } 2888 final long ident = Binder.clearCallingIdentity(); 2889 try { 2890 for (ModeListenerInfo info : modeListeners) { 2891 info.mExecutor.execute(() -> 2892 info.mListener.onModeChanged(mode)); 2893 } 2894 } finally { 2895 Binder.restoreCallingIdentity(ident); 2896 } 2897 } 2898 } 2899 2900 private static class ModeListenerInfo { 2901 final @NonNull OnModeChangedListener mListener; 2902 final @NonNull Executor mExecutor; 2903 ModeListenerInfo(OnModeChangedListener listener, Executor exe)2904 ModeListenerInfo(OnModeChangedListener listener, Executor exe) { 2905 mListener = listener; 2906 mExecutor = exe; 2907 } 2908 } 2909 2910 @GuardedBy("mModeListenerLock") hasModeListener(OnModeChangedListener listener)2911 private boolean hasModeListener(OnModeChangedListener listener) { 2912 return getModeListenerInfo(listener) != null; 2913 } 2914 2915 @GuardedBy("mModeListenerLock") getModeListenerInfo( OnModeChangedListener listener)2916 private @Nullable ModeListenerInfo getModeListenerInfo( 2917 OnModeChangedListener listener) { 2918 if (mModeListeners == null) { 2919 return null; 2920 } 2921 for (ModeListenerInfo info : mModeListeners) { 2922 if (info.mListener == listener) { 2923 return info; 2924 } 2925 } 2926 return null; 2927 } 2928 2929 2930 @GuardedBy("mModeListenerLock") 2931 /** 2932 * @return true if the listener was removed from the list 2933 */ removeModeListener(OnModeChangedListener listener)2934 private boolean removeModeListener(OnModeChangedListener listener) { 2935 final ModeListenerInfo infoToRemove = getModeListenerInfo(listener); 2936 if (infoToRemove != null) { 2937 mModeListeners.remove(infoToRemove); 2938 return true; 2939 } 2940 return false; 2941 } 2942 2943 /** 2944 * Adds a listener to be notified of changes to the audio mode. 2945 * See {@link #getMode()} 2946 * @param executor 2947 * @param listener 2948 */ addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)2949 public void addOnModeChangedListener( 2950 @NonNull @CallbackExecutor Executor executor, 2951 @NonNull OnModeChangedListener listener) { 2952 Objects.requireNonNull(executor); 2953 Objects.requireNonNull(listener); 2954 synchronized (mModeListenerLock) { 2955 if (hasModeListener(listener)) { 2956 throw new IllegalArgumentException("attempt to call addOnModeChangedListener() " 2957 + "on a previously registered listener"); 2958 } 2959 // lazy initialization of the list of strategy-preferred device listener 2960 if (mModeListeners == null) { 2961 mModeListeners = new ArrayList<>(); 2962 } 2963 final int oldCbCount = mModeListeners.size(); 2964 mModeListeners.add(new ModeListenerInfo(listener, executor)); 2965 if (oldCbCount == 0) { 2966 // register binder for callbacks 2967 if (mModeDispatcherStub == null) { 2968 mModeDispatcherStub = new ModeDispatcherStub(); 2969 } 2970 try { 2971 getService().registerModeDispatcher(mModeDispatcherStub); 2972 } catch (RemoteException e) { 2973 throw e.rethrowFromSystemServer(); 2974 } 2975 } 2976 } 2977 } 2978 2979 /** 2980 * Removes a previously added listener for changes to audio mode. 2981 * See {@link #getMode()} 2982 * @param listener 2983 */ removeOnModeChangedListener(@onNull OnModeChangedListener listener)2984 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) { 2985 Objects.requireNonNull(listener); 2986 synchronized (mModeListenerLock) { 2987 if (!removeModeListener(listener)) { 2988 throw new IllegalArgumentException("attempt to call removeOnModeChangedListener() " 2989 + "on an unregistered listener"); 2990 } 2991 if (mModeListeners.size() == 0) { 2992 // unregister binder for callbacks 2993 try { 2994 getService().unregisterModeDispatcher(mModeDispatcherStub); 2995 } catch (RemoteException e) { 2996 throw e.rethrowFromSystemServer(); 2997 } finally { 2998 mModeDispatcherStub = null; 2999 mModeListeners = null; 3000 } 3001 } 3002 } 3003 } 3004 3005 /** 3006 * Indicates if the platform supports a special call screening and call monitoring mode. 3007 * <p> 3008 * When this mode is supported, it is possible to perform call screening and monitoring 3009 * functions while other use cases like music or movie playback are active. 3010 * <p> 3011 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in 3012 * call screening mode. 3013 * <p> 3014 * If call screening mode is not supported, setting mode to 3015 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by 3016 * {@link #getMode()}. 3017 * @return true if call screening mode is supported, false otherwise. 3018 */ isCallScreeningModeSupported()3019 public boolean isCallScreeningModeSupported() { 3020 final IAudioService service = getService(); 3021 try { 3022 return service.isCallScreeningModeSupported(); 3023 } catch (RemoteException e) { 3024 throw e.rethrowFromSystemServer(); 3025 } 3026 } 3027 3028 /* modes for setMode/getMode/setRoute/getRoute */ 3029 /** 3030 * Audio harware modes. 3031 */ 3032 /** 3033 * Invalid audio mode. 3034 */ 3035 public static final int MODE_INVALID = AudioSystem.MODE_INVALID; 3036 /** 3037 * Current audio mode. Used to apply audio routing to current mode. 3038 */ 3039 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; 3040 /** 3041 * Normal audio mode: not ringing and no call established. 3042 */ 3043 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; 3044 /** 3045 * Ringing audio mode. An incoming is being signaled. 3046 */ 3047 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; 3048 /** 3049 * In call audio mode. A telephony call is established. 3050 */ 3051 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; 3052 /** 3053 * In communication audio mode. An audio/video chat or VoIP call is established. 3054 */ 3055 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; 3056 /** 3057 * Call screening in progress. Call is connected and audio is accessible to call 3058 * screening applications but other audio use cases are still possible. 3059 */ 3060 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; 3061 3062 /** @hide */ 3063 @IntDef(flag = false, prefix = "MODE_", value = { 3064 MODE_NORMAL, 3065 MODE_RINGTONE, 3066 MODE_IN_CALL, 3067 MODE_IN_COMMUNICATION, 3068 MODE_CALL_SCREENING } 3069 ) 3070 @Retention(RetentionPolicy.SOURCE) 3071 public @interface AudioMode {} 3072 3073 /* Routing bits for setRouting/getRouting API */ 3074 /** 3075 * Routing audio output to earpiece 3076 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3077 * setBluetoothScoOn() methods instead. 3078 */ 3079 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; 3080 /** 3081 * Routing audio output to speaker 3082 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3083 * setBluetoothScoOn() methods instead. 3084 */ 3085 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; 3086 /** 3087 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} 3088 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3089 * setBluetoothScoOn() methods instead. 3090 */ 3091 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; 3092 /** 3093 * Routing audio output to bluetooth SCO 3094 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3095 * setBluetoothScoOn() methods instead. 3096 */ 3097 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; 3098 /** 3099 * Routing audio output to headset 3100 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3101 * setBluetoothScoOn() methods instead. 3102 */ 3103 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; 3104 /** 3105 * Routing audio output to bluetooth A2DP 3106 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3107 * setBluetoothScoOn() methods instead. 3108 */ 3109 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; 3110 /** 3111 * Used for mask parameter of {@link #setRouting(int,int,int)}. 3112 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3113 * setBluetoothScoOn() methods instead. 3114 */ 3115 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; 3116 3117 /** 3118 * Sets the audio routing for a specified mode 3119 * 3120 * @param mode audio mode to change route. E.g., MODE_RINGTONE. 3121 * @param routes bit vector of routes requested, created from one or 3122 * more of ROUTE_xxx types. Set bits indicate that route should be on 3123 * @param mask bit vector of routes to change, created from one or more of 3124 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged 3125 * 3126 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3127 * setBluetoothScoOn() methods instead. 3128 */ 3129 @Deprecated setRouting(int mode, int routes, int mask)3130 public void setRouting(int mode, int routes, int mask) { 3131 } 3132 3133 /** 3134 * Returns the current audio routing bit vector for a specified mode. 3135 * 3136 * @param mode audio mode to get route (e.g., MODE_RINGTONE) 3137 * @return an audio route bit vector that can be compared with ROUTE_xxx 3138 * bits 3139 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(), 3140 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead. 3141 */ 3142 @Deprecated getRouting(int mode)3143 public int getRouting(int mode) { 3144 return -1; 3145 } 3146 3147 /** 3148 * Checks whether any music is active. 3149 * 3150 * @return true if any music tracks are active. 3151 */ isMusicActive()3152 public boolean isMusicActive() { 3153 final IAudioService service = getService(); 3154 try { 3155 return service.isMusicActive(false /*remotely*/); 3156 } catch (RemoteException e) { 3157 throw e.rethrowFromSystemServer(); 3158 } 3159 } 3160 3161 /** 3162 * @hide 3163 * Checks whether any music or media is actively playing on a remote device (e.g. wireless 3164 * display). Note that BT audio sinks are not considered remote devices. 3165 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device 3166 */ 3167 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isMusicActiveRemotely()3168 public boolean isMusicActiveRemotely() { 3169 final IAudioService service = getService(); 3170 try { 3171 return service.isMusicActive(true /*remotely*/); 3172 } catch (RemoteException e) { 3173 throw e.rethrowFromSystemServer(); 3174 } 3175 } 3176 3177 /** 3178 * @hide 3179 * Checks whether the current audio focus is exclusive. 3180 * @return true if the top of the audio focus stack requested focus 3181 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} 3182 */ isAudioFocusExclusive()3183 public boolean isAudioFocusExclusive() { 3184 final IAudioService service = getService(); 3185 try { 3186 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; 3187 } catch (RemoteException e) { 3188 throw e.rethrowFromSystemServer(); 3189 } 3190 } 3191 3192 /** 3193 * Return a new audio session identifier not associated with any player or effect. 3194 * An audio session identifier is a system wide unique identifier for a set of audio streams 3195 * (one or more mixed together). 3196 * <p>The primary use of the audio session ID is to associate audio effects to audio players, 3197 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio 3198 * session ID will be applied to the mixed audio content of the players that share the same 3199 * audio session. 3200 * <p>This method can for instance be used when creating one of the 3201 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect, 3202 * or to specify a session for a speech synthesis utterance 3203 * in {@link android.speech.tts.TextToSpeech.Engine}. 3204 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the 3205 * system failed to generate a new session, a condition in which audio playback or recording 3206 * will subsequently fail as well. 3207 */ generateAudioSessionId()3208 public int generateAudioSessionId() { 3209 int session = AudioSystem.newAudioSessionId(); 3210 if (session > 0) { 3211 return session; 3212 } else { 3213 Log.e(TAG, "Failure to generate a new audio session ID"); 3214 return ERROR; 3215 } 3216 } 3217 3218 /** 3219 * A special audio session ID to indicate that the audio session ID isn't known and the 3220 * framework should generate a new value. This can be used when building a new 3221 * {@link AudioTrack} instance with 3222 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}. 3223 */ 3224 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE; 3225 3226 3227 /* 3228 * Sets a generic audio configuration parameter. The use of these parameters 3229 * are platform dependant, see libaudio 3230 * 3231 * ** Temporary interface - DO NOT USE 3232 * 3233 * TODO: Replace with a more generic key:value get/set mechanism 3234 * 3235 * param key name of parameter to set. Must not be null. 3236 * param value value of parameter. Must not be null. 3237 */ 3238 /** 3239 * @hide 3240 * @deprecated Use {@link #setParameters(String)} instead 3241 */ setParameter(String key, String value)3242 @Deprecated public void setParameter(String key, String value) { 3243 setParameters(key+"="+value); 3244 } 3245 3246 /** 3247 * Sets a variable number of parameter values to audio hardware. 3248 * 3249 * @param keyValuePairs list of parameters key value pairs in the form: 3250 * key1=value1;key2=value2;... 3251 * 3252 */ setParameters(String keyValuePairs)3253 public void setParameters(String keyValuePairs) { 3254 AudioSystem.setParameters(keyValuePairs); 3255 } 3256 3257 /** 3258 * Gets a variable number of parameter values from audio hardware. 3259 * 3260 * @param keys list of parameters 3261 * @return list of parameters key value pairs in the form: 3262 * key1=value1;key2=value2;... 3263 */ getParameters(String keys)3264 public String getParameters(String keys) { 3265 return AudioSystem.getParameters(keys); 3266 } 3267 3268 /* Sound effect identifiers */ 3269 /** 3270 * Keyboard and direction pad click sound 3271 * @see #playSoundEffect(int) 3272 */ 3273 public static final int FX_KEY_CLICK = 0; 3274 /** 3275 * Focus has moved up 3276 * @see #playSoundEffect(int) 3277 */ 3278 public static final int FX_FOCUS_NAVIGATION_UP = 1; 3279 /** 3280 * Focus has moved down 3281 * @see #playSoundEffect(int) 3282 */ 3283 public static final int FX_FOCUS_NAVIGATION_DOWN = 2; 3284 /** 3285 * Focus has moved left 3286 * @see #playSoundEffect(int) 3287 */ 3288 public static final int FX_FOCUS_NAVIGATION_LEFT = 3; 3289 /** 3290 * Focus has moved right 3291 * @see #playSoundEffect(int) 3292 */ 3293 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; 3294 /** 3295 * IME standard keypress sound 3296 * @see #playSoundEffect(int) 3297 */ 3298 public static final int FX_KEYPRESS_STANDARD = 5; 3299 /** 3300 * IME spacebar keypress sound 3301 * @see #playSoundEffect(int) 3302 */ 3303 public static final int FX_KEYPRESS_SPACEBAR = 6; 3304 /** 3305 * IME delete keypress sound 3306 * @see #playSoundEffect(int) 3307 */ 3308 public static final int FX_KEYPRESS_DELETE = 7; 3309 /** 3310 * IME return_keypress sound 3311 * @see #playSoundEffect(int) 3312 */ 3313 public static final int FX_KEYPRESS_RETURN = 8; 3314 3315 /** 3316 * Invalid keypress sound 3317 * @see #playSoundEffect(int) 3318 */ 3319 public static final int FX_KEYPRESS_INVALID = 9; 3320 3321 /** 3322 * Back sound 3323 * @see #playSoundEffect(int) 3324 */ 3325 public static final int FX_BACK = 10; 3326 3327 /** 3328 * @hide Home sound 3329 * <p> 3330 * To be played by the framework when the home app becomes active if config_enableHomeSound is 3331 * set to true. This is currently only used on TV devices. 3332 * Note that this sound is only available if a sound file is specified in audio_assets.xml. 3333 * @see #playSoundEffect(int) 3334 */ 3335 public static final int FX_HOME = 11; 3336 3337 /** 3338 * @hide Navigation repeat sound 1 3339 * <p> 3340 * To be played by the framework when a focus navigation is repeatedly triggered 3341 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3342 * This is currently only used on TV devices. 3343 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3344 * @see #playSoundEffect(int) 3345 */ 3346 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12; 3347 3348 /** 3349 * @hide Navigation repeat sound 2 3350 * <p> 3351 * To be played by the framework when a focus navigation is repeatedly triggered 3352 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3353 * This is currently only used on TV devices. 3354 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3355 * @see #playSoundEffect(int) 3356 */ 3357 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13; 3358 3359 /** 3360 * @hide Navigation repeat sound 3 3361 * <p> 3362 * To be played by the framework when a focus navigation is repeatedly triggered 3363 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3364 * This is currently only used on TV devices. 3365 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3366 * @see #playSoundEffect(int) 3367 */ 3368 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14; 3369 3370 /** 3371 * @hide Navigation repeat sound 4 3372 * <p> 3373 * To be played by the framework when a focus navigation is repeatedly triggered 3374 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 3375 * This is currently only used on TV devices. 3376 * Note that this sound is only available if a sound file is specified in audio_assets.xml 3377 * @see #playSoundEffect(int) 3378 */ 3379 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15; 3380 3381 /** 3382 * @hide Number of sound effects 3383 */ 3384 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3385 public static final int NUM_SOUND_EFFECTS = 16; 3386 3387 /** @hide */ 3388 @IntDef(prefix = { "FX_" }, value = { 3389 FX_KEY_CLICK, 3390 FX_FOCUS_NAVIGATION_UP, 3391 FX_FOCUS_NAVIGATION_DOWN, 3392 FX_FOCUS_NAVIGATION_LEFT, 3393 FX_FOCUS_NAVIGATION_RIGHT, 3394 FX_KEYPRESS_STANDARD, 3395 FX_KEYPRESS_SPACEBAR, 3396 FX_KEYPRESS_DELETE, 3397 FX_KEYPRESS_RETURN, 3398 FX_KEYPRESS_INVALID, 3399 FX_BACK 3400 }) 3401 @Retention(RetentionPolicy.SOURCE) 3402 public @interface SystemSoundEffect {} 3403 3404 /** 3405 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects 3406 */ 3407 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4; 3408 3409 /** 3410 * @hide 3411 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[ 3412 * @return The id of a navigation repeat sound effect or -1 if out of bounds 3413 */ getNthNavigationRepeatSoundEffect(int n)3414 public static int getNthNavigationRepeatSoundEffect(int n) { 3415 switch (n) { 3416 case 0: 3417 return FX_FOCUS_NAVIGATION_REPEAT_1; 3418 case 1: 3419 return FX_FOCUS_NAVIGATION_REPEAT_2; 3420 case 2: 3421 return FX_FOCUS_NAVIGATION_REPEAT_3; 3422 case 3: 3423 return FX_FOCUS_NAVIGATION_REPEAT_4; 3424 default: 3425 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n); 3426 return -1; 3427 } 3428 } 3429 3430 /** 3431 * @hide 3432 */ setNavigationRepeatSoundEffectsEnabled(boolean enabled)3433 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) { 3434 try { 3435 getService().setNavigationRepeatSoundEffectsEnabled(enabled); 3436 } catch (RemoteException e) { 3437 3438 } 3439 } 3440 3441 /** 3442 * @hide 3443 * @return true if the navigation repeat sound effects are enabled 3444 */ areNavigationRepeatSoundEffectsEnabled()3445 public boolean areNavigationRepeatSoundEffectsEnabled() { 3446 try { 3447 return getService().areNavigationRepeatSoundEffectsEnabled(); 3448 } catch (RemoteException e) { 3449 throw e.rethrowFromSystemServer(); 3450 } 3451 } 3452 3453 /** 3454 * @hide 3455 * @param enabled 3456 */ setHomeSoundEffectEnabled(boolean enabled)3457 public void setHomeSoundEffectEnabled(boolean enabled) { 3458 try { 3459 getService().setHomeSoundEffectEnabled(enabled); 3460 } catch (RemoteException e) { 3461 3462 } 3463 } 3464 3465 /** 3466 * @hide 3467 * @return true if the home sound effect is enabled 3468 */ isHomeSoundEffectEnabled()3469 public boolean isHomeSoundEffectEnabled() { 3470 try { 3471 return getService().isHomeSoundEffectEnabled(); 3472 } catch (RemoteException e) { 3473 throw e.rethrowFromSystemServer(); 3474 } 3475 } 3476 3477 /** 3478 * Plays a sound effect (Key clicks, lid open/close...) 3479 * @param effectType The type of sound effect. 3480 * NOTE: This version uses the UI settings to determine 3481 * whether sounds are heard or not. 3482 */ playSoundEffect(@ystemSoundEffect int effectType)3483 public void playSoundEffect(@SystemSoundEffect int effectType) { 3484 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3485 return; 3486 } 3487 3488 if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) { 3489 return; 3490 } 3491 3492 final IAudioService service = getService(); 3493 try { 3494 service.playSoundEffect(effectType); 3495 } catch (RemoteException e) { 3496 throw e.rethrowFromSystemServer(); 3497 } 3498 } 3499 3500 /** 3501 * Plays a sound effect (Key clicks, lid open/close...) 3502 * @param effectType The type of sound effect. 3503 * @param userId The current user to pull sound settings from 3504 * NOTE: This version uses the UI settings to determine 3505 * whether sounds are heard or not. 3506 * @hide 3507 */ playSoundEffect(@ystemSoundEffect int effectType, int userId)3508 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) { 3509 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3510 return; 3511 } 3512 3513 if (!querySoundEffectsEnabled(userId)) { 3514 return; 3515 } 3516 3517 final IAudioService service = getService(); 3518 try { 3519 service.playSoundEffect(effectType); 3520 } catch (RemoteException e) { 3521 throw e.rethrowFromSystemServer(); 3522 } 3523 } 3524 3525 /** 3526 * Plays a sound effect (Key clicks, lid open/close...) 3527 * @param effectType The type of sound effect. 3528 * @param volume Sound effect volume. 3529 * The volume value is a raw scalar so UI controls should be scaled logarithmically. 3530 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. 3531 * NOTE: This version is for applications that have their own 3532 * settings panel for enabling and controlling volume. 3533 */ playSoundEffect(@ystemSoundEffect int effectType, float volume)3534 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) { 3535 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 3536 return; 3537 } 3538 3539 final IAudioService service = getService(); 3540 try { 3541 service.playSoundEffectVolume(effectType, volume); 3542 } catch (RemoteException e) { 3543 throw e.rethrowFromSystemServer(); 3544 } 3545 } 3546 3547 /** 3548 * Settings has an in memory cache, so this is fast. 3549 */ querySoundEffectsEnabled(int user)3550 private boolean querySoundEffectsEnabled(int user) { 3551 return Settings.System.getIntForUser(getContext().getContentResolver(), 3552 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0; 3553 } 3554 3555 /** 3556 * Load Sound effects. 3557 * This method must be called when sound effects are enabled. 3558 */ loadSoundEffects()3559 public void loadSoundEffects() { 3560 final IAudioService service = getService(); 3561 try { 3562 service.loadSoundEffects(); 3563 } catch (RemoteException e) { 3564 throw e.rethrowFromSystemServer(); 3565 } 3566 } 3567 3568 /** 3569 * Unload Sound effects. 3570 * This method can be called to free some memory when 3571 * sound effects are disabled. 3572 */ unloadSoundEffects()3573 public void unloadSoundEffects() { 3574 final IAudioService service = getService(); 3575 try { 3576 service.unloadSoundEffects(); 3577 } catch (RemoteException e) { 3578 throw e.rethrowFromSystemServer(); 3579 } 3580 } 3581 3582 /** 3583 * @hide 3584 */ audioFocusToString(int focus)3585 public static String audioFocusToString(int focus) { 3586 switch (focus) { 3587 case AUDIOFOCUS_NONE: 3588 return "AUDIOFOCUS_NONE"; 3589 case AUDIOFOCUS_GAIN: 3590 return "AUDIOFOCUS_GAIN"; 3591 case AUDIOFOCUS_GAIN_TRANSIENT: 3592 return "AUDIOFOCUS_GAIN_TRANSIENT"; 3593 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 3594 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"; 3595 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 3596 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE"; 3597 case AUDIOFOCUS_LOSS: 3598 return "AUDIOFOCUS_LOSS"; 3599 case AUDIOFOCUS_LOSS_TRANSIENT: 3600 return "AUDIOFOCUS_LOSS_TRANSIENT"; 3601 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK. 3602 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"; 3603 default: 3604 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")"; 3605 } 3606 } 3607 3608 /** 3609 * Used to indicate no audio focus has been gained or lost, or requested. 3610 */ 3611 public static final int AUDIOFOCUS_NONE = 0; 3612 3613 /** 3614 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 3615 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3616 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3617 */ 3618 public static final int AUDIOFOCUS_GAIN = 1; 3619 /** 3620 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 3621 * amount of time. Examples of temporary changes are the playback of driving directions, or an 3622 * event notification. 3623 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3624 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3625 */ 3626 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; 3627 /** 3628 * Used to indicate a temporary request of audio focus, anticipated to last a short 3629 * amount of time, and where it is acceptable for other audio applications to keep playing 3630 * after having lowered their output level (also referred to as "ducking"). 3631 * Examples of temporary changes are the playback of driving directions where playback of music 3632 * in the background is acceptable. 3633 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3634 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3635 */ 3636 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; 3637 /** 3638 * Used to indicate a temporary request of audio focus, anticipated to last a short 3639 * amount of time, during which no other applications, or system components, should play 3640 * anything. Examples of exclusive and transient audio focus requests are voice 3641 * memo recording and speech recognition, during which the system shouldn't play any 3642 * notifications, and media playback should have paused. 3643 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 3644 */ 3645 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; 3646 /** 3647 * Used to indicate a loss of audio focus of unknown duration. 3648 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3649 */ 3650 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 3651 /** 3652 * Used to indicate a transient loss of audio focus. 3653 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3654 */ 3655 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; 3656 /** 3657 * Used to indicate a transient loss of audio focus where the loser of the audio focus can 3658 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 3659 * the new focus owner doesn't require others to be silent. 3660 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 3661 */ 3662 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = 3663 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; 3664 3665 /** 3666 * Interface definition for a callback to be invoked when the audio focus of the system is 3667 * updated. 3668 */ 3669 public interface OnAudioFocusChangeListener { 3670 /** 3671 * Called on the listener to notify it the audio focus for this listener has been changed. 3672 * The focusChange value indicates whether the focus was gained, 3673 * whether the focus was lost, and whether that loss is transient, or whether the new focus 3674 * holder will hold it for an unknown amount of time. 3675 * When losing focus, listeners can use the focus change information to decide what 3676 * behavior to adopt when losing focus. A music player could for instance elect to lower 3677 * the volume of its music stream (duck) for transient focus losses, and pause otherwise. 3678 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN}, 3679 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 3680 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. 3681 */ onAudioFocusChange(int focusChange)3682 public void onAudioFocusChange(int focusChange); 3683 } 3684 3685 /** 3686 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback 3687 */ 3688 private static class FocusRequestInfo { 3689 @NonNull final AudioFocusRequest mRequest; 3690 @Nullable final Handler mHandler; FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)3691 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { 3692 mRequest = afr; 3693 mHandler = handler; 3694 } 3695 } 3696 3697 /** 3698 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, 3699 * to actual listener objects. 3700 */ 3701 @UnsupportedAppUsage 3702 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = 3703 new ConcurrentHashMap<String, FocusRequestInfo>(); 3704 findFocusRequestInfo(String id)3705 private FocusRequestInfo findFocusRequestInfo(String id) { 3706 return mAudioFocusIdListenerMap.get(id); 3707 } 3708 3709 /** 3710 * Handler for events (audio focus change, recording config change) coming from the 3711 * audio service. 3712 */ 3713 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate = 3714 new ServiceEventHandlerDelegate(null); 3715 3716 /** 3717 * Event types 3718 */ 3719 private final static int MSSG_FOCUS_CHANGE = 0; 3720 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1; 3721 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2; 3722 3723 /** 3724 * Helper class to handle the forwarding of audio service events to the appropriate listener 3725 */ 3726 private class ServiceEventHandlerDelegate { 3727 private final Handler mHandler; 3728 ServiceEventHandlerDelegate(Handler handler)3729 ServiceEventHandlerDelegate(Handler handler) { 3730 Looper looper; 3731 if (handler == null) { 3732 if ((looper = Looper.myLooper()) == null) { 3733 looper = Looper.getMainLooper(); 3734 } 3735 } else { 3736 looper = handler.getLooper(); 3737 } 3738 3739 if (looper != null) { 3740 // implement the event handler delegate to receive events from audio service 3741 mHandler = new Handler(looper) { 3742 @Override 3743 public void handleMessage(Message msg) { 3744 switch (msg.what) { 3745 case MSSG_FOCUS_CHANGE: { 3746 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); 3747 if (fri != null) { 3748 final OnAudioFocusChangeListener listener = 3749 fri.mRequest.getOnAudioFocusChangeListener(); 3750 if (listener != null) { 3751 Log.d(TAG, "dispatching onAudioFocusChange(" 3752 + msg.arg1 + ") to " + msg.obj); 3753 listener.onAudioFocusChange(msg.arg1); 3754 } 3755 } 3756 } break; 3757 case MSSG_RECORDING_CONFIG_CHANGE: { 3758 final RecordConfigChangeCallbackData cbData = 3759 (RecordConfigChangeCallbackData) msg.obj; 3760 if (cbData.mCb != null) { 3761 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs); 3762 } 3763 } break; 3764 case MSSG_PLAYBACK_CONFIG_CHANGE: { 3765 final PlaybackConfigChangeCallbackData cbData = 3766 (PlaybackConfigChangeCallbackData) msg.obj; 3767 if (cbData.mCb != null) { 3768 if (DEBUG) { 3769 Log.d(TAG, "dispatching onPlaybackConfigChanged()"); 3770 } 3771 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs); 3772 } 3773 } break; 3774 default: 3775 Log.e(TAG, "Unknown event " + msg.what); 3776 } 3777 } 3778 }; 3779 } else { 3780 mHandler = null; 3781 } 3782 } 3783 getHandler()3784 Handler getHandler() { 3785 return mHandler; 3786 } 3787 } 3788 3789 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { 3790 @Override 3791 public void dispatchAudioFocusChange(int focusChange, String id) { 3792 final FocusRequestInfo fri = findFocusRequestInfo(id); 3793 if (fri != null) { 3794 final OnAudioFocusChangeListener listener = 3795 fri.mRequest.getOnAudioFocusChangeListener(); 3796 if (listener != null) { 3797 final Handler h = (fri.mHandler == null) ? 3798 mServiceEventHandlerDelegate.getHandler() : fri.mHandler; 3799 final Message m = h.obtainMessage( 3800 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, 3801 id/*obj*/); 3802 h.sendMessage(m); 3803 } 3804 } 3805 } 3806 3807 @Override 3808 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) { 3809 synchronized (mFocusRequestsLock) { 3810 // TODO use generation counter as the key instead 3811 final BlockingFocusResultReceiver focusReceiver = 3812 mFocusRequestsAwaitingResult.remove(clientId); 3813 if (focusReceiver != null) { 3814 focusReceiver.notifyResult(requestResult); 3815 } else { 3816 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver"); 3817 } 3818 } 3819 } 3820 }; 3821 getIdForAudioFocusListener(OnAudioFocusChangeListener l)3822 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { 3823 if (l == null) { 3824 return new String(this.toString()); 3825 } else { 3826 return new String(this.toString() + l.toString()); 3827 } 3828 } 3829 3830 /** 3831 * @hide 3832 * Registers a listener to be called when audio focus changes and keeps track of the associated 3833 * focus request (including Handler to use for the listener). 3834 * @param afr the full request parameters 3835 */ registerAudioFocusRequest(@onNull AudioFocusRequest afr)3836 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { 3837 final Handler h = afr.getOnAudioFocusChangeListenerHandler(); 3838 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : 3839 new ServiceEventHandlerDelegate(h).getHandler()); 3840 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 3841 mAudioFocusIdListenerMap.put(key, fri); 3842 } 3843 3844 /** 3845 * @hide 3846 * Causes the specified listener to not be called anymore when focus is gained or lost. 3847 * @param l the listener to unregister. 3848 */ unregisterAudioFocusRequest(OnAudioFocusChangeListener l)3849 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { 3850 // remove locally 3851 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); 3852 } 3853 3854 3855 /** 3856 * A failed focus change request. 3857 */ 3858 public static final int AUDIOFOCUS_REQUEST_FAILED = 0; 3859 /** 3860 * A successful focus change request. 3861 */ 3862 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; 3863 /** 3864 * A focus change request whose granting is delayed: the request was successful, but the 3865 * requester will only be granted audio focus once the condition that prevented immediate 3866 * granting has ended. 3867 * See {@link #requestAudioFocus(AudioFocusRequest)} and 3868 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} 3869 */ 3870 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; 3871 3872 /** @hide */ 3873 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = { 3874 AUDIOFOCUS_REQUEST_FAILED, 3875 AUDIOFOCUS_REQUEST_GRANTED, 3876 AUDIOFOCUS_REQUEST_DELAYED } 3877 ) 3878 @Retention(RetentionPolicy.SOURCE) 3879 public @interface FocusRequestResult {} 3880 3881 /** 3882 * @hide 3883 * code returned when a synchronous focus request on the client-side is to be blocked 3884 * until the external audio focus policy decides on the response for the client 3885 */ 3886 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100; 3887 3888 /** 3889 * Timeout duration in ms when waiting on an external focus policy for the result for a 3890 * focus request 3891 */ 3892 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200; 3893 3894 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id"; 3895 3896 private final Object mFocusRequestsLock = new Object(); 3897 /** 3898 * Map of all receivers of focus request results, one per unresolved focus request. 3899 * Receivers are added before sending the request to the external focus policy, 3900 * and are removed either after receiving the result, or after the timeout. 3901 * This variable is lazily initialized. 3902 */ 3903 @GuardedBy("mFocusRequestsLock") 3904 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult; 3905 3906 3907 /** 3908 * Request audio focus. 3909 * Send a request to obtain the audio focus 3910 * @param l the listener to be notified of audio focus changes 3911 * @param streamType the main audio stream type affected by the focus request 3912 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 3913 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 3914 * for the playback of driving directions, or notifications sounds. 3915 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 3916 * the previous focus owner to keep playing if it ducks its audio output. 3917 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 3918 * that benefits from the system not playing disruptive sounds like notifications, for 3919 * usecases such as voice memo recording, or speech recognition. 3920 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 3921 * as the playback of a song or a video. 3922 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 3923 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)} 3924 */ requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)3925 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { 3926 PlayerBase.deprecateStreamTypeForPlayback(streamType, 3927 "AudioManager", "requestAudioFocus()"); 3928 int status = AUDIOFOCUS_REQUEST_FAILED; 3929 3930 try { 3931 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or 3932 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the 3933 // AUDIOFOCUS_FLAG_DELAY_OK flag 3934 status = requestAudioFocus(l, 3935 new AudioAttributes.Builder() 3936 .setInternalLegacyStreamType(streamType).build(), 3937 durationHint, 3938 0 /* flags, legacy behavior */); 3939 } catch (IllegalArgumentException e) { 3940 Log.e(TAG, "Audio focus request denied due to ", e); 3941 } 3942 3943 return status; 3944 } 3945 3946 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks 3947 /** 3948 * @hide 3949 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be 3950 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when 3951 * the system is in a state where focus cannot change, but be granted focus later when 3952 * this condition ends. 3953 */ 3954 @SystemApi 3955 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0; 3956 /** 3957 * @hide 3958 * Use this flag when requesting audio focus to indicate that the requester 3959 * will pause its media playback (if applicable) when losing audio focus with 3960 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking. 3961 * <br>On some platforms, the ducking may be handled without the application being aware of it 3962 * (i.e. it will not transiently lose focus). For applications that for instance play spoken 3963 * content, such as audio book or podcast players, ducking may never be acceptable, and will 3964 * thus always pause. This flag enables them to be declared as such whenever they request focus. 3965 */ 3966 @SystemApi 3967 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1; 3968 /** 3969 * @hide 3970 * Use this flag to lock audio focus so granting is temporarily disabled. 3971 * <br>This flag can only be used by owners of a registered 3972 * {@link android.media.audiopolicy.AudioPolicy} in 3973 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)} 3974 */ 3975 @SystemApi 3976 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2; 3977 3978 /** 3979 * @hide 3980 * flag set on test API calls, 3981 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}, 3982 * note that it isn't used in conjunction with other flags, it is passed as the single 3983 * value for flags */ 3984 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3; 3985 /** @hide */ 3986 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK 3987 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS; 3988 /** @hide */ 3989 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK 3990 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK; 3991 3992 /** 3993 * Request audio focus. 3994 * See the {@link AudioFocusRequest} for information about the options available to configure 3995 * your request, and notification of focus gain and loss. 3996 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is 3997 * requested. 3998 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 3999 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4000 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus 4001 * is requested without building the {@link AudioFocusRequest} with 4002 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to 4003 * {@code true}. 4004 * @throws NullPointerException if passed a null argument 4005 */ requestAudioFocus(@onNull AudioFocusRequest focusRequest)4006 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { 4007 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); 4008 } 4009 4010 /** 4011 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4012 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus 4013 * with {@link #requestAudioFocus(AudioFocusRequest)}. 4014 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4015 * @throws IllegalArgumentException if passed a null argument 4016 */ abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4017 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) { 4018 if (focusRequest == null) { 4019 throw new IllegalArgumentException("Illegal null AudioFocusRequest"); 4020 } 4021 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(), 4022 focusRequest.getAudioAttributes()); 4023 } 4024 4025 /** 4026 * @hide 4027 * Request audio focus. 4028 * Send a request to obtain the audio focus. This method differs from 4029 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express 4030 * that the requester accepts delayed grants of audio focus. 4031 * @param l the listener to be notified of audio focus changes. It is not allowed to be null 4032 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}. 4033 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4034 * requesting audio focus. 4035 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4036 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 4037 * for the playback of driving directions, or notifications sounds. 4038 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4039 * the previous focus owner to keep playing if it ducks its audio output. 4040 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4041 * that benefits from the system not playing disruptive sounds like notifications, for 4042 * usecases such as voice memo recording, or speech recognition. 4043 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4044 * as the playback of a song or a video. 4045 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4046 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}. 4047 * <br>Use 0 when not using any flags for the request, which behaves like 4048 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4049 * focus is granted immediately, or the grant request fails because the system is in a 4050 * state where focus cannot change (e.g. a phone call). 4051 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4052 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4053 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested 4054 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag. 4055 * @throws IllegalArgumentException 4056 */ 4057 @SystemApi 4058 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)4059 public int requestAudioFocus(OnAudioFocusChangeListener l, 4060 @NonNull AudioAttributes requestAttributes, 4061 int durationHint, 4062 int flags) throws IllegalArgumentException { 4063 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) { 4064 throw new IllegalArgumentException("Invalid flags 0x" 4065 + Integer.toHexString(flags).toUpperCase()); 4066 } 4067 return requestAudioFocus(l, requestAttributes, durationHint, 4068 flags & AUDIOFOCUS_FLAGS_APPS, 4069 null /* no AudioPolicy*/); 4070 } 4071 4072 /** 4073 * @hide 4074 * Request or lock audio focus. 4075 * This method is to be used by system components that have registered an 4076 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4077 * so focus granting is temporarily disabled. 4078 * @param l see the description of the same parameter in 4079 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4080 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4081 * requesting audio focus. 4082 * @param durationHint see the description of the same parameter in 4083 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4084 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4085 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}. 4086 * <br>Use 0 when not using any flags for the request, which behaves like 4087 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4088 * focus is granted immediately, or the grant request fails because the system is in a 4089 * state where focus cannot change (e.g. a phone call). 4090 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4091 * focus, or null. 4092 * @return see the description of the same return value in 4093 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4094 * @throws IllegalArgumentException 4095 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} 4096 */ 4097 @SystemApi 4098 @RequiresPermission(anyOf= { 4099 android.Manifest.permission.MODIFY_PHONE_STATE, 4100 android.Manifest.permission.MODIFY_AUDIO_ROUTING 4101 }) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)4102 public int requestAudioFocus(OnAudioFocusChangeListener l, 4103 @NonNull AudioAttributes requestAttributes, 4104 int durationHint, 4105 int flags, 4106 AudioPolicy ap) throws IllegalArgumentException { 4107 // parameter checking 4108 if (requestAttributes == null) { 4109 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 4110 } 4111 if (!AudioFocusRequest.isValidFocusGain(durationHint)) { 4112 throw new IllegalArgumentException("Invalid duration hint"); 4113 } 4114 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) { 4115 throw new IllegalArgumentException("Illegal flags 0x" 4116 + Integer.toHexString(flags).toUpperCase()); 4117 } 4118 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) { 4119 throw new IllegalArgumentException( 4120 "Illegal null focus listener when flagged as accepting delayed focus grant"); 4121 } 4122 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4123 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { 4124 throw new IllegalArgumentException( 4125 "Illegal null focus listener when flagged as pausing instead of ducking"); 4126 } 4127 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { 4128 throw new IllegalArgumentException( 4129 "Illegal null audio policy when locking audio focus"); 4130 } 4131 4132 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint) 4133 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */) 4134 .setAudioAttributes(requestAttributes) 4135 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) 4136 == AUDIOFOCUS_FLAG_DELAY_OK) 4137 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4138 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4139 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) 4140 .build(); 4141 return requestAudioFocus(afr, ap); 4142 } 4143 4144 /** 4145 * @hide 4146 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID. 4147 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4148 * @param afr the parameters of the request 4149 * @param clientFakeId the identifier of the AudioManager the client would be requesting from 4150 * @param clientFakeUid the UID of the client, here an arbitrary int, 4151 * doesn't have to be a real UID 4152 * @param clientTargetSdk the target SDK used by the client 4153 * @return return code indicating status of the request 4154 */ 4155 @TestApi 4156 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4157 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr, 4158 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) { 4159 Objects.requireNonNull(afr); 4160 Objects.requireNonNull(clientFakeId); 4161 try { 4162 return getService().requestAudioFocusForTest(afr.getAudioAttributes(), 4163 afr.getFocusGain(), 4164 mICallBack, 4165 mAudioFocusDispatcher, 4166 clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk); 4167 } catch (RemoteException e) { 4168 throw e.rethrowFromSystemServer(); 4169 } 4170 } 4171 4172 /** 4173 * @hide 4174 * Test API to abandon audio focus for an arbitrary client. 4175 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4176 * @param afr the parameters used for the request 4177 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client 4178 * would be requesting 4179 * @return return code indicating status of the request 4180 */ 4181 @TestApi 4182 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4183 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr, 4184 @NonNull String clientFakeId) { 4185 Objects.requireNonNull(afr); 4186 Objects.requireNonNull(clientFakeId); 4187 try { 4188 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher, 4189 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient"); 4190 } catch (RemoteException e) { 4191 throw e.rethrowFromSystemServer(); 4192 } 4193 } 4194 4195 /** 4196 * @hide 4197 * Return the duration of the fade out applied when a player of the given AudioAttributes 4198 * is losing audio focus 4199 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS} 4200 * @return a duration in ms, 0 indicates no fade out is applied 4201 */ 4202 @TestApi 4203 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4204 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa) 4205 { 4206 Objects.requireNonNull(aa); 4207 try { 4208 return getService().getFadeOutDurationOnFocusLossMillis(aa); 4209 } catch (RemoteException e) { 4210 throw e.rethrowFromSystemServer(); 4211 } 4212 } 4213 4214 /** 4215 * @hide 4216 * Request or lock audio focus. 4217 * This method is to be used by system components that have registered an 4218 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4219 * so focus granting is temporarily disabled. 4220 * @param afr see the description of the same parameter in 4221 * {@link #requestAudioFocus(AudioFocusRequest)} 4222 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4223 * focus, or null. 4224 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4225 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4226 * @throws NullPointerException if the AudioFocusRequest is null 4227 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy 4228 */ 4229 @SystemApi 4230 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)4231 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { 4232 if (afr == null) { 4233 throw new NullPointerException("Illegal null AudioFocusRequest"); 4234 } 4235 // this can only be checked now, not during the creation of the AudioFocusRequest instance 4236 if (afr.locksFocus() && ap == null) { 4237 throw new IllegalArgumentException( 4238 "Illegal null audio policy when locking audio focus"); 4239 } 4240 registerAudioFocusRequest(afr); 4241 final IAudioService service = getService(); 4242 final int status; 4243 int sdk; 4244 try { 4245 sdk = getContext().getApplicationInfo().targetSdkVersion; 4246 } catch (NullPointerException e) { 4247 // some tests don't have a Context 4248 sdk = Build.VERSION.SDK_INT; 4249 } 4250 4251 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 4252 final BlockingFocusResultReceiver focusReceiver; 4253 synchronized (mFocusRequestsLock) { 4254 try { 4255 // TODO status contains result and generation counter for ext policy 4256 status = service.requestAudioFocus(afr.getAudioAttributes(), 4257 afr.getFocusGain(), mICallBack, 4258 mAudioFocusDispatcher, 4259 clientId, 4260 getContext().getOpPackageName() /* package name */, afr.getFlags(), 4261 ap != null ? ap.cb() : null, 4262 sdk); 4263 } catch (RemoteException e) { 4264 throw e.rethrowFromSystemServer(); 4265 } 4266 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 4267 // default path with no external focus policy 4268 return status; 4269 } 4270 if (mFocusRequestsAwaitingResult == null) { 4271 mFocusRequestsAwaitingResult = 4272 new HashMap<String, BlockingFocusResultReceiver>(1); 4273 } 4274 focusReceiver = new BlockingFocusResultReceiver(clientId); 4275 mFocusRequestsAwaitingResult.put(clientId, focusReceiver); 4276 } 4277 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS); 4278 if (DEBUG && !focusReceiver.receivedResult()) { 4279 Log.e(TAG, "requestAudio response from ext policy timed out, denying request"); 4280 } 4281 synchronized (mFocusRequestsLock) { 4282 mFocusRequestsAwaitingResult.remove(clientId); 4283 } 4284 return focusReceiver.requestResult(); 4285 } 4286 4287 // helper class that abstracts out the handling of spurious wakeups in Object.wait() 4288 private static final class SafeWaitObject { 4289 private boolean mQuit = false; 4290 safeNotify()4291 public void safeNotify() { 4292 synchronized (this) { 4293 mQuit = true; 4294 this.notify(); 4295 } 4296 } 4297 safeWait(long millis)4298 public void safeWait(long millis) throws InterruptedException { 4299 final long timeOutTime = java.lang.System.currentTimeMillis() + millis; 4300 synchronized (this) { 4301 while (!mQuit) { 4302 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis(); 4303 if (timeToWait < 0) { break; } 4304 this.wait(timeToWait); 4305 } 4306 } 4307 } 4308 } 4309 4310 private static final class BlockingFocusResultReceiver { 4311 private final SafeWaitObject mLock = new SafeWaitObject(); 4312 @GuardedBy("mLock") 4313 private boolean mResultReceived = false; 4314 // request denied by default (e.g. timeout) 4315 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4316 private final String mFocusClientId; 4317 BlockingFocusResultReceiver(String clientId)4318 BlockingFocusResultReceiver(String clientId) { 4319 mFocusClientId = clientId; 4320 } 4321 receivedResult()4322 boolean receivedResult() { return mResultReceived; } requestResult()4323 int requestResult() { return mFocusRequestResult; } 4324 notifyResult(int requestResult)4325 void notifyResult(int requestResult) { 4326 synchronized (mLock) { 4327 mResultReceived = true; 4328 mFocusRequestResult = requestResult; 4329 mLock.safeNotify(); 4330 } 4331 } 4332 waitForResult(long timeOutMs)4333 public void waitForResult(long timeOutMs) { 4334 synchronized (mLock) { 4335 if (mResultReceived) { 4336 // the result was received before waiting 4337 return; 4338 } 4339 try { 4340 mLock.safeWait(timeOutMs); 4341 } catch (InterruptedException e) { } 4342 } 4343 } 4344 } 4345 4346 /** 4347 * @hide 4348 * Used internally by telephony package to request audio focus. Will cause the focus request 4349 * to be associated with the "voice communication" identifier only used in AudioService 4350 * to identify this use case. 4351 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 4352 * the establishment of the call 4353 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 4354 * media applications resume after a call 4355 */ 4356 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) requestAudioFocusForCall(int streamType, int durationHint)4357 public void requestAudioFocusForCall(int streamType, int durationHint) { 4358 final IAudioService service = getService(); 4359 try { 4360 service.requestAudioFocus(new AudioAttributes.Builder() 4361 .setInternalLegacyStreamType(streamType).build(), 4362 durationHint, mICallBack, null, 4363 AudioSystem.IN_VOICE_COMM_FOCUS_ID, 4364 getContext().getOpPackageName(), 4365 AUDIOFOCUS_FLAG_LOCK, 4366 null /* policy token */, 0 /* sdk n/a here*/); 4367 } catch (RemoteException e) { 4368 throw e.rethrowFromSystemServer(); 4369 } 4370 } 4371 4372 /** 4373 * @hide 4374 * Return the volume ramping time for a sound to be played after the given focus request, 4375 * and to play a sound of the given attributes 4376 * @param focusGain 4377 * @param attr 4378 * @return 4379 */ getFocusRampTimeMs(int focusGain, AudioAttributes attr)4380 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 4381 final IAudioService service = getService(); 4382 try { 4383 return service.getFocusRampTimeMs(focusGain, attr); 4384 } catch (RemoteException e) { 4385 throw e.rethrowFromSystemServer(); 4386 } 4387 } 4388 4389 /** 4390 * @hide 4391 * Set the result to the audio focus request received through 4392 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 4393 * @param afi the information about the focus requester 4394 * @param requestResult the result to the focus request to be passed to the requester 4395 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 4396 */ 4397 @SystemApi 4398 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)4399 public void setFocusRequestResult(@NonNull AudioFocusInfo afi, 4400 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) { 4401 if (afi == null) { 4402 throw new IllegalArgumentException("Illegal null AudioFocusInfo"); 4403 } 4404 if (ap == null) { 4405 throw new IllegalArgumentException("Illegal null AudioPolicy"); 4406 } 4407 final IAudioService service = getService(); 4408 try { 4409 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); 4410 } catch (RemoteException e) { 4411 throw e.rethrowFromSystemServer(); 4412 } 4413 } 4414 4415 /** 4416 * @hide 4417 * Notifies an application with a focus listener of gain or loss of audio focus. 4418 * This method can only be used by owners of an {@link AudioPolicy} configured with 4419 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 4420 * @param afi the recipient of the focus change, that has previously requested audio focus, and 4421 * that was received by the {@code AudioPolicy} through 4422 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 4423 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 4424 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 4425 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 4426 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 4427 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 4428 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 4429 * <br>For the focus gain, the change type should be the same as the app requested. 4430 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 4431 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or 4432 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or 4433 * if there was an error sending the request. 4434 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. 4435 */ 4436 @SystemApi 4437 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)4438 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, 4439 @NonNull AudioPolicy ap) { 4440 if (afi == null) { 4441 throw new NullPointerException("Illegal null AudioFocusInfo"); 4442 } 4443 if (ap == null) { 4444 throw new NullPointerException("Illegal null AudioPolicy"); 4445 } 4446 final IAudioService service = getService(); 4447 try { 4448 return service.dispatchFocusChange(afi, focusChange, ap.cb()); 4449 } catch (RemoteException e) { 4450 throw e.rethrowFromSystemServer(); 4451 } 4452 } 4453 4454 /** 4455 * @hide 4456 * Used internally by telephony package to abandon audio focus, typically after a call or 4457 * when ringing ends and the call is rejected or not answered. 4458 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 4459 */ 4460 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) abandonAudioFocusForCall()4461 public void abandonAudioFocusForCall() { 4462 final IAudioService service = getService(); 4463 try { 4464 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, 4465 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); 4466 } catch (RemoteException e) { 4467 throw e.rethrowFromSystemServer(); 4468 } 4469 } 4470 4471 /** 4472 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4473 * @param l the listener with which focus was requested. 4474 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4475 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 4476 */ abandonAudioFocus(OnAudioFocusChangeListener l)4477 public int abandonAudioFocus(OnAudioFocusChangeListener l) { 4478 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/); 4479 } 4480 4481 /** 4482 * @hide 4483 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4484 * @param l the listener with which focus was requested. 4485 * @param aa the {@link AudioAttributes} with which audio focus was requested 4486 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4487 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 4488 */ 4489 @SystemApi 4490 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would 4491 // have been done by a matching requestAudioFocus abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)4492 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { 4493 int status = AUDIOFOCUS_REQUEST_FAILED; 4494 unregisterAudioFocusRequest(l); 4495 final IAudioService service = getService(); 4496 try { 4497 status = service.abandonAudioFocus(mAudioFocusDispatcher, 4498 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); 4499 } catch (RemoteException e) { 4500 throw e.rethrowFromSystemServer(); 4501 } 4502 return status; 4503 } 4504 4505 //==================================================================== 4506 // Remote Control 4507 /** 4508 * Register a component to be the sole receiver of MEDIA_BUTTON intents. 4509 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 4510 * that will receive the media button intent. This broadcast receiver must be declared 4511 * in the application manifest. The package of the component must match that of 4512 * the context you're registering from. 4513 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 4514 */ 4515 @Deprecated registerMediaButtonEventReceiver(ComponentName eventReceiver)4516 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 4517 if (eventReceiver == null) { 4518 return; 4519 } 4520 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) { 4521 Log.e(TAG, "registerMediaButtonEventReceiver() error: " + 4522 "receiver and context package names don't match"); 4523 return; 4524 } 4525 // construct a PendingIntent for the media button and register it 4526 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4527 // the associated intent will be handled by the component being registered 4528 mediaButtonIntent.setComponent(eventReceiver); 4529 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 4530 0/*requestCode, ignored*/, mediaButtonIntent, 4531 PendingIntent.FLAG_IMMUTABLE); 4532 registerMediaButtonIntent(pi, eventReceiver); 4533 } 4534 4535 /** 4536 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like 4537 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows 4538 * the buttons to go to any PendingIntent. Note that you should only use this form if 4539 * you know you will continue running for the full time until unregistering the 4540 * PendingIntent. 4541 * @param eventReceiver target that will receive media button intents. The PendingIntent 4542 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action 4543 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the 4544 * media button that was pressed. 4545 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 4546 */ 4547 @Deprecated registerMediaButtonEventReceiver(PendingIntent eventReceiver)4548 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { 4549 if (eventReceiver == null) { 4550 return; 4551 } 4552 registerMediaButtonIntent(eventReceiver, null); 4553 } 4554 4555 /** 4556 * @hide 4557 * no-op if (pi == null) or (eventReceiver == null) 4558 */ registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)4559 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) { 4560 if (pi == null) { 4561 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter"); 4562 return; 4563 } 4564 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 4565 helper.addMediaButtonListener(pi, eventReceiver, getContext()); 4566 } 4567 4568 /** 4569 * Unregister the receiver of MEDIA_BUTTON intents. 4570 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 4571 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. 4572 * @deprecated Use {@link MediaSession} instead. 4573 */ 4574 @Deprecated unregisterMediaButtonEventReceiver(ComponentName eventReceiver)4575 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 4576 if (eventReceiver == null) { 4577 return; 4578 } 4579 // construct a PendingIntent for the media button and unregister it 4580 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4581 // the associated intent will be handled by the component being registered 4582 mediaButtonIntent.setComponent(eventReceiver); 4583 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 4584 0/*requestCode, ignored*/, mediaButtonIntent, 4585 PendingIntent.FLAG_IMMUTABLE); 4586 unregisterMediaButtonIntent(pi); 4587 } 4588 4589 /** 4590 * Unregister the receiver of MEDIA_BUTTON intents. 4591 * @param eventReceiver same PendingIntent that was registed with 4592 * {@link #registerMediaButtonEventReceiver(PendingIntent)}. 4593 * @deprecated Use {@link MediaSession} instead. 4594 */ 4595 @Deprecated unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)4596 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { 4597 if (eventReceiver == null) { 4598 return; 4599 } 4600 unregisterMediaButtonIntent(eventReceiver); 4601 } 4602 4603 /** 4604 * @hide 4605 */ unregisterMediaButtonIntent(PendingIntent pi)4606 public void unregisterMediaButtonIntent(PendingIntent pi) { 4607 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 4608 helper.removeMediaButtonListener(pi); 4609 } 4610 4611 /** 4612 * Registers the remote control client for providing information to display on the remote 4613 * controls. 4614 * @param rcClient The remote control client from which remote controls will receive 4615 * information to display. 4616 * @see RemoteControlClient 4617 * @deprecated Use {@link MediaSession} instead. 4618 */ 4619 @Deprecated registerRemoteControlClient(RemoteControlClient rcClient)4620 public void registerRemoteControlClient(RemoteControlClient rcClient) { 4621 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 4622 return; 4623 } 4624 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 4625 } 4626 4627 /** 4628 * Unregisters the remote control client that was providing information to display on the 4629 * remote controls. 4630 * @param rcClient The remote control client to unregister. 4631 * @see #registerRemoteControlClient(RemoteControlClient) 4632 * @deprecated Use {@link MediaSession} instead. 4633 */ 4634 @Deprecated unregisterRemoteControlClient(RemoteControlClient rcClient)4635 public void unregisterRemoteControlClient(RemoteControlClient rcClient) { 4636 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 4637 return; 4638 } 4639 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 4640 } 4641 4642 /** 4643 * Registers a {@link RemoteController} instance for it to receive media 4644 * metadata updates and playback state information from applications using 4645 * {@link RemoteControlClient}, and control their playback. 4646 * <p> 4647 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be 4648 * one of the enabled notification listeners (see 4649 * {@link android.service.notification.NotificationListenerService}). 4650 * 4651 * @param rctlr the object to register. 4652 * @return true if the {@link RemoteController} was successfully registered, 4653 * false if an error occurred, due to an internal system error, or 4654 * insufficient permissions. 4655 * @deprecated Use 4656 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)} 4657 * and {@link MediaController} instead. 4658 */ 4659 @Deprecated registerRemoteController(RemoteController rctlr)4660 public boolean registerRemoteController(RemoteController rctlr) { 4661 if (rctlr == null) { 4662 return false; 4663 } 4664 rctlr.startListeningToSessions(); 4665 return true; 4666 } 4667 4668 /** 4669 * Unregisters a {@link RemoteController}, causing it to no longer receive 4670 * media metadata and playback state information, and no longer be capable 4671 * of controlling playback. 4672 * 4673 * @param rctlr the object to unregister. 4674 * @deprecated Use 4675 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)} 4676 * instead. 4677 */ 4678 @Deprecated unregisterRemoteController(RemoteController rctlr)4679 public void unregisterRemoteController(RemoteController rctlr) { 4680 if (rctlr == null) { 4681 return; 4682 } 4683 rctlr.stopListeningToSessions(); 4684 } 4685 4686 4687 //==================================================================== 4688 // Audio policy 4689 /** 4690 * @hide 4691 * Register the given {@link AudioPolicy}. 4692 * This call is synchronous and blocks until the registration process successfully completed 4693 * or failed to complete. 4694 * @param policy the non-null {@link AudioPolicy} to register. 4695 * @return {@link #ERROR} if there was an error communicating with the registration service 4696 * or if the user doesn't have the required 4697 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission, 4698 * {@link #SUCCESS} otherwise. 4699 */ 4700 @SystemApi 4701 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) registerAudioPolicy(@onNull AudioPolicy policy)4702 public int registerAudioPolicy(@NonNull AudioPolicy policy) { 4703 return registerAudioPolicyStatic(policy); 4704 } 4705 registerAudioPolicyStatic(@onNull AudioPolicy policy)4706 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) { 4707 if (policy == null) { 4708 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 4709 } 4710 final IAudioService service = getService(); 4711 try { 4712 MediaProjection projection = policy.getMediaProjection(); 4713 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), 4714 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(), 4715 policy.isVolumeController(), 4716 projection == null ? null : projection.getProjection()); 4717 if (regId == null) { 4718 return ERROR; 4719 } else { 4720 policy.setRegistration(regId); 4721 } 4722 // successful registration 4723 } catch (RemoteException e) { 4724 throw e.rethrowFromSystemServer(); 4725 } 4726 return SUCCESS; 4727 } 4728 4729 /** 4730 * @hide 4731 * Unregisters an {@link AudioPolicy} asynchronously. 4732 * @param policy the non-null {@link AudioPolicy} to unregister. 4733 */ 4734 @SystemApi 4735 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicyAsync(@onNull AudioPolicy policy)4736 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { 4737 unregisterAudioPolicyAsyncStatic(policy); 4738 } 4739 unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)4740 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) { 4741 if (policy == null) { 4742 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 4743 } 4744 final IAudioService service = getService(); 4745 try { 4746 service.unregisterAudioPolicyAsync(policy.cb()); 4747 policy.reset(); 4748 } catch (RemoteException e) { 4749 throw e.rethrowFromSystemServer(); 4750 } 4751 } 4752 4753 /** 4754 * @hide 4755 * Unregisters an {@link AudioPolicy} synchronously. 4756 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects 4757 * associated with mixes of this policy. 4758 * @param policy the non-null {@link AudioPolicy} to unregister. 4759 */ 4760 @SystemApi 4761 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicy(@onNull AudioPolicy policy)4762 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { 4763 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); 4764 final IAudioService service = getService(); 4765 try { 4766 policy.invalidateCaptorsAndInjectors(); 4767 service.unregisterAudioPolicy(policy.cb()); 4768 policy.reset(); 4769 } catch (RemoteException e) { 4770 throw e.rethrowFromSystemServer(); 4771 } 4772 } 4773 4774 /** 4775 * @hide 4776 * @return true if an AudioPolicy was previously registered 4777 */ 4778 @TestApi hasRegisteredDynamicPolicy()4779 public boolean hasRegisteredDynamicPolicy() { 4780 final IAudioService service = getService(); 4781 try { 4782 return service.hasRegisteredDynamicPolicy(); 4783 } catch (RemoteException e) { 4784 throw e.rethrowFromSystemServer(); 4785 } 4786 } 4787 4788 //==================================================================== 4789 // Notification of playback activity & playback configuration 4790 /** 4791 * Interface for receiving update notifications about the playback activity on the system. 4792 * Extend this abstract class and register it with 4793 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)} 4794 * to be notified. 4795 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current 4796 * configuration. 4797 * @see AudioPlaybackConfiguration 4798 */ 4799 public static abstract class AudioPlaybackCallback { 4800 /** 4801 * Called whenever the playback activity and configuration has changed. 4802 * @param configs list containing the results of 4803 * {@link AudioManager#getActivePlaybackConfigurations()}. 4804 */ onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)4805 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {} 4806 } 4807 4808 private static class AudioPlaybackCallbackInfo { 4809 final AudioPlaybackCallback mCb; 4810 final Handler mHandler; AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)4811 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) { 4812 mCb = cb; 4813 mHandler = handler; 4814 } 4815 } 4816 4817 private final static class PlaybackConfigChangeCallbackData { 4818 final AudioPlaybackCallback mCb; 4819 final List<AudioPlaybackConfiguration> mConfigs; 4820 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)4821 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, 4822 List<AudioPlaybackConfiguration> configs) { 4823 mCb = cb; 4824 mConfigs = configs; 4825 } 4826 } 4827 4828 /** 4829 * Register a callback to be notified of audio playback changes through 4830 * {@link AudioPlaybackCallback} 4831 * @param cb non-null callback to register 4832 * @param handler the {@link Handler} object for the thread on which to execute 4833 * the callback. If <code>null</code>, the {@link Handler} associated with the main 4834 * {@link Looper} will be used. 4835 */ registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)4836 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb, 4837 @Nullable Handler handler) 4838 { 4839 if (cb == null) { 4840 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 4841 } 4842 4843 synchronized(mPlaybackCallbackLock) { 4844 // lazy initialization of the list of playback callbacks 4845 if (mPlaybackCallbackList == null) { 4846 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>(); 4847 } 4848 final int oldCbCount = mPlaybackCallbackList.size(); 4849 if (!hasPlaybackCallback_sync(cb)) { 4850 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb, 4851 new ServiceEventHandlerDelegate(handler).getHandler())); 4852 final int newCbCount = mPlaybackCallbackList.size(); 4853 if ((oldCbCount == 0) && (newCbCount > 0)) { 4854 // register binder for callbacks 4855 try { 4856 getService().registerPlaybackCallback(mPlayCb); 4857 } catch (RemoteException e) { 4858 throw e.rethrowFromSystemServer(); 4859 } 4860 } 4861 } else { 4862 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously" 4863 + "registered callback"); 4864 } 4865 } 4866 } 4867 4868 /** 4869 * Unregister an audio playback callback previously registered with 4870 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 4871 * @param cb non-null callback to unregister 4872 */ unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)4873 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) { 4874 if (cb == null) { 4875 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 4876 } 4877 synchronized(mPlaybackCallbackLock) { 4878 if (mPlaybackCallbackList == null) { 4879 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 4880 + " that was never registered"); 4881 return; 4882 } 4883 final int oldCbCount = mPlaybackCallbackList.size(); 4884 if (removePlaybackCallback_sync(cb)) { 4885 final int newCbCount = mPlaybackCallbackList.size(); 4886 if ((oldCbCount > 0) && (newCbCount == 0)) { 4887 // unregister binder for callbacks 4888 try { 4889 getService().unregisterPlaybackCallback(mPlayCb); 4890 } catch (RemoteException e) { 4891 throw e.rethrowFromSystemServer(); 4892 } 4893 } 4894 } else { 4895 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 4896 + " already unregistered or never registered"); 4897 } 4898 } 4899 } 4900 4901 /** 4902 * Returns the current active audio playback configurations of the device 4903 * @return a non-null list of playback configurations. An empty list indicates there is no 4904 * playback active when queried. 4905 * @see AudioPlaybackConfiguration 4906 */ getActivePlaybackConfigurations()4907 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { 4908 final IAudioService service = getService(); 4909 try { 4910 return service.getActivePlaybackConfigurations(); 4911 } catch (RemoteException e) { 4912 throw e.rethrowFromSystemServer(); 4913 } 4914 } 4915 4916 /** 4917 * All operations on this list are sync'd on mPlaybackCallbackLock. 4918 * List is lazy-initialized in 4919 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 4920 * List can be null. 4921 */ 4922 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList; 4923 private final Object mPlaybackCallbackLock = new Object(); 4924 4925 /** 4926 * Must be called synchronized on mPlaybackCallbackLock 4927 */ hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4928 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 4929 if (mPlaybackCallbackList != null) { 4930 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4931 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 4932 return true; 4933 } 4934 } 4935 } 4936 return false; 4937 } 4938 4939 /** 4940 * Must be called synchronized on mPlaybackCallbackLock 4941 */ removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4942 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 4943 if (mPlaybackCallbackList != null) { 4944 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4945 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 4946 mPlaybackCallbackList.remove(i); 4947 return true; 4948 } 4949 } 4950 } 4951 return false; 4952 } 4953 4954 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { 4955 @Override 4956 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, 4957 boolean flush) { 4958 if (flush) { 4959 Binder.flushPendingCommands(); 4960 } 4961 synchronized(mPlaybackCallbackLock) { 4962 if (mPlaybackCallbackList != null) { 4963 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 4964 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i); 4965 if (arci.mHandler != null) { 4966 final Message m = arci.mHandler.obtainMessage( 4967 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/, 4968 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 4969 arci.mHandler.sendMessage(m); 4970 } 4971 } 4972 } 4973 } 4974 } 4975 4976 }; 4977 4978 //==================================================================== 4979 // Notification of recording activity & recording configuration 4980 /** 4981 * Interface for receiving update notifications about the recording configuration. Extend 4982 * this abstract class and register it with 4983 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)} 4984 * to be notified. 4985 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current 4986 * configuration. 4987 * @see AudioRecordingConfiguration 4988 */ 4989 public static abstract class AudioRecordingCallback { 4990 /** 4991 * Called whenever the device recording configuration has changed. 4992 * @param configs list containing the results of 4993 * {@link AudioManager#getActiveRecordingConfigurations()}. 4994 */ onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)4995 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {} 4996 } 4997 4998 private static class AudioRecordingCallbackInfo { 4999 final AudioRecordingCallback mCb; 5000 final Handler mHandler; AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5001 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) { 5002 mCb = cb; 5003 mHandler = handler; 5004 } 5005 } 5006 5007 private final static class RecordConfigChangeCallbackData { 5008 final AudioRecordingCallback mCb; 5009 final List<AudioRecordingConfiguration> mConfigs; 5010 RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5011 RecordConfigChangeCallbackData(AudioRecordingCallback cb, 5012 List<AudioRecordingConfiguration> configs) { 5013 mCb = cb; 5014 mConfigs = configs; 5015 } 5016 } 5017 5018 /** 5019 * Register a callback to be notified of audio recording changes through 5020 * {@link AudioRecordingCallback} 5021 * @param cb non-null callback to register 5022 * @param handler the {@link Handler} object for the thread on which to execute 5023 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5024 * {@link Looper} will be used. 5025 */ registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5026 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, 5027 @Nullable Handler handler) 5028 { 5029 if (cb == null) { 5030 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5031 } 5032 5033 synchronized(mRecordCallbackLock) { 5034 // lazy initialization of the list of recording callbacks 5035 if (mRecordCallbackList == null) { 5036 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>(); 5037 } 5038 final int oldCbCount = mRecordCallbackList.size(); 5039 if (!hasRecordCallback_sync(cb)) { 5040 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb, 5041 new ServiceEventHandlerDelegate(handler).getHandler())); 5042 final int newCbCount = mRecordCallbackList.size(); 5043 if ((oldCbCount == 0) && (newCbCount > 0)) { 5044 // register binder for callbacks 5045 final IAudioService service = getService(); 5046 try { 5047 service.registerRecordingCallback(mRecCb); 5048 } catch (RemoteException e) { 5049 throw e.rethrowFromSystemServer(); 5050 } 5051 } 5052 } else { 5053 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously" 5054 + "registered callback"); 5055 } 5056 } 5057 } 5058 5059 /** 5060 * Unregister an audio recording callback previously registered with 5061 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5062 * @param cb non-null callback to unregister 5063 */ unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5064 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) { 5065 if (cb == null) { 5066 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5067 } 5068 synchronized(mRecordCallbackLock) { 5069 if (mRecordCallbackList == null) { 5070 return; 5071 } 5072 final int oldCbCount = mRecordCallbackList.size(); 5073 if (removeRecordCallback_sync(cb)) { 5074 final int newCbCount = mRecordCallbackList.size(); 5075 if ((oldCbCount > 0) && (newCbCount == 0)) { 5076 // unregister binder for callbacks 5077 final IAudioService service = getService(); 5078 try { 5079 service.unregisterRecordingCallback(mRecCb); 5080 } catch (RemoteException e) { 5081 throw e.rethrowFromSystemServer(); 5082 } 5083 } 5084 } else { 5085 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback" 5086 + " already unregistered or never registered"); 5087 } 5088 } 5089 } 5090 5091 /** 5092 * Returns the current active audio recording configurations of the device. 5093 * @return a non-null list of recording configurations. An empty list indicates there is 5094 * no recording active when queried. 5095 * @see AudioRecordingConfiguration 5096 */ getActiveRecordingConfigurations()5097 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { 5098 final IAudioService service = getService(); 5099 try { 5100 return service.getActiveRecordingConfigurations(); 5101 } catch (RemoteException e) { 5102 throw e.rethrowFromSystemServer(); 5103 } 5104 } 5105 5106 /** 5107 * constants for the recording events, to keep in sync 5108 * with frameworks/av/include/media/AudioPolicy.h 5109 */ 5110 /** @hide */ 5111 public static final int RECORD_CONFIG_EVENT_NONE = -1; 5112 /** @hide */ 5113 public static final int RECORD_CONFIG_EVENT_START = 0; 5114 /** @hide */ 5115 public static final int RECORD_CONFIG_EVENT_STOP = 1; 5116 /** @hide */ 5117 public static final int RECORD_CONFIG_EVENT_UPDATE = 2; 5118 /** @hide */ 5119 public static final int RECORD_CONFIG_EVENT_RELEASE = 3; 5120 /** 5121 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h 5122 */ 5123 /** @hide */ 5124 public static final int RECORD_RIID_INVALID = -1; 5125 /** @hide */ 5126 public static final int RECORDER_STATE_STARTED = 0; 5127 /** @hide */ 5128 public static final int RECORDER_STATE_STOPPED = 1; 5129 5130 /** 5131 * All operations on this list are sync'd on mRecordCallbackLock. 5132 * List is lazy-initialized in 5133 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5134 * List can be null. 5135 */ 5136 private List<AudioRecordingCallbackInfo> mRecordCallbackList; 5137 private final Object mRecordCallbackLock = new Object(); 5138 5139 /** 5140 * Must be called synchronized on mRecordCallbackLock 5141 */ hasRecordCallback_sync(@onNull AudioRecordingCallback cb)5142 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5143 if (mRecordCallbackList != null) { 5144 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5145 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5146 return true; 5147 } 5148 } 5149 } 5150 return false; 5151 } 5152 5153 /** 5154 * Must be called synchronized on mRecordCallbackLock 5155 */ removeRecordCallback_sync(@onNull AudioRecordingCallback cb)5156 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 5157 if (mRecordCallbackList != null) { 5158 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5159 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 5160 mRecordCallbackList.remove(i); 5161 return true; 5162 } 5163 } 5164 } 5165 return false; 5166 } 5167 5168 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { 5169 @Override 5170 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { 5171 synchronized(mRecordCallbackLock) { 5172 if (mRecordCallbackList != null) { 5173 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 5174 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i); 5175 if (arci.mHandler != null) { 5176 final Message m = arci.mHandler.obtainMessage( 5177 MSSG_RECORDING_CONFIG_CHANGE/*what*/, 5178 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 5179 arci.mHandler.sendMessage(m); 5180 } 5181 } 5182 } 5183 } 5184 } 5185 5186 }; 5187 5188 //===================================================================== 5189 5190 /** 5191 * @hide 5192 * Reload audio settings. This method is called by Settings backup 5193 * agent when audio settings are restored and causes the AudioService 5194 * to read and apply restored settings. 5195 */ 5196 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) reloadAudioSettings()5197 public void reloadAudioSettings() { 5198 final IAudioService service = getService(); 5199 try { 5200 service.reloadAudioSettings(); 5201 } catch (RemoteException e) { 5202 throw e.rethrowFromSystemServer(); 5203 } 5204 } 5205 5206 /** 5207 * @hide 5208 * Notifies AudioService that it is connected to an A2DP device that supports absolute volume, 5209 * so that AudioService can send volume change events to the A2DP device, rather than handling 5210 * them. 5211 */ avrcpSupportsAbsoluteVolume(String address, boolean support)5212 public void avrcpSupportsAbsoluteVolume(String address, boolean support) { 5213 final IAudioService service = getService(); 5214 try { 5215 service.avrcpSupportsAbsoluteVolume(address, support); 5216 } catch (RemoteException e) { 5217 throw e.rethrowFromSystemServer(); 5218 } 5219 } 5220 5221 /** 5222 * {@hide} 5223 */ 5224 private final IBinder mICallBack = new Binder(); 5225 5226 /** 5227 * Checks whether the phone is in silent mode, with or without vibrate. 5228 * 5229 * @return true if phone is in silent mode, with or without vibrate. 5230 * 5231 * @see #getRingerMode() 5232 * 5233 * @hide pending API Council approval 5234 */ 5235 @UnsupportedAppUsage isSilentMode()5236 public boolean isSilentMode() { 5237 int ringerMode = getRingerMode(); 5238 boolean silentMode = 5239 (ringerMode == RINGER_MODE_SILENT) || 5240 (ringerMode == RINGER_MODE_VIBRATE); 5241 return silentMode; 5242 } 5243 5244 // This section re-defines new output device constants from AudioSystem, because the AudioSystem 5245 // class is not used by other parts of the framework, which instead use definitions and methods 5246 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. 5247 5248 /** @hide 5249 * The audio device code for representing "no device." */ 5250 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; 5251 /** @hide 5252 * The audio output device code for the small speaker at the front of the device used 5253 * when placing calls. Does not refer to an in-ear headphone without attached microphone, 5254 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a 5255 * {@link #DEVICE_OUT_WIRED_HEADPHONE}. 5256 */ 5257 @UnsupportedAppUsage 5258 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; 5259 /** @hide 5260 * The audio output device code for the built-in speaker */ 5261 @UnsupportedAppUsage 5262 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; 5263 /** @hide 5264 * The audio output device code for a wired headset with attached microphone */ 5265 @UnsupportedAppUsage 5266 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 5267 /** @hide 5268 * The audio output device code for a wired headphone without attached microphone */ 5269 @UnsupportedAppUsage 5270 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 5271 /** @hide 5272 * The audio output device code for a USB headphone with attached microphone */ 5273 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET; 5274 /** @hide 5275 * The audio output device code for generic Bluetooth SCO, for voice */ 5276 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 5277 /** @hide 5278 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and 5279 * Hands-Free Profile (HFP), for voice 5280 */ 5281 @UnsupportedAppUsage 5282 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 5283 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 5284 /** @hide 5285 * The audio output device code for Bluetooth SCO car audio, for voice */ 5286 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 5287 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 5288 /** @hide 5289 * The audio output device code for generic Bluetooth A2DP, for music */ 5290 @UnsupportedAppUsage 5291 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 5292 /** @hide 5293 * The audio output device code for Bluetooth A2DP headphones, for music */ 5294 @UnsupportedAppUsage 5295 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 5296 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; 5297 /** @hide 5298 * The audio output device code for Bluetooth A2DP external speaker, for music */ 5299 @UnsupportedAppUsage 5300 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 5301 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; 5302 /** @hide 5303 * The audio output device code for S/PDIF (legacy) or HDMI 5304 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ 5305 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; 5306 /** @hide 5307 * The audio output device code for HDMI */ 5308 @UnsupportedAppUsage 5309 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; 5310 /** @hide 5311 * The audio output device code for an analog wired headset attached via a 5312 * docking station 5313 */ 5314 @UnsupportedAppUsage 5315 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 5316 /** @hide 5317 * The audio output device code for a digital wired headset attached via a 5318 * docking station 5319 */ 5320 @UnsupportedAppUsage 5321 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; 5322 /** @hide 5323 * The audio output device code for a USB audio accessory. The accessory is in USB host 5324 * mode and the Android device in USB device mode 5325 */ 5326 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; 5327 /** @hide 5328 * The audio output device code for a USB audio device. The device is in USB device 5329 * mode and the Android device in USB host mode 5330 */ 5331 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; 5332 /** @hide 5333 * The audio output device code for projection output. 5334 */ 5335 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 5336 /** @hide 5337 * The audio output device code the telephony voice TX path. 5338 */ 5339 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; 5340 /** @hide 5341 * The audio output device code for an analog jack with line impedance detected. 5342 */ 5343 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; 5344 /** @hide 5345 * The audio output device code for HDMI Audio Return Channel. 5346 */ 5347 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; 5348 /** @hide 5349 * The audio output device code for HDMI enhanced Audio Return Channel. 5350 */ 5351 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC; 5352 /** @hide 5353 * The audio output device code for S/PDIF digital connection. 5354 */ 5355 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; 5356 /** @hide 5357 * The audio output device code for built-in FM transmitter. 5358 */ 5359 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; 5360 /** @hide 5361 * The audio output device code for echo reference injection point. 5362 */ 5363 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; 5364 /** @hide 5365 * The audio output device code for a BLE audio headset. 5366 */ 5367 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; 5368 /** @hide 5369 * The audio output device code for a BLE audio speaker. 5370 */ 5371 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; 5372 /** @hide 5373 * This is not used as a returned value from {@link #getDevicesForStream}, but could be 5374 * used in the future in a set method to select whatever default device is chosen by the 5375 * platform-specific implementation. 5376 */ 5377 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; 5378 5379 /** @hide 5380 * The audio input device code for default built-in microphone 5381 */ 5382 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; 5383 /** @hide 5384 * The audio input device code for a Bluetooth SCO headset 5385 */ 5386 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 5387 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 5388 /** @hide 5389 * The audio input device code for wired headset microphone 5390 */ 5391 public static final int DEVICE_IN_WIRED_HEADSET = 5392 AudioSystem.DEVICE_IN_WIRED_HEADSET; 5393 /** @hide 5394 * The audio input device code for HDMI 5395 */ 5396 public static final int DEVICE_IN_HDMI = 5397 AudioSystem.DEVICE_IN_HDMI; 5398 /** @hide 5399 * The audio input device code for HDMI ARC 5400 */ 5401 public static final int DEVICE_IN_HDMI_ARC = 5402 AudioSystem.DEVICE_IN_HDMI_ARC; 5403 5404 /** @hide 5405 * The audio input device code for HDMI EARC 5406 */ 5407 public static final int DEVICE_IN_HDMI_EARC = 5408 AudioSystem.DEVICE_IN_HDMI_EARC; 5409 5410 /** @hide 5411 * The audio input device code for telephony voice RX path 5412 */ 5413 public static final int DEVICE_IN_TELEPHONY_RX = 5414 AudioSystem.DEVICE_IN_TELEPHONY_RX; 5415 /** @hide 5416 * The audio input device code for built-in microphone pointing to the back 5417 */ 5418 public static final int DEVICE_IN_BACK_MIC = 5419 AudioSystem.DEVICE_IN_BACK_MIC; 5420 /** @hide 5421 * The audio input device code for analog from a docking station 5422 */ 5423 public static final int DEVICE_IN_ANLG_DOCK_HEADSET = 5424 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; 5425 /** @hide 5426 * The audio input device code for digital from a docking station 5427 */ 5428 public static final int DEVICE_IN_DGTL_DOCK_HEADSET = 5429 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; 5430 /** @hide 5431 * The audio input device code for a USB audio accessory. The accessory is in USB host 5432 * mode and the Android device in USB device mode 5433 */ 5434 public static final int DEVICE_IN_USB_ACCESSORY = 5435 AudioSystem.DEVICE_IN_USB_ACCESSORY; 5436 /** @hide 5437 * The audio input device code for a USB audio device. The device is in USB device 5438 * mode and the Android device in USB host mode 5439 */ 5440 public static final int DEVICE_IN_USB_DEVICE = 5441 AudioSystem.DEVICE_IN_USB_DEVICE; 5442 /** @hide 5443 * The audio input device code for a FM radio tuner 5444 */ 5445 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; 5446 /** @hide 5447 * The audio input device code for a TV tuner 5448 */ 5449 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; 5450 /** @hide 5451 * The audio input device code for an analog jack with line impedance detected 5452 */ 5453 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; 5454 /** @hide 5455 * The audio input device code for a S/PDIF digital connection 5456 */ 5457 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; 5458 /** @hide 5459 * The audio input device code for audio loopback 5460 */ 5461 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; 5462 /** @hide 5463 * The audio input device code for an echo reference capture point. 5464 */ 5465 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; 5466 /** @hide 5467 * The audio input device code for a BLE audio headset. 5468 */ 5469 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; 5470 5471 /** 5472 * Return true if the device code corresponds to an output device. 5473 * @hide 5474 */ isOutputDevice(int device)5475 public static boolean isOutputDevice(int device) 5476 { 5477 return (device & AudioSystem.DEVICE_BIT_IN) == 0; 5478 } 5479 5480 /** 5481 * Return true if the device code corresponds to an input device. 5482 * @hide 5483 */ isInputDevice(int device)5484 public static boolean isInputDevice(int device) 5485 { 5486 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN; 5487 } 5488 5489 5490 /** 5491 * Return the enabled devices for the specified output stream type. 5492 * 5493 * @param streamType The stream type to query. One of 5494 * {@link #STREAM_VOICE_CALL}, 5495 * {@link #STREAM_SYSTEM}, 5496 * {@link #STREAM_RING}, 5497 * {@link #STREAM_MUSIC}, 5498 * {@link #STREAM_ALARM}, 5499 * {@link #STREAM_NOTIFICATION}, 5500 * {@link #STREAM_DTMF}, 5501 * {@link #STREAM_ACCESSIBILITY}. 5502 * 5503 * @return The bit-mask "or" of audio output device codes for all enabled devices on this 5504 * stream. Zero or more of 5505 * {@link #DEVICE_OUT_EARPIECE}, 5506 * {@link #DEVICE_OUT_SPEAKER}, 5507 * {@link #DEVICE_OUT_WIRED_HEADSET}, 5508 * {@link #DEVICE_OUT_WIRED_HEADPHONE}, 5509 * {@link #DEVICE_OUT_BLUETOOTH_SCO}, 5510 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET}, 5511 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT}, 5512 * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, 5513 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, 5514 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, 5515 * {@link #DEVICE_OUT_HDMI}, 5516 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, 5517 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. 5518 * {@link #DEVICE_OUT_USB_ACCESSORY}. 5519 * {@link #DEVICE_OUT_USB_DEVICE}. 5520 * {@link #DEVICE_OUT_REMOTE_SUBMIX}. 5521 * {@link #DEVICE_OUT_TELEPHONY_TX}. 5522 * {@link #DEVICE_OUT_LINE}. 5523 * {@link #DEVICE_OUT_HDMI_ARC}. 5524 * {@link #DEVICE_OUT_HDMI_EARC}. 5525 * {@link #DEVICE_OUT_SPDIF}. 5526 * {@link #DEVICE_OUT_FM}. 5527 * {@link #DEVICE_OUT_DEFAULT} is not used here. 5528 * 5529 * The implementation may support additional device codes beyond those listed, so 5530 * the application should ignore any bits which it does not recognize. 5531 * Note that the information may be imprecise when the implementation 5532 * cannot distinguish whether a particular device is enabled. 5533 * 5534 * {@hide} 5535 */ 5536 @UnsupportedAppUsage getDevicesForStream(int streamType)5537 public int getDevicesForStream(int streamType) { 5538 switch (streamType) { 5539 case STREAM_VOICE_CALL: 5540 case STREAM_SYSTEM: 5541 case STREAM_RING: 5542 case STREAM_MUSIC: 5543 case STREAM_ALARM: 5544 case STREAM_NOTIFICATION: 5545 case STREAM_DTMF: 5546 case STREAM_ACCESSIBILITY: 5547 final IAudioService service = getService(); 5548 try { 5549 return service.getDevicesForStream(streamType); 5550 } catch (RemoteException e) { 5551 throw e.rethrowFromSystemServer(); 5552 } 5553 default: 5554 return 0; 5555 } 5556 } 5557 5558 /** 5559 * @hide 5560 * Get the audio devices that would be used for the routing of the given audio attributes. 5561 * @param attributes the {@link AudioAttributes} for which the routing is being queried 5562 * @return an empty list if there was an issue with the request, a list of audio devices 5563 * otherwise (typically one device, except for duplicated paths). 5564 */ 5565 @SystemApi 5566 @RequiresPermission(anyOf = { 5567 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5568 android.Manifest.permission.QUERY_AUDIO_STATE 5569 }) getDevicesForAttributes( @onNull AudioAttributes attributes)5570 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes( 5571 @NonNull AudioAttributes attributes) { 5572 Objects.requireNonNull(attributes); 5573 final IAudioService service = getService(); 5574 try { 5575 return service.getDevicesForAttributes(attributes); 5576 } catch (RemoteException e) { 5577 throw e.rethrowFromSystemServer(); 5578 } 5579 } 5580 5581 /** 5582 * @hide 5583 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as 5584 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not 5585 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}. 5586 */ 5587 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; 5588 /** 5589 * @hide 5590 * Volume behavior for an audio device where a software attenuation is applied 5591 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5592 */ 5593 @SystemApi 5594 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; 5595 /** 5596 * @hide 5597 * Volume behavior for an audio device where the volume is always set to provide no attenuation 5598 * nor gain (e.g. unit gain). 5599 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5600 */ 5601 @SystemApi 5602 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; 5603 /** 5604 * @hide 5605 * Volume behavior for an audio device where the volume is either set to muted, or to provide 5606 * no attenuation nor gain (e.g. unit gain). 5607 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5608 */ 5609 @SystemApi 5610 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; 5611 /** 5612 * @hide 5613 * Volume behavior for an audio device where no software attenuation is applied, and 5614 * the volume is kept synchronized between the host and the device itself through a 5615 * device-specific protocol such as BT AVRCP. 5616 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5617 */ 5618 @SystemApi 5619 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; 5620 /** 5621 * @hide 5622 * Volume behavior for an audio device where no software attenuation is applied, and 5623 * the volume is kept synchronized between the host and the device itself through a 5624 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g. 5625 * normal vs in phone call). 5626 * @see #setMode(int) 5627 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 5628 */ 5629 @SystemApi 5630 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; 5631 5632 /** @hide */ 5633 @IntDef({ 5634 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 5635 DEVICE_VOLUME_BEHAVIOR_FULL, 5636 DEVICE_VOLUME_BEHAVIOR_FIXED, 5637 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 5638 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 5639 }) 5640 @Retention(RetentionPolicy.SOURCE) 5641 public @interface DeviceVolumeBehavior {} 5642 5643 /** @hide */ 5644 @IntDef({ 5645 DEVICE_VOLUME_BEHAVIOR_UNSET, 5646 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 5647 DEVICE_VOLUME_BEHAVIOR_FULL, 5648 DEVICE_VOLUME_BEHAVIOR_FIXED, 5649 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 5650 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 5651 }) 5652 @Retention(RetentionPolicy.SOURCE) 5653 public @interface DeviceVolumeBehaviorState {} 5654 5655 /** 5656 * @hide 5657 * Throws IAE on an invalid volume behavior value 5658 * @param volumeBehavior behavior value to check 5659 */ enforceValidVolumeBehavior(int volumeBehavior)5660 public static void enforceValidVolumeBehavior(int volumeBehavior) { 5661 switch (volumeBehavior) { 5662 case DEVICE_VOLUME_BEHAVIOR_VARIABLE: 5663 case DEVICE_VOLUME_BEHAVIOR_FULL: 5664 case DEVICE_VOLUME_BEHAVIOR_FIXED: 5665 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: 5666 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE: 5667 return; 5668 default: 5669 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior); 5670 } 5671 } 5672 5673 /** 5674 * @hide 5675 * Sets the volume behavior for an audio output device. 5676 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE 5677 * @see #DEVICE_VOLUME_BEHAVIOR_FULL 5678 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED 5679 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE 5680 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE 5681 * @param device the device to be affected 5682 * @param deviceVolumeBehavior one of the device behaviors 5683 */ 5684 @SystemApi 5685 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)5686 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, 5687 @DeviceVolumeBehavior int deviceVolumeBehavior) { 5688 // verify arguments (validity of device type is enforced in server) 5689 Objects.requireNonNull(device); 5690 enforceValidVolumeBehavior(deviceVolumeBehavior); 5691 // communicate with service 5692 final IAudioService service = getService(); 5693 try { 5694 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior, 5695 mApplicationContext.getOpPackageName()); 5696 } catch (RemoteException e) { 5697 throw e.rethrowFromSystemServer(); 5698 } 5699 } 5700 5701 /** 5702 * @hide 5703 * Returns the volume device behavior for the given audio device 5704 * @param device the audio device 5705 * @return the volume behavior for the device 5706 */ 5707 @SystemApi 5708 @RequiresPermission(anyOf = { 5709 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5710 android.Manifest.permission.QUERY_AUDIO_STATE 5711 }) 5712 public @DeviceVolumeBehavior getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)5713 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { 5714 // verify arguments (validity of device type is enforced in server) 5715 Objects.requireNonNull(device); 5716 // communicate with service 5717 final IAudioService service = getService(); 5718 try { 5719 return service.getDeviceVolumeBehavior(device); 5720 } catch (RemoteException e) { 5721 throw e.rethrowFromSystemServer(); 5722 } 5723 } 5724 5725 /** 5726 * @hide 5727 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}. 5728 */ 5729 @TestApi 5730 @RequiresPermission(anyOf = { 5731 android.Manifest.permission.MODIFY_AUDIO_ROUTING, 5732 android.Manifest.permission.QUERY_AUDIO_STATE 5733 }) isFullVolumeDevice()5734 public boolean isFullVolumeDevice() { 5735 final AudioAttributes attributes = new AudioAttributes.Builder() 5736 .setUsage(AudioAttributes.USAGE_MEDIA) 5737 .build(); 5738 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes); 5739 for (AudioDeviceAttributes device : devices) { 5740 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) { 5741 return true; 5742 } 5743 } 5744 return false; 5745 } 5746 5747 /** 5748 * Indicate wired accessory connection state change. 5749 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) 5750 * @param state new connection state: 1 connected, 0 disconnected 5751 * @param name device name 5752 * {@hide} 5753 */ 5754 @UnsupportedAppUsage 5755 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(int type, int state, String address, String name)5756 public void setWiredDeviceConnectionState(int type, int state, String address, String name) { 5757 final IAudioService service = getService(); 5758 try { 5759 service.setWiredDeviceConnectionState(type, state, address, name, 5760 mApplicationContext.getOpPackageName()); 5761 } catch (RemoteException e) { 5762 throw e.rethrowFromSystemServer(); 5763 } 5764 } 5765 5766 /** 5767 * Indicate Hearing Aid connection state change and eventually suppress 5768 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. 5769 * This operation is asynchronous but its execution will still be sequentially scheduled 5770 * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 5771 * * BluetoothDevice, int, int, boolean, int)} and 5772 * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. 5773 * @param device Bluetooth device connected/disconnected 5774 * @param state new connection state (BluetoothProfile.STATE_xxx) 5775 * @param musicDevice Default get system volume for the connecting device. 5776 * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or 5777 * {@link android.bluetooth.BluetoothProfile.HEARING_AID}) 5778 * @param suppressNoisyIntent if true the 5779 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. 5780 * {@hide} 5781 */ setBluetoothHearingAidDeviceConnectionState( BluetoothDevice device, int state, boolean suppressNoisyIntent, int musicDevice)5782 public void setBluetoothHearingAidDeviceConnectionState( 5783 BluetoothDevice device, int state, boolean suppressNoisyIntent, 5784 int musicDevice) { 5785 final IAudioService service = getService(); 5786 try { 5787 service.setBluetoothHearingAidDeviceConnectionState(device, 5788 state, suppressNoisyIntent, musicDevice); 5789 } catch (RemoteException e) { 5790 throw e.rethrowFromSystemServer(); 5791 } 5792 } 5793 5794 /** 5795 * Indicate A2DP source or sink connection state change and eventually suppress 5796 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent. 5797 * This operation is asynchronous but its execution will still be sequentially scheduled 5798 * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, 5799 * int, boolean, int)} and 5800 * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}. 5801 * @param device Bluetooth device connected/disconnected 5802 * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED} 5803 * or {@link BluetoothProfile#STATE_DISCONNECTED} 5804 * @param profile profile for the A2DP device 5805 * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting. 5806 * (either {@link android.bluetooth.BluetoothProfile.A2DP} or 5807 * {@link android.bluetooth.BluetoothProfile.A2DP_SINK}) 5808 * @param suppressNoisyIntent if true the 5809 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent. 5810 * {@hide} 5811 */ setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)5812 public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 5813 BluetoothDevice device, int state, 5814 int profile, boolean suppressNoisyIntent, int a2dpVolume) { 5815 final IAudioService service = getService(); 5816 try { 5817 service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device, 5818 state, profile, suppressNoisyIntent, a2dpVolume); 5819 } catch (RemoteException e) { 5820 throw e.rethrowFromSystemServer(); 5821 } 5822 } 5823 5824 /** 5825 * Indicate A2DP device configuration has changed. 5826 * This operation is asynchronous but its execution will still be sequentially scheduled 5827 * relative to calls to 5828 * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int, 5829 * boolean, int)} and 5830 * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)} 5831 * @param device Bluetooth device whose configuration has changed. 5832 * {@hide} 5833 */ handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)5834 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) { 5835 final IAudioService service = getService(); 5836 try { 5837 service.handleBluetoothA2dpDeviceConfigChange(device); 5838 } catch (RemoteException e) { 5839 throw e.rethrowFromSystemServer(); 5840 } 5841 } 5842 5843 /** {@hide} */ getRingtonePlayer()5844 public IRingtonePlayer getRingtonePlayer() { 5845 try { 5846 return getService().getRingtonePlayer(); 5847 } catch (RemoteException e) { 5848 throw e.rethrowFromSystemServer(); 5849 } 5850 } 5851 5852 /** 5853 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate 5854 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps 5855 * should use this value as a default, and offer the user the option to override it. 5856 * The low latency output stream is typically either the device's primary output stream, 5857 * or another output stream with smaller buffers. 5858 */ 5859 // FIXME Deprecate 5860 public static final String PROPERTY_OUTPUT_SAMPLE_RATE = 5861 "android.media.property.OUTPUT_SAMPLE_RATE"; 5862 5863 /** 5864 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size 5865 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps 5866 * should use this value as a minimum, and offer the user the option to override it. 5867 * The low latency output stream is typically either the device's primary output stream, 5868 * or another output stream with smaller buffers. 5869 */ 5870 // FIXME Deprecate 5871 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = 5872 "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; 5873 5874 /** 5875 * Used as a key for {@link #getProperty} to determine if the default microphone audio source 5876 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 5877 */ 5878 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = 5879 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; 5880 5881 /** 5882 * Used as a key for {@link #getProperty} to determine if the default speaker audio path 5883 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 5884 */ 5885 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = 5886 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; 5887 5888 /** 5889 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is 5890 * available and supported with the expected frequency range and level response. 5891 */ 5892 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = 5893 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED"; 5894 /** 5895 * Returns the value of the property with the specified key. 5896 * @param key One of the strings corresponding to a property key: either 5897 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE}, 5898 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER}, 5899 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, 5900 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or 5901 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}. 5902 * @return A string representing the associated value for that property key, 5903 * or null if there is no value for that key. 5904 */ getProperty(String key)5905 public String getProperty(String key) { 5906 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) { 5907 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate(); 5908 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null; 5909 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) { 5910 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount(); 5911 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null; 5912 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) { 5913 // Will throw a RuntimeException Resources.NotFoundException if this config value is 5914 // not found. 5915 return String.valueOf(getContext().getResources().getBoolean( 5916 com.android.internal.R.bool.config_supportMicNearUltrasound)); 5917 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) { 5918 return String.valueOf(getContext().getResources().getBoolean( 5919 com.android.internal.R.bool.config_supportSpeakerNearUltrasound)); 5920 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) { 5921 return String.valueOf(getContext().getResources().getBoolean( 5922 com.android.internal.R.bool.config_supportAudioSourceUnprocessed)); 5923 } else { 5924 // null or unknown key 5925 return null; 5926 } 5927 } 5928 5929 /** 5930 * @hide 5931 * Sets an additional audio output device delay in milliseconds. 5932 * 5933 * The additional output delay is a request to the output device to 5934 * delay audio presentation (generally with respect to video presentation for better 5935 * synchronization). 5936 * It may not be supported by all output devices, 5937 * and typically increases the audio latency by the amount of additional 5938 * audio delay requested. 5939 * 5940 * If additional audio delay is supported by an audio output device, 5941 * it is expected to be supported for all output streams (and configurations) 5942 * opened on that device. 5943 * 5944 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 5945 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0} 5946 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}. 5947 * @return true if successful, false if the device does not support output device delay 5948 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}. 5949 */ 5950 @SystemApi 5951 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)5952 public boolean setAdditionalOutputDeviceDelay( 5953 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) { 5954 Objects.requireNonNull(device); 5955 try { 5956 return getService().setAdditionalOutputDeviceDelay( 5957 new AudioDeviceAttributes(device), delayMillis); 5958 } catch (RemoteException e) { 5959 throw e.rethrowFromSystemServer(); 5960 } 5961 } 5962 5963 /** 5964 * @hide 5965 * Returns the current additional audio output device delay in milliseconds. 5966 * 5967 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 5968 * @return the additional output device delay. This is a non-negative number. 5969 * {@code 0} is returned if unsupported. 5970 */ 5971 @SystemApi 5972 @IntRange(from = 0) getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)5973 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 5974 Objects.requireNonNull(device); 5975 try { 5976 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device)); 5977 } catch (RemoteException e) { 5978 throw e.rethrowFromSystemServer(); 5979 } 5980 } 5981 5982 /** 5983 * @hide 5984 * Returns the maximum additional audio output device delay in milliseconds. 5985 * 5986 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 5987 * @return the maximum output device delay in milliseconds that can be set. 5988 * This is a non-negative number 5989 * representing the additional audio delay supported for the device. 5990 * {@code 0} is returned if unsupported. 5991 */ 5992 @SystemApi 5993 @IntRange(from = 0) getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)5994 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 5995 Objects.requireNonNull(device); 5996 try { 5997 return getService().getMaxAdditionalOutputDeviceDelay( 5998 new AudioDeviceAttributes(device)); 5999 } catch (RemoteException e) { 6000 throw e.rethrowFromSystemServer(); 6001 } 6002 } 6003 6004 /** 6005 * Returns the estimated latency for the given stream type in milliseconds. 6006 * 6007 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need 6008 * a better solution. 6009 * @hide 6010 */ 6011 @UnsupportedAppUsage getOutputLatency(int streamType)6012 public int getOutputLatency(int streamType) { 6013 return AudioSystem.getOutputLatency(streamType); 6014 } 6015 6016 /** 6017 * Registers a global volume controller interface. Currently limited to SystemUI. 6018 * 6019 * @hide 6020 */ setVolumeController(IVolumeController controller)6021 public void setVolumeController(IVolumeController controller) { 6022 try { 6023 getService().setVolumeController(controller); 6024 } catch (RemoteException e) { 6025 throw e.rethrowFromSystemServer(); 6026 } 6027 } 6028 6029 /** 6030 * Notify audio manager about volume controller visibility changes. 6031 * Currently limited to SystemUI. 6032 * 6033 * @hide 6034 */ notifyVolumeControllerVisible(IVolumeController controller, boolean visible)6035 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) { 6036 try { 6037 getService().notifyVolumeControllerVisible(controller, visible); 6038 } catch (RemoteException e) { 6039 throw e.rethrowFromSystemServer(); 6040 } 6041 } 6042 6043 /** 6044 * Only useful for volume controllers. 6045 * @hide 6046 */ isStreamAffectedByRingerMode(int streamType)6047 public boolean isStreamAffectedByRingerMode(int streamType) { 6048 try { 6049 return getService().isStreamAffectedByRingerMode(streamType); 6050 } catch (RemoteException e) { 6051 throw e.rethrowFromSystemServer(); 6052 } 6053 } 6054 6055 /** 6056 * Only useful for volume controllers. 6057 * @hide 6058 */ isStreamAffectedByMute(int streamType)6059 public boolean isStreamAffectedByMute(int streamType) { 6060 try { 6061 return getService().isStreamAffectedByMute(streamType); 6062 } catch (RemoteException e) { 6063 throw e.rethrowFromSystemServer(); 6064 } 6065 } 6066 6067 /** 6068 * Only useful for volume controllers. 6069 * @hide 6070 */ disableSafeMediaVolume()6071 public void disableSafeMediaVolume() { 6072 try { 6073 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName()); 6074 } catch (RemoteException e) { 6075 throw e.rethrowFromSystemServer(); 6076 } 6077 } 6078 6079 /** 6080 * Only useful for volume controllers. 6081 * @hide 6082 */ 6083 @UnsupportedAppUsage setRingerModeInternal(int ringerMode)6084 public void setRingerModeInternal(int ringerMode) { 6085 try { 6086 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName()); 6087 } catch (RemoteException e) { 6088 throw e.rethrowFromSystemServer(); 6089 } 6090 } 6091 6092 /** 6093 * Only useful for volume controllers. 6094 * @hide 6095 */ 6096 @UnsupportedAppUsage getRingerModeInternal()6097 public int getRingerModeInternal() { 6098 try { 6099 return getService().getRingerModeInternal(); 6100 } catch (RemoteException e) { 6101 throw e.rethrowFromSystemServer(); 6102 } 6103 } 6104 6105 /** 6106 * Only useful for volume controllers. 6107 * @hide 6108 */ setVolumePolicy(VolumePolicy policy)6109 public void setVolumePolicy(VolumePolicy policy) { 6110 try { 6111 getService().setVolumePolicy(policy); 6112 } catch (RemoteException e) { 6113 throw e.rethrowFromSystemServer(); 6114 } 6115 } 6116 6117 /** 6118 * Set Hdmi Cec system audio mode. 6119 * 6120 * @param on whether to be on system audio mode 6121 * @return output device type. 0 (DEVICE_NONE) if failed to set device. 6122 * @hide 6123 */ setHdmiSystemAudioSupported(boolean on)6124 public int setHdmiSystemAudioSupported(boolean on) { 6125 try { 6126 return getService().setHdmiSystemAudioSupported(on); 6127 } catch (RemoteException e) { 6128 throw e.rethrowFromSystemServer(); 6129 } 6130 } 6131 6132 /** 6133 * Returns true if Hdmi Cec system audio mode is supported. 6134 * 6135 * @hide 6136 */ 6137 @SystemApi 6138 @SuppressLint("RequiresPermission") // FIXME is this still used? isHdmiSystemAudioSupported()6139 public boolean isHdmiSystemAudioSupported() { 6140 try { 6141 return getService().isHdmiSystemAudioSupported(); 6142 } catch (RemoteException e) { 6143 throw e.rethrowFromSystemServer(); 6144 } 6145 } 6146 6147 /** 6148 * Return codes for listAudioPorts(), createAudioPatch() ... 6149 */ 6150 6151 /** @hide */ 6152 @SystemApi 6153 public static final int SUCCESS = AudioSystem.SUCCESS; 6154 /** 6155 * A default error code. 6156 */ 6157 public static final int ERROR = AudioSystem.ERROR; 6158 /** @hide 6159 * CANDIDATE FOR PUBLIC API 6160 */ 6161 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 6162 /** @hide 6163 */ 6164 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 6165 /** @hide 6166 */ 6167 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED; 6168 /** @hide 6169 */ 6170 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT; 6171 /** 6172 * An error code indicating that the object reporting it is no longer valid and needs to 6173 * be recreated. 6174 */ 6175 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 6176 6177 /** 6178 * Returns a list of descriptors for all audio ports managed by the audio framework. 6179 * Audio ports are nodes in the audio framework or audio hardware that can be configured 6180 * or connected and disconnected with createAudioPatch() or releaseAudioPatch(). 6181 * See AudioPort for a list of attributes of each audio port. 6182 * @param ports An AudioPort ArrayList where the list will be returned. 6183 * @hide 6184 */ 6185 @UnsupportedAppUsage listAudioPorts(ArrayList<AudioPort> ports)6186 public static int listAudioPorts(ArrayList<AudioPort> ports) { 6187 return updateAudioPortCache(ports, null, null); 6188 } 6189 6190 /** 6191 * Returns a list of descriptors for all audio ports managed by the audio framework as 6192 * it was before the last update calback. 6193 * @param ports An AudioPort ArrayList where the list will be returned. 6194 * @hide 6195 */ listPreviousAudioPorts(ArrayList<AudioPort> ports)6196 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) { 6197 return updateAudioPortCache(null, null, ports); 6198 } 6199 6200 /** 6201 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort) 6202 * @see listAudioPorts(ArrayList<AudioPort>) 6203 * @hide 6204 */ listAudioDevicePorts(ArrayList<AudioDevicePort> devices)6205 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 6206 if (devices == null) { 6207 return ERROR_BAD_VALUE; 6208 } 6209 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 6210 int status = updateAudioPortCache(ports, null, null); 6211 if (status == SUCCESS) { 6212 filterDevicePorts(ports, devices); 6213 } 6214 return status; 6215 } 6216 6217 /** 6218 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort) 6219 * @see listPreviousAudioPorts(ArrayList<AudioPort>) 6220 * @hide 6221 */ listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)6222 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 6223 if (devices == null) { 6224 return ERROR_BAD_VALUE; 6225 } 6226 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 6227 int status = updateAudioPortCache(null, null, ports); 6228 if (status == SUCCESS) { 6229 filterDevicePorts(ports, devices); 6230 } 6231 return status; 6232 } 6233 filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)6234 private static void filterDevicePorts(ArrayList<AudioPort> ports, 6235 ArrayList<AudioDevicePort> devices) { 6236 devices.clear(); 6237 for (int i = 0; i < ports.size(); i++) { 6238 if (ports.get(i) instanceof AudioDevicePort) { 6239 devices.add((AudioDevicePort)ports.get(i)); 6240 } 6241 } 6242 } 6243 6244 /** 6245 * Create a connection between two or more devices. The framework will reject the request if 6246 * device types are not compatible or the implementation does not support the requested 6247 * configuration. 6248 * NOTE: current implementation is limited to one source and one sink per patch. 6249 * @param patch AudioPatch array where the newly created patch will be returned. 6250 * As input, if patch[0] is not null, the specified patch will be replaced by the 6251 * new patch created. This avoids calling releaseAudioPatch() when modifying a 6252 * patch and allows the implementation to optimize transitions. 6253 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE. 6254 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK. 6255 * 6256 * @return - {@link #SUCCESS} if connection is successful. 6257 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed. 6258 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported. 6259 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create 6260 * a patch. 6261 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 6262 * - {@link #ERROR} if patch cannot be connected for any other reason. 6263 * 6264 * patch[0] contains the newly created patch 6265 * @hide 6266 */ 6267 @UnsupportedAppUsage createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)6268 public static int createAudioPatch(AudioPatch[] patch, 6269 AudioPortConfig[] sources, 6270 AudioPortConfig[] sinks) { 6271 return AudioSystem.createAudioPatch(patch, sources, sinks); 6272 } 6273 6274 /** 6275 * Releases an existing audio patch connection. 6276 * @param patch The audio patch to disconnect. 6277 * @return - {@link #SUCCESS} if disconnection is successful. 6278 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist. 6279 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release 6280 * a patch. 6281 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 6282 * - {@link #ERROR} if patch cannot be released for any other reason. 6283 * @hide 6284 */ 6285 @UnsupportedAppUsage releaseAudioPatch(AudioPatch patch)6286 public static int releaseAudioPatch(AudioPatch patch) { 6287 return AudioSystem.releaseAudioPatch(patch); 6288 } 6289 6290 /** 6291 * List all existing connections between audio ports. 6292 * @param patches An AudioPatch array where the list will be returned. 6293 * @hide 6294 */ 6295 @UnsupportedAppUsage listAudioPatches(ArrayList<AudioPatch> patches)6296 public static int listAudioPatches(ArrayList<AudioPatch> patches) { 6297 return updateAudioPortCache(null, patches, null); 6298 } 6299 6300 /** 6301 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by 6302 * AudioGain.buildConfig() 6303 * @hide 6304 */ setAudioPortGain(AudioPort port, AudioGainConfig gain)6305 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) { 6306 if (port == null || gain == null) { 6307 return ERROR_BAD_VALUE; 6308 } 6309 AudioPortConfig activeConfig = port.activeConfig(); 6310 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(), 6311 activeConfig.channelMask(), activeConfig.format(), gain); 6312 config.mConfigMask = AudioPortConfig.GAIN; 6313 return AudioSystem.setAudioPortConfig(config); 6314 } 6315 6316 /** 6317 * Listener registered by client to be notified upon new audio port connections, 6318 * disconnections or attributes update. 6319 * @hide 6320 */ 6321 public interface OnAudioPortUpdateListener { 6322 /** 6323 * Callback method called upon audio port list update. 6324 * @param portList the updated list of audio ports 6325 */ onAudioPortListUpdate(AudioPort[] portList)6326 public void onAudioPortListUpdate(AudioPort[] portList); 6327 6328 /** 6329 * Callback method called upon audio patch list update. 6330 * @param patchList the updated list of audio patches 6331 */ onAudioPatchListUpdate(AudioPatch[] patchList)6332 public void onAudioPatchListUpdate(AudioPatch[] patchList); 6333 6334 /** 6335 * Callback method called when the mediaserver dies 6336 */ onServiceDied()6337 public void onServiceDied(); 6338 } 6339 6340 /** 6341 * Register an audio port list update listener. 6342 * @hide 6343 */ 6344 @UnsupportedAppUsage registerAudioPortUpdateListener(OnAudioPortUpdateListener l)6345 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { 6346 sAudioPortEventHandler.init(); 6347 sAudioPortEventHandler.registerListener(l); 6348 } 6349 6350 /** 6351 * Unregister an audio port list update listener. 6352 * @hide 6353 */ 6354 @UnsupportedAppUsage unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)6355 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) { 6356 sAudioPortEventHandler.unregisterListener(l); 6357 } 6358 6359 // 6360 // AudioPort implementation 6361 // 6362 6363 static final int AUDIOPORT_GENERATION_INIT = 0; 6364 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT); 6365 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); 6366 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); 6367 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); 6368 resetAudioPortGeneration()6369 static int resetAudioPortGeneration() { 6370 int generation; 6371 synchronized (sAudioPortGeneration) { 6372 generation = sAudioPortGeneration; 6373 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 6374 } 6375 return generation; 6376 } 6377 updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)6378 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, 6379 ArrayList<AudioPort> previousPorts) { 6380 sAudioPortEventHandler.init(); 6381 synchronized (sAudioPortGeneration) { 6382 6383 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { 6384 int[] patchGeneration = new int[1]; 6385 int[] portGeneration = new int[1]; 6386 int status; 6387 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>(); 6388 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>(); 6389 6390 do { 6391 newPorts.clear(); 6392 status = AudioSystem.listAudioPorts(newPorts, portGeneration); 6393 if (status != SUCCESS) { 6394 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed"); 6395 return status; 6396 } 6397 newPatches.clear(); 6398 status = AudioSystem.listAudioPatches(newPatches, patchGeneration); 6399 if (status != SUCCESS) { 6400 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed"); 6401 return status; 6402 } 6403 // Loop until patch generation is the same as port generation unless audio ports 6404 // and audio patches are not null. 6405 } while (patchGeneration[0] != portGeneration[0] 6406 && (ports == null || patches == null)); 6407 // If the patch generation doesn't equal port generation, return ERROR here in case 6408 // of mismatch between audio ports and audio patches. 6409 if (patchGeneration[0] != portGeneration[0]) { 6410 return ERROR; 6411 } 6412 6413 for (int i = 0; i < newPatches.size(); i++) { 6414 for (int j = 0; j < newPatches.get(i).sources().length; j++) { 6415 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j], 6416 newPorts); 6417 newPatches.get(i).sources()[j] = portCfg; 6418 } 6419 for (int j = 0; j < newPatches.get(i).sinks().length; j++) { 6420 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j], 6421 newPorts); 6422 newPatches.get(i).sinks()[j] = portCfg; 6423 } 6424 } 6425 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) { 6426 AudioPatch newPatch = i.next(); 6427 boolean hasInvalidPort = false; 6428 for (AudioPortConfig portCfg : newPatch.sources()) { 6429 if (portCfg == null) { 6430 hasInvalidPort = true; 6431 break; 6432 } 6433 } 6434 for (AudioPortConfig portCfg : newPatch.sinks()) { 6435 if (portCfg == null) { 6436 hasInvalidPort = true; 6437 break; 6438 } 6439 } 6440 if (hasInvalidPort) { 6441 // Temporarily remove patches with invalid ports. One who created the patch 6442 // is responsible for dealing with the port change. 6443 i.remove(); 6444 } 6445 } 6446 6447 sPreviousAudioPortsCached = sAudioPortsCached; 6448 sAudioPortsCached = newPorts; 6449 sAudioPatchesCached = newPatches; 6450 sAudioPortGeneration = portGeneration[0]; 6451 } 6452 if (ports != null) { 6453 ports.clear(); 6454 ports.addAll(sAudioPortsCached); 6455 } 6456 if (patches != null) { 6457 patches.clear(); 6458 patches.addAll(sAudioPatchesCached); 6459 } 6460 if (previousPorts != null) { 6461 previousPorts.clear(); 6462 previousPorts.addAll(sPreviousAudioPortsCached); 6463 } 6464 } 6465 return SUCCESS; 6466 } 6467 updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)6468 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) { 6469 AudioPort port = portCfg.port(); 6470 int k; 6471 for (k = 0; k < ports.size(); k++) { 6472 // compare handles because the port returned by JNI is not of the correct 6473 // subclass 6474 if (ports.get(k).handle().equals(port.handle())) { 6475 port = ports.get(k); 6476 break; 6477 } 6478 } 6479 if (k == ports.size()) { 6480 // this hould never happen 6481 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id()); 6482 return null; 6483 } 6484 AudioGainConfig gainCfg = portCfg.gain(); 6485 if (gainCfg != null) { 6486 AudioGain gain = port.gain(gainCfg.index()); 6487 gainCfg = gain.buildConfig(gainCfg.mode(), 6488 gainCfg.channelMask(), 6489 gainCfg.values(), 6490 gainCfg.rampDurationMs()); 6491 } 6492 return port.buildConfig(portCfg.samplingRate(), 6493 portCfg.channelMask(), 6494 portCfg.format(), 6495 gainCfg); 6496 } 6497 6498 private OnAmPortUpdateListener mPortListener = null; 6499 6500 /** 6501 * The message sent to apps when the contents of the device list changes if they provide 6502 * a {@link Handler} object to addOnAudioDeviceConnectionListener(). 6503 */ 6504 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0; 6505 private final static int MSG_DEVICES_DEVICES_ADDED = 1; 6506 private final static int MSG_DEVICES_DEVICES_REMOVED = 2; 6507 6508 /** 6509 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. 6510 */ 6511 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = 6512 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); 6513 6514 /** 6515 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter 6516 * the results list to only those device types they are interested in. 6517 */ 6518 /** 6519 * Specifies to the {@link AudioManager#getDevices(int)} method to include 6520 * source (i.e. input) audio devices. 6521 */ 6522 public static final int GET_DEVICES_INPUTS = 0x0001; 6523 6524 /** 6525 * Specifies to the {@link AudioManager#getDevices(int)} method to include 6526 * sink (i.e. output) audio devices. 6527 */ 6528 public static final int GET_DEVICES_OUTPUTS = 0x0002; 6529 6530 /** @hide */ 6531 @IntDef(flag = true, prefix = "GET_DEVICES", value = { 6532 GET_DEVICES_INPUTS, 6533 GET_DEVICES_OUTPUTS } 6534 ) 6535 @Retention(RetentionPolicy.SOURCE) 6536 public @interface AudioDeviceRole {} 6537 6538 /** 6539 * Specifies to the {@link AudioManager#getDevices(int)} method to include both 6540 * source and sink devices. 6541 */ 6542 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS; 6543 6544 /** 6545 * Determines if a given AudioDevicePort meets the specified filter criteria. 6546 * @param port The port to test. 6547 * @param flags A set of bitflags specifying the criteria to test. 6548 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS} 6549 **/ checkFlags(AudioDevicePort port, int flags)6550 private static boolean checkFlags(AudioDevicePort port, int flags) { 6551 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 || 6552 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; 6553 } 6554 checkTypes(AudioDevicePort port)6555 private static boolean checkTypes(AudioDevicePort port) { 6556 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != 6557 AudioDeviceInfo.TYPE_UNKNOWN; 6558 } 6559 6560 /** 6561 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices 6562 * currently connected to the system and meeting the criteria specified in the 6563 * <code>flags</code> parameter. 6564 * @param flags A set of bitflags specifying the criteria to test. 6565 * @see #GET_DEVICES_OUTPUTS 6566 * @see #GET_DEVICES_INPUTS 6567 * @see #GET_DEVICES_ALL 6568 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 6569 */ getDevices(@udioDeviceRole int flags)6570 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) { 6571 return getDevicesStatic(flags); 6572 } 6573 6574 /** 6575 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo 6576 * objects from the current (internal) AudioDevicePort list. 6577 */ 6578 private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)6579 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { 6580 6581 // figure out how many AudioDeviceInfo we need space for... 6582 int numRecs = 0; 6583 for (AudioDevicePort port : ports) { 6584 if (checkTypes(port) && checkFlags(port, flags)) { 6585 numRecs++; 6586 } 6587 } 6588 6589 // Now load them up... 6590 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; 6591 int slot = 0; 6592 for (AudioDevicePort port : ports) { 6593 if (checkTypes(port) && checkFlags(port, flags)) { 6594 deviceList[slot++] = new AudioDeviceInfo(port); 6595 } 6596 } 6597 6598 return deviceList; 6599 } 6600 6601 /* 6602 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by 6603 * the add/remove callback mechanism to provide a list of the newly added or removed devices 6604 * rather than the whole list and make the app figure it out. 6605 * Note that calling this method with: 6606 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. 6607 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. 6608 */ calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)6609 private static AudioDeviceInfo[] calcListDeltas( 6610 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { 6611 6612 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>(); 6613 6614 AudioDevicePort cur_port = null; 6615 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) { 6616 boolean cur_port_found = false; 6617 cur_port = ports_B.get(cur_index); 6618 for (int prev_index = 0; 6619 prev_index < ports_A.size() && !cur_port_found; 6620 prev_index++) { 6621 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id()); 6622 } 6623 6624 if (!cur_port_found) { 6625 delta_ports.add(cur_port); 6626 } 6627 } 6628 6629 return infoListFromPortList(delta_ports, flags); 6630 } 6631 6632 /** 6633 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently 6634 * connected to the system and meeting the criteria specified in the <code>flags</code> 6635 * parameter. 6636 * This is an internal function. The public API front is getDevices(int). 6637 * @param flags A set of bitflags specifying the criteria to test. 6638 * @see #GET_DEVICES_OUTPUTS 6639 * @see #GET_DEVICES_INPUTS 6640 * @see #GET_DEVICES_ALL 6641 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 6642 * @hide 6643 */ getDevicesStatic(int flags)6644 public static AudioDeviceInfo[] getDevicesStatic(int flags) { 6645 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>(); 6646 int status = AudioManager.listAudioDevicePorts(ports); 6647 if (status != AudioManager.SUCCESS) { 6648 // fail and bail! 6649 return new AudioDeviceInfo[0]; // Always return an array. 6650 } 6651 6652 return infoListFromPortList(ports, flags); 6653 } 6654 6655 /** 6656 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID. 6657 * @param portId The audio port ID to look up for. 6658 * @param flags A set of bitflags specifying the criteria to test. 6659 * @see #GET_DEVICES_OUTPUTS 6660 * @see #GET_DEVICES_INPUTS 6661 * @see #GET_DEVICES_ALL 6662 * @return An AudioDeviceInfo or null if no device with matching port ID is found. 6663 * @hide 6664 */ getDeviceForPortId(int portId, int flags)6665 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) { 6666 if (portId == 0) { 6667 return null; 6668 } 6669 AudioDeviceInfo[] devices = getDevicesStatic(flags); 6670 for (AudioDeviceInfo device : devices) { 6671 if (device.getId() == portId) { 6672 return device; 6673 } 6674 } 6675 return null; 6676 } 6677 6678 /** 6679 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes 6680 * to the set of connected audio devices. 6681 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect 6682 * notifications. 6683 * @param handler Specifies the {@link Handler} object for the thread on which to execute 6684 * the callback. If <code>null</code>, the {@link Handler} associated with the main 6685 * {@link Looper} will be used. 6686 */ registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)6687 public void registerAudioDeviceCallback(AudioDeviceCallback callback, 6688 @Nullable Handler handler) { 6689 synchronized (mDeviceCallbacks) { 6690 if (callback != null && !mDeviceCallbacks.containsKey(callback)) { 6691 if (mDeviceCallbacks.size() == 0) { 6692 if (mPortListener == null) { 6693 mPortListener = new OnAmPortUpdateListener(); 6694 } 6695 registerAudioPortUpdateListener(mPortListener); 6696 } 6697 NativeEventHandlerDelegate delegate = 6698 new NativeEventHandlerDelegate(callback, handler); 6699 mDeviceCallbacks.put(callback, delegate); 6700 broadcastDeviceListChange_sync(delegate.getHandler()); 6701 } 6702 } 6703 } 6704 6705 /** 6706 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered 6707 * to receive notifications of changes to the set of connected audio devices. 6708 * @param callback The {@link AudioDeviceCallback} object that was previously registered 6709 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered. 6710 */ unregisterAudioDeviceCallback(AudioDeviceCallback callback)6711 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { 6712 synchronized (mDeviceCallbacks) { 6713 if (mDeviceCallbacks.containsKey(callback)) { 6714 mDeviceCallbacks.remove(callback); 6715 if (mDeviceCallbacks.size() == 0) { 6716 unregisterAudioPortUpdateListener(mPortListener); 6717 } 6718 } 6719 } 6720 } 6721 6722 /** 6723 * Set port id for microphones by matching device type and address. 6724 * @hide 6725 */ setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)6726 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) { 6727 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 6728 for (int i = microphones.size() - 1; i >= 0; i--) { 6729 boolean foundPortId = false; 6730 for (AudioDeviceInfo device : devices) { 6731 if (device.getPort().type() == microphones.get(i).getInternalDeviceType() 6732 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) { 6733 microphones.get(i).setId(device.getId()); 6734 foundPortId = true; 6735 break; 6736 } 6737 } 6738 if (!foundPortId) { 6739 Log.i(TAG, "Failed to find port id for device with type:" 6740 + microphones.get(i).getType() + " address:" 6741 + microphones.get(i).getAddress()); 6742 microphones.remove(i); 6743 } 6744 } 6745 } 6746 6747 /** 6748 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}. 6749 * @hide 6750 */ microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)6751 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) { 6752 int deviceType = deviceInfo.getType(); 6753 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC 6754 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY 6755 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN 6756 : MicrophoneInfo.LOCATION_PERIPHERAL; 6757 MicrophoneInfo microphone = new MicrophoneInfo( 6758 deviceInfo.getPort().name() + deviceInfo.getId(), 6759 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation, 6760 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN, 6761 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN, 6762 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(), 6763 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN, 6764 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN); 6765 microphone.setId(deviceInfo.getId()); 6766 return microphone; 6767 } 6768 6769 /** 6770 * Add {@link MicrophoneInfo} by device information while filtering certain types. 6771 */ addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)6772 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, 6773 HashSet<Integer> filterTypes) { 6774 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS); 6775 for (AudioDeviceInfo device : devices) { 6776 if (filterTypes.contains(device.getType())) { 6777 continue; 6778 } 6779 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device); 6780 microphones.add(microphone); 6781 } 6782 } 6783 6784 /** 6785 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics 6786 * of all available microphones. The list is empty when no microphones are available 6787 * on the device. An error during the query will result in an IOException being thrown. 6788 * 6789 * @return a list that contains all microphones' characteristics 6790 * @throws IOException if an error occurs. 6791 */ getMicrophones()6792 public List<MicrophoneInfo> getMicrophones() throws IOException { 6793 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>(); 6794 int status = AudioSystem.getMicrophones(microphones); 6795 HashSet<Integer> filterTypes = new HashSet<>(); 6796 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY); 6797 if (status != AudioManager.SUCCESS) { 6798 // fail and populate microphones with unknown characteristics by device information. 6799 if (status != AudioManager.ERROR_INVALID_OPERATION) { 6800 Log.e(TAG, "getMicrophones failed:" + status); 6801 } 6802 Log.i(TAG, "fallback on device info"); 6803 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 6804 return microphones; 6805 } 6806 setPortIdForMicrophones(microphones); 6807 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); 6808 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 6809 return microphones; 6810 } 6811 6812 /** 6813 * Returns a list of audio formats that corresponds to encoding formats 6814 * supported on offload path for A2DP playback. 6815 * 6816 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats 6817 * supported for offload A2DP playback 6818 * @hide 6819 */ getHwOffloadEncodingFormatsSupportedForA2DP()6820 public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() { 6821 ArrayList<Integer> formatsList = new ArrayList<Integer>(); 6822 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>(); 6823 6824 int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList); 6825 if (status != AudioManager.SUCCESS) { 6826 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status); 6827 return codecConfigList; 6828 } 6829 6830 for (Integer format : formatsList) { 6831 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); 6832 if (btSourceCodec 6833 != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 6834 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec)); 6835 } 6836 } 6837 return codecConfigList; 6838 } 6839 6840 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the 6841 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list 6842 // of the ports that exist at the time of the last notification. 6843 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>(); 6844 6845 /** 6846 * Internal method to compute and generate add/remove messages and then send to any 6847 * registered callbacks. Must be called synchronized on mDeviceCallbacks. 6848 */ broadcastDeviceListChange_sync(Handler handler)6849 private void broadcastDeviceListChange_sync(Handler handler) { 6850 int status; 6851 6852 // Get the new current set of ports 6853 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>(); 6854 status = AudioManager.listAudioDevicePorts(current_ports); 6855 if (status != AudioManager.SUCCESS) { 6856 return; 6857 } 6858 6859 if (handler != null) { 6860 // This is the callback for the registration, so send the current list 6861 AudioDeviceInfo[] deviceList = 6862 infoListFromPortList(current_ports, GET_DEVICES_ALL); 6863 handler.sendMessage( 6864 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList)); 6865 } else { 6866 AudioDeviceInfo[] added_devices = 6867 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL); 6868 AudioDeviceInfo[] removed_devices = 6869 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL); 6870 if (added_devices.length != 0 || removed_devices.length != 0) { 6871 for (int i = 0; i < mDeviceCallbacks.size(); i++) { 6872 handler = mDeviceCallbacks.valueAt(i).getHandler(); 6873 if (handler != null) { 6874 if (removed_devices.length != 0) { 6875 handler.sendMessage(Message.obtain(handler, 6876 MSG_DEVICES_DEVICES_REMOVED, 6877 removed_devices)); 6878 } 6879 if (added_devices.length != 0) { 6880 handler.sendMessage(Message.obtain(handler, 6881 MSG_DEVICES_DEVICES_ADDED, 6882 added_devices)); 6883 } 6884 } 6885 } 6886 } 6887 } 6888 6889 mPreviousPorts = current_ports; 6890 } 6891 6892 /** 6893 * Handles Port list update notifications from the AudioManager 6894 */ 6895 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener { 6896 static final String TAG = "OnAmPortUpdateListener"; onAudioPortListUpdate(AudioPort[] portList)6897 public void onAudioPortListUpdate(AudioPort[] portList) { 6898 synchronized (mDeviceCallbacks) { 6899 broadcastDeviceListChange_sync(null); 6900 } 6901 } 6902 6903 /** 6904 * Callback method called upon audio patch list update. 6905 * Note: We don't do anything with Patches at this time, so ignore this notification. 6906 * @param patchList the updated list of audio patches. 6907 */ onAudioPatchListUpdate(AudioPatch[] patchList)6908 public void onAudioPatchListUpdate(AudioPatch[] patchList) {} 6909 6910 /** 6911 * Callback method called when the mediaserver dies 6912 */ onServiceDied()6913 public void onServiceDied() { 6914 synchronized (mDeviceCallbacks) { 6915 broadcastDeviceListChange_sync(null); 6916 } 6917 } 6918 } 6919 6920 6921 /** 6922 * @hide 6923 * Abstract class to receive event notification about audioserver process state. 6924 */ 6925 @SystemApi 6926 public abstract static class AudioServerStateCallback { onAudioServerDown()6927 public void onAudioServerDown() { } onAudioServerUp()6928 public void onAudioServerUp() { } 6929 } 6930 6931 private Executor mAudioServerStateExec; 6932 private AudioServerStateCallback mAudioServerStateCb; 6933 private final Object mAudioServerStateCbLock = new Object(); 6934 6935 private final IAudioServerStateDispatcher mAudioServerStateDispatcher = 6936 new IAudioServerStateDispatcher.Stub() { 6937 @Override 6938 public void dispatchAudioServerStateChange(boolean state) { 6939 Executor exec; 6940 AudioServerStateCallback cb; 6941 6942 synchronized (mAudioServerStateCbLock) { 6943 exec = mAudioServerStateExec; 6944 cb = mAudioServerStateCb; 6945 } 6946 6947 if ((exec == null) || (cb == null)) { 6948 return; 6949 } 6950 if (state) { 6951 exec.execute(() -> cb.onAudioServerUp()); 6952 } else { 6953 exec.execute(() -> cb.onAudioServerDown()); 6954 } 6955 } 6956 }; 6957 6958 /** 6959 * @hide 6960 * Registers a callback for notification of audio server state changes. 6961 * @param executor {@link Executor} to handle the callbacks 6962 * @param stateCallback the callback to receive the audio server state changes 6963 * To remove the callabck, pass a null reference for both executor and stateCallback. 6964 */ 6965 @SystemApi setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)6966 public void setAudioServerStateCallback(@NonNull Executor executor, 6967 @NonNull AudioServerStateCallback stateCallback) { 6968 if (stateCallback == null) { 6969 throw new IllegalArgumentException("Illegal null AudioServerStateCallback"); 6970 } 6971 if (executor == null) { 6972 throw new IllegalArgumentException( 6973 "Illegal null Executor for the AudioServerStateCallback"); 6974 } 6975 6976 synchronized (mAudioServerStateCbLock) { 6977 if (mAudioServerStateCb != null) { 6978 throw new IllegalStateException( 6979 "setAudioServerStateCallback called with already registered callabck"); 6980 } 6981 final IAudioService service = getService(); 6982 try { 6983 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher); 6984 } catch (RemoteException e) { 6985 throw e.rethrowFromSystemServer(); 6986 } 6987 mAudioServerStateExec = executor; 6988 mAudioServerStateCb = stateCallback; 6989 } 6990 } 6991 6992 /** 6993 * @hide 6994 * Unregisters the callback for notification of audio server state changes. 6995 */ 6996 @SystemApi clearAudioServerStateCallback()6997 public void clearAudioServerStateCallback() { 6998 synchronized (mAudioServerStateCbLock) { 6999 if (mAudioServerStateCb != null) { 7000 final IAudioService service = getService(); 7001 try { 7002 service.unregisterAudioServerStateDispatcher( 7003 mAudioServerStateDispatcher); 7004 } catch (RemoteException e) { 7005 throw e.rethrowFromSystemServer(); 7006 } 7007 } 7008 mAudioServerStateExec = null; 7009 mAudioServerStateCb = null; 7010 } 7011 } 7012 7013 /** 7014 * @hide 7015 * Checks if native audioservice is running or not. 7016 * @return true if native audioservice runs, false otherwise. 7017 */ 7018 @SystemApi isAudioServerRunning()7019 public boolean isAudioServerRunning() { 7020 final IAudioService service = getService(); 7021 try { 7022 return service.isAudioServerRunning(); 7023 } catch (RemoteException e) { 7024 throw e.rethrowFromSystemServer(); 7025 } 7026 } 7027 7028 /** 7029 * Sets the surround sound mode. 7030 * 7031 * @return true if successful, otherwise false 7032 */ 7033 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)7034 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) { 7035 try { 7036 return getService().setEncodedSurroundMode(mode); 7037 } catch (RemoteException e) { 7038 throw e.rethrowFromSystemServer(); 7039 } 7040 } 7041 7042 /** 7043 * Gets the surround sound mode. 7044 * 7045 * @return true if successful, otherwise false 7046 */ getEncodedSurroundMode()7047 public @EncodedSurroundOutputMode int getEncodedSurroundMode() { 7048 try { 7049 return getService().getEncodedSurroundMode( 7050 getContext().getApplicationInfo().targetSdkVersion); 7051 } catch (RemoteException e) { 7052 throw e.rethrowFromSystemServer(); 7053 } 7054 } 7055 7056 /** 7057 * @hide 7058 * Returns all surround formats. 7059 * @return a map where the key is a surround format and 7060 * the value indicates the surround format is enabled or not 7061 */ 7062 @TestApi 7063 @NonNull getSurroundFormats()7064 public Map<Integer, Boolean> getSurroundFormats() { 7065 try { 7066 return getService().getSurroundFormats(); 7067 } catch (RemoteException e) { 7068 throw e.rethrowFromSystemServer(); 7069 } 7070 } 7071 7072 /** 7073 * Sets and persists a certain surround format as enabled or not. 7074 * <p> 7075 * This API is called by TvSettings surround sound menu when user enables or disables a 7076 * surround sound format. This setting is persisted as global user setting. 7077 * Applications should revert their changes to surround sound settings unless they intend to 7078 * modify the global user settings across all apps. The framework does not auto-revert an 7079 * application's settings after a lifecycle event. Audio focus is not required to apply these 7080 * settings. 7081 * 7082 * @param enabled the required surround format state, true for enabled, false for disabled 7083 * @return true if successful, otherwise false 7084 */ 7085 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS) setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)7086 public boolean setSurroundFormatEnabled( 7087 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { 7088 try { 7089 return getService().setSurroundFormatEnabled(audioFormat, enabled); 7090 } catch (RemoteException e) { 7091 throw e.rethrowFromSystemServer(); 7092 } 7093 } 7094 7095 /** 7096 * Gets whether a certain surround format is enabled or not. 7097 * @param audioFormat a surround format 7098 * 7099 * @return whether the required surround format is enabled 7100 */ isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)7101 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) { 7102 try { 7103 return getService().isSurroundFormatEnabled(audioFormat); 7104 } catch (RemoteException e) { 7105 throw e.rethrowFromSystemServer(); 7106 } 7107 } 7108 7109 /** 7110 * @hide 7111 * Returns all surround formats that are reported by the connected HDMI device. 7112 * The return values are not affected by calling setSurroundFormatEnabled. 7113 * 7114 * @return a list of surround formats 7115 */ 7116 @TestApi 7117 @NonNull getReportedSurroundFormats()7118 public List<Integer> getReportedSurroundFormats() { 7119 try { 7120 return getService().getReportedSurroundFormats(); 7121 } catch (RemoteException e) { 7122 throw e.rethrowFromSystemServer(); 7123 } 7124 } 7125 7126 /** 7127 * Return if audio haptic coupled playback is supported or not. 7128 * 7129 * @return whether audio haptic playback supported. 7130 */ isHapticPlaybackSupported()7131 public static boolean isHapticPlaybackSupported() { 7132 return AudioSystem.isHapticPlaybackSupported(); 7133 } 7134 7135 /** 7136 * @hide 7137 * Introspection API to retrieve audio product strategies. 7138 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 7139 * audio product strategies, which is indexed by a weakly typed index in order to be extended 7140 * by OEM without any needs of AOSP patches. 7141 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product 7142 * strategy refered either by its index or human readable string. It will allow clients 7143 * application to start streaming data using these {@link AudioAttributes} on the selected 7144 * device by Audio Policy Engine. 7145 * @return a (possibly zero-length) array of 7146 * {@see android.media.audiopolicy.AudioProductStrategy} objects. 7147 */ 7148 @SystemApi 7149 @NonNull 7150 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioProductStrategies()7151 public static List<AudioProductStrategy> getAudioProductStrategies() { 7152 final IAudioService service = getService(); 7153 try { 7154 return service.getAudioProductStrategies(); 7155 } catch (RemoteException e) { 7156 throw e.rethrowFromSystemServer(); 7157 } 7158 } 7159 7160 /** 7161 * @hide 7162 * Introspection API to retrieve audio volume groups. 7163 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 7164 * audio volume groups. 7165 * @return a (possibly zero-length) List of 7166 * {@see android.media.audiopolicy.AudioVolumeGroup} objects. 7167 */ 7168 @SystemApi 7169 @NonNull 7170 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioVolumeGroups()7171 public static List<AudioVolumeGroup> getAudioVolumeGroups() { 7172 final IAudioService service = getService(); 7173 try { 7174 return service.getAudioVolumeGroups(); 7175 } catch (RemoteException e) { 7176 throw e.rethrowFromSystemServer(); 7177 } 7178 } 7179 7180 /** 7181 * @hide 7182 * Callback registered by client to be notified upon volume group change. 7183 */ 7184 @SystemApi 7185 public abstract static class VolumeGroupCallback { 7186 /** 7187 * Callback method called upon audio volume group change. 7188 * @param group the group for which the volume has changed 7189 */ onAudioVolumeGroupChanged(int group, int flags)7190 public void onAudioVolumeGroupChanged(int group, int flags) {} 7191 } 7192 7193 /** 7194 * @hide 7195 * Register an audio volume group change listener. 7196 * @param callback the {@link VolumeGroupCallback} to register 7197 */ 7198 @SystemApi registerVolumeGroupCallback( @onNull Executor executor, @NonNull VolumeGroupCallback callback)7199 public void registerVolumeGroupCallback( 7200 @NonNull Executor executor, 7201 @NonNull VolumeGroupCallback callback) { 7202 Preconditions.checkNotNull(executor, "executor must not be null"); 7203 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 7204 sAudioAudioVolumeGroupChangedHandler.init(); 7205 // TODO: make use of executor 7206 sAudioAudioVolumeGroupChangedHandler.registerListener(callback); 7207 } 7208 7209 /** 7210 * @hide 7211 * Unregister an audio volume group change listener. 7212 * @param callback the {@link VolumeGroupCallback} to unregister 7213 */ 7214 @SystemApi unregisterVolumeGroupCallback( @onNull VolumeGroupCallback callback)7215 public void unregisterVolumeGroupCallback( 7216 @NonNull VolumeGroupCallback callback) { 7217 Preconditions.checkNotNull(callback, "volume group change cb must not be null"); 7218 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback); 7219 } 7220 7221 /** 7222 * Return if an asset contains haptic channels or not. 7223 * 7224 * @param context the {@link Context} to resolve the uri. 7225 * @param uri the {@link Uri} of the asset. 7226 * @return true if the assert contains haptic channels. 7227 * @hide 7228 */ hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)7229 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) { 7230 MediaExtractor extractor = new MediaExtractor(); 7231 try { 7232 extractor.setDataSource(context, uri, null); 7233 for (int i = 0; i < extractor.getTrackCount(); i++) { 7234 MediaFormat format = extractor.getTrackFormat(i); 7235 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) 7236 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) { 7237 return true; 7238 } 7239 } 7240 } catch (IOException e) { 7241 Log.e(TAG, "hasHapticChannels failure:" + e); 7242 } 7243 return false; 7244 } 7245 7246 /** 7247 * Return if an asset contains haptic channels or not. 7248 * 7249 * @param context the {@link Context} to resolve the uri. 7250 * @param uri the {@link Uri} of the asset. 7251 * @return true if the assert contains haptic channels. 7252 * @hide 7253 */ hasHapticChannels(@ullable Context context, @NonNull Uri uri)7254 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) { 7255 Objects.requireNonNull(uri); 7256 7257 if (context != null) { 7258 return hasHapticChannelsImpl(context, uri); 7259 } 7260 7261 Context cachedContext = sContext.get(); 7262 if (cachedContext != null) { 7263 if (DEBUG) { 7264 Log.d(TAG, "Try to use static context to query if having haptic channels"); 7265 } 7266 return hasHapticChannelsImpl(cachedContext, uri); 7267 } 7268 7269 // Try with audio service context, this may fail to get correct result. 7270 if (DEBUG) { 7271 Log.d(TAG, "Try to use audio service context to query if having haptic channels"); 7272 } 7273 try { 7274 return getService().hasHapticChannels(uri); 7275 } catch (RemoteException e) { 7276 throw e.rethrowFromSystemServer(); 7277 } 7278 } 7279 7280 /** 7281 * Set whether or not there is an active RTT call. 7282 * This method should be called by Telecom service. 7283 * @hide 7284 * TODO: make this a @SystemApi 7285 */ setRttEnabled(boolean rttEnabled)7286 public static void setRttEnabled(boolean rttEnabled) { 7287 try { 7288 getService().setRttEnabled(rttEnabled); 7289 } catch (RemoteException e) { 7290 throw e.rethrowFromSystemServer(); 7291 } 7292 } 7293 7294 /** 7295 * Adjusts the volume of the most relevant stream, or the given fallback 7296 * stream. 7297 * <p> 7298 * This method should only be used by applications that replace the 7299 * platform-wide management of audio settings or the main telephony 7300 * application. 7301 * <p> 7302 * This method has no effect if the device implements a fixed volume policy 7303 * as indicated by {@link #isVolumeFixed()}. 7304 * <p>This API checks if the caller has the necessary permissions based on the provided 7305 * component name, uid, and pid values. 7306 * See {@link #adjustSuggestedStreamVolume(int, int, int)}. 7307 * 7308 * @param suggestedStreamType The stream type that will be used if there 7309 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 7310 * valid here. 7311 * @param direction The direction to adjust the volume. One of 7312 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 7313 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 7314 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 7315 * @param flags One or more flags. 7316 * @param packageName the package name of client application 7317 * @param uid the uid of client application 7318 * @param pid the pid of client application 7319 * @param targetSdkVersion the target sdk version of client application 7320 * @see #adjustVolume(int, int) 7321 * @see #adjustStreamVolume(int, int, int) 7322 * @see #setStreamVolume(int, int, int) 7323 * @see #isVolumeFixed() 7324 * 7325 * @hide 7326 */ 7327 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7328 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags, 7329 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7330 try { 7331 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags, 7332 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7333 } catch (RemoteException e) { 7334 throw e.rethrowFromSystemServer(); 7335 } 7336 } 7337 7338 /** 7339 * Adjusts the volume of a particular stream by one step in a direction. 7340 * <p> 7341 * This method should only be used by applications that replace the platform-wide 7342 * management of audio settings or the main telephony application. 7343 * <p>This method has no effect if the device implements a fixed volume policy 7344 * as indicated by {@link #isVolumeFixed()}. 7345 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 7346 * unless the app has been granted Do Not Disturb Access. 7347 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 7348 * <p>This API checks if the caller has the necessary permissions based on the provided 7349 * component name, uid, and pid values. 7350 * See {@link #adjustStreamVolume(int, int, int)}. 7351 * 7352 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 7353 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 7354 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 7355 * @param direction The direction to adjust the volume. One of 7356 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 7357 * {@link #ADJUST_SAME}. 7358 * @param flags One or more flags. 7359 * @param packageName the package name of client application 7360 * @param uid the uid of client application 7361 * @param pid the pid of client application 7362 * @param targetSdkVersion the target sdk version of client application 7363 * @see #adjustVolume(int, int) 7364 * @see #setStreamVolume(int, int, int) 7365 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 7366 * and the caller is not granted notification policy access. 7367 * 7368 * @hide 7369 */ 7370 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustStreamVolumeForUid(int streamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7371 public void adjustStreamVolumeForUid(int streamType, int direction, int flags, 7372 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7373 try { 7374 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid, 7375 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7376 } catch (RemoteException e) { 7377 throw e.rethrowFromSystemServer(); 7378 } 7379 } 7380 7381 /** 7382 * Sets the volume index for a particular stream. 7383 * <p>This method has no effect if the device implements a fixed volume policy 7384 * as indicated by {@link #isVolumeFixed()}. 7385 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 7386 * the app has been granted Do Not Disturb Access. 7387 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 7388 * <p>This API checks if the caller has the necessary permissions based on the provided 7389 * component name, uid, and pid values. 7390 * See {@link #setStreamVolume(int, int, int)}. 7391 * 7392 * @param streamType The stream whose volume index should be set. 7393 * @param index The volume index to set. See 7394 * {@link #getStreamMaxVolume(int)} for the largest valid value. 7395 * @param flags One or more flags. 7396 * @param packageName the package name of client application 7397 * @param uid the uid of client application 7398 * @param pid the pid of client application 7399 * @param targetSdkVersion the target sdk version of client application 7400 * @see #getStreamMaxVolume(int) 7401 * @see #getStreamVolume(int) 7402 * @see #isVolumeFixed() 7403 * @throws SecurityException if the volume change triggers a Do Not Disturb change 7404 * and the caller is not granted notification policy access. 7405 * 7406 * @hide 7407 */ 7408 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setStreamVolumeForUid(int streamType, int index, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7409 public void setStreamVolumeForUid(int streamType, int index, int flags, 7410 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 7411 try { 7412 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid, 7413 UserHandle.getUserHandleForUid(uid), targetSdkVersion); 7414 } catch (RemoteException e) { 7415 throw e.rethrowFromSystemServer(); 7416 } 7417 } 7418 7419 7420 /** @hide 7421 * TODO: make this a @SystemApi */ 7422 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) setMultiAudioFocusEnabled(boolean enabled)7423 public void setMultiAudioFocusEnabled(boolean enabled) { 7424 try { 7425 getService().setMultiAudioFocusEnabled(enabled); 7426 } catch (RemoteException e) { 7427 throw e.rethrowFromSystemServer(); 7428 } 7429 } 7430 7431 7432 /** 7433 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID. 7434 * For more details on Hardware A/V synchronization please refer to 7435 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/"> 7436 * media tunneling documentation</a>. 7437 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved. 7438 * @return the HW A/V sync ID for this audio session (an integer different from 0). 7439 * @throws UnsupportedOperationException if HW A/V synchronization is not supported. 7440 */ getAudioHwSyncForSession(int sessionId)7441 public int getAudioHwSyncForSession(int sessionId) { 7442 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId); 7443 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) { 7444 throw new UnsupportedOperationException("HW A/V synchronization is not supported."); 7445 } 7446 return hwSyncId; 7447 } 7448 7449 /** 7450 * Selects the audio device that should be used for communication use cases, for instance voice 7451 * or video calls. This method can be used by voice or video chat applications to select a 7452 * different audio device than the one selected by default by the platform. 7453 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by 7454 * {@link #getAvailableCommunicationDevices()}. 7455 * The selection is active as long as the requesting application process lives, until 7456 * {@link #clearCommunicationDevice} is called or until the device is disconnected. 7457 * It is therefore important for applications to clear the request when a call ends or the 7458 * the requesting activity or service is stopped or destroyed. 7459 * <p>In case of simultaneous requests by multiple applications the priority is given to the 7460 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the 7461 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode 7462 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main 7463 * telephony application with permission 7464 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}. 7465 * <p> If the requested devices is not currently available, the request will be rejected and 7466 * the method will return false. 7467 * <p>This API replaces the following deprecated APIs: 7468 * <ul> 7469 * <li> {@link #startBluetoothSco()} 7470 * <li> {@link #stopBluetoothSco()} 7471 * <li> {@link #setSpeakerphoneOn(boolean)} 7472 * </ul> 7473 * <h4>Example</h4> 7474 * <p>The example below shows how to enable and disable speakerphone mode. 7475 * <pre class="prettyprint"> 7476 * // Get an AudioManager instance 7477 * AudioManager audioManager = Context.getSystemService(AudioManager.class); 7478 * AudioDeviceInfo speakerDevice = null; 7479 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); 7480 * for (AudioDeviceInfo device : devices) { 7481 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { 7482 * speakerDevice = device; 7483 * break; 7484 * } 7485 * } 7486 * if (speakerDevice != null) { 7487 * // Turn speakerphone ON. 7488 * boolean result = audioManager.setCommunicationDevice(speakerDevice); 7489 * if (!result) { 7490 * // Handle error. 7491 * } 7492 * // Turn speakerphone OFF. 7493 * audioManager.clearCommunicationDevice(); 7494 * } 7495 * </pre> 7496 * @param device the requested audio device. 7497 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. 7498 * @throws IllegalArgumentException If an invalid device is specified. 7499 */ setCommunicationDevice(@onNull AudioDeviceInfo device)7500 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { 7501 Objects.requireNonNull(device); 7502 try { 7503 if (device.getId() == 0) { 7504 throw new IllegalArgumentException("In valid device: " + device); 7505 } 7506 return getService().setCommunicationDevice(mICallBack, device.getId()); 7507 } catch (RemoteException e) { 7508 throw e.rethrowFromSystemServer(); 7509 } 7510 } 7511 7512 /** 7513 * Cancels previous communication device selection made with 7514 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 7515 */ clearCommunicationDevice()7516 public void clearCommunicationDevice() { 7517 try { 7518 getService().setCommunicationDevice(mICallBack, 0); 7519 } catch (RemoteException e) { 7520 throw e.rethrowFromSystemServer(); 7521 } 7522 } 7523 7524 /** 7525 * Returns currently selected audio device for communication. 7526 * <p>This API replaces the following deprecated APIs: 7527 * <ul> 7528 * <li> {@link #isBluetoothScoOn()} 7529 * <li> {@link #isSpeakerphoneOn()} 7530 * </ul> 7531 * @return an {@link AudioDeviceInfo} indicating which audio device is 7532 * currently selected for communication use cases. Can be null on platforms 7533 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 7534 * is used. 7535 */ 7536 @Nullable getCommunicationDevice()7537 public AudioDeviceInfo getCommunicationDevice() { 7538 try { 7539 return getDeviceForPortId( 7540 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); 7541 } catch (RemoteException e) { 7542 throw e.rethrowFromSystemServer(); 7543 } 7544 } 7545 7546 /** 7547 * Returns a list of audio devices that can be selected for communication use cases via 7548 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 7549 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). 7550 */ 7551 @NonNull getAvailableCommunicationDevices()7552 public List<AudioDeviceInfo> getAvailableCommunicationDevices() { 7553 try { 7554 ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); 7555 int[] portIds = getService().getAvailableCommunicationDeviceIds(); 7556 for (int portId : portIds) { 7557 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 7558 if (device == null) { 7559 continue; 7560 } 7561 devices.add(device); 7562 } 7563 return devices; 7564 } catch (RemoteException e) { 7565 throw e.rethrowFromSystemServer(); 7566 } 7567 } 7568 7569 /** 7570 * @hide 7571 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided. 7572 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 7573 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 7574 * The method will return null if no device of the provided type is connected. 7575 * If more than one device of the provided type is connected, an object corresponding to the 7576 * first device encountered in the enumeration list will be returned. 7577 * @param deviceType The device device for which an <code>AudioDeviceInfo</code> 7578 * object is queried. 7579 * @return An AudioDeviceInfo object or null if no device with the requested type is connected. 7580 * @throws IllegalArgumentException If an invalid device type is specified. 7581 */ 7582 @TestApi 7583 @Nullable getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)7584 public static AudioDeviceInfo getDeviceInfoFromType( 7585 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 7586 return getDeviceInfoFromTypeAndAddress(deviceType, null); 7587 } 7588 7589 /** 7590 * @hide 7591 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and 7592 * address provided. 7593 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 7594 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 7595 * If a null address is provided, the matching will happen on the type only. 7596 * The method will return null if no device of the provided type and address is connected. 7597 * If more than one device of the provided type is connected, an object corresponding to the 7598 * first device encountered in the enumeration list will be returned. 7599 * @param type The device device for which an <code>AudioDeviceInfo</code> 7600 * object is queried. 7601 * @param address The device address for which an <code>AudioDeviceInfo</code> 7602 * object is queried or null if requesting match on type only. 7603 * @return An AudioDeviceInfo object or null if no matching device is connected. 7604 * @throws IllegalArgumentException If an invalid device type is specified. 7605 */ 7606 @Nullable getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)7607 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( 7608 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { 7609 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); 7610 AudioDeviceInfo deviceForType = null; 7611 for (AudioDeviceInfo device : devices) { 7612 if (device.getType() == type) { 7613 deviceForType = device; 7614 if (address == null || address.equals(device.getAddress())) { 7615 return device; 7616 } 7617 } 7618 } 7619 return deviceForType; 7620 } 7621 7622 /** 7623 * Listener registered by client to be notified upon communication audio device change. 7624 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7625 */ 7626 public interface OnCommunicationDeviceChangedListener { 7627 /** 7628 * Callback method called upon communication audio device change. 7629 * @param device the audio device requested for communication use cases. 7630 * Can be null on platforms not supporting 7631 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 7632 */ onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)7633 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); 7634 } 7635 7636 /** 7637 * Adds a listener for being notified of changes to the communication audio device. 7638 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7639 * @param executor 7640 * @param listener 7641 */ addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)7642 public void addOnCommunicationDeviceChangedListener( 7643 @NonNull @CallbackExecutor Executor executor, 7644 @NonNull OnCommunicationDeviceChangedListener listener) { 7645 Objects.requireNonNull(executor); 7646 Objects.requireNonNull(listener); 7647 synchronized (mCommDevListenerLock) { 7648 if (hasCommDevListener(listener)) { 7649 throw new IllegalArgumentException( 7650 "attempt to call addOnCommunicationDeviceChangedListener() " 7651 + "on a previously registered listener"); 7652 } 7653 // lazy initialization of the list of strategy-preferred device listener 7654 if (mCommDevListeners == null) { 7655 mCommDevListeners = new ArrayList<>(); 7656 } 7657 final int oldCbCount = mCommDevListeners.size(); 7658 mCommDevListeners.add(new CommDevListenerInfo(listener, executor)); 7659 if (oldCbCount == 0 && mCommDevListeners.size() > 0) { 7660 // register binder for callbacks 7661 if (mCommDevDispatcherStub == null) { 7662 mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub(); 7663 } 7664 try { 7665 getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub); 7666 } catch (RemoteException e) { 7667 throw e.rethrowFromSystemServer(); 7668 } 7669 } 7670 } 7671 } 7672 7673 /** 7674 * Removes a previously added listener of changes to the communication audio device. 7675 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 7676 * @param listener 7677 */ removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)7678 public void removeOnCommunicationDeviceChangedListener( 7679 @NonNull OnCommunicationDeviceChangedListener listener) { 7680 Objects.requireNonNull(listener); 7681 synchronized (mCommDevListenerLock) { 7682 if (!removeCommDevListener(listener)) { 7683 throw new IllegalArgumentException( 7684 "attempt to call removeOnCommunicationDeviceChangedListener() " 7685 + "on an unregistered listener"); 7686 } 7687 if (mCommDevListeners.size() == 0) { 7688 // unregister binder for callbacks 7689 try { 7690 getService().unregisterCommunicationDeviceDispatcher( 7691 mCommDevDispatcherStub); 7692 } catch (RemoteException e) { 7693 throw e.rethrowFromSystemServer(); 7694 } finally { 7695 mCommDevDispatcherStub = null; 7696 mCommDevListeners = null; 7697 } 7698 } 7699 } 7700 } 7701 7702 private final Object mCommDevListenerLock = new Object(); 7703 /** 7704 * List of listeners for preferred device for strategy and their associated Executor. 7705 * List is lazy-initialized on first registration 7706 */ 7707 @GuardedBy("mCommDevListenerLock") 7708 private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners; 7709 7710 private static class CommDevListenerInfo { 7711 final @NonNull OnCommunicationDeviceChangedListener mListener; 7712 final @NonNull Executor mExecutor; 7713 CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe)7714 CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) { 7715 mListener = listener; 7716 mExecutor = exe; 7717 } 7718 } 7719 7720 @GuardedBy("mCommDevListenerLock") 7721 private CommunicationDeviceDispatcherStub mCommDevDispatcherStub; 7722 7723 private final class CommunicationDeviceDispatcherStub 7724 extends ICommunicationDeviceDispatcher.Stub { 7725 7726 @Override dispatchCommunicationDeviceChanged(int portId)7727 public void dispatchCommunicationDeviceChanged(int portId) { 7728 // make a shallow copy of listeners so callback is not executed under lock 7729 final ArrayList<CommDevListenerInfo> commDevListeners; 7730 synchronized (mCommDevListenerLock) { 7731 if (mCommDevListeners == null || mCommDevListeners.size() == 0) { 7732 return; 7733 } 7734 commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone(); 7735 } 7736 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 7737 final long ident = Binder.clearCallingIdentity(); 7738 try { 7739 for (CommDevListenerInfo info : commDevListeners) { 7740 info.mExecutor.execute(() -> 7741 info.mListener.onCommunicationDeviceChanged(device)); 7742 } 7743 } finally { 7744 Binder.restoreCallingIdentity(ident); 7745 } 7746 } 7747 } 7748 7749 @GuardedBy("mCommDevListenerLock") getCommDevListenerInfo( OnCommunicationDeviceChangedListener listener)7750 private @Nullable CommDevListenerInfo getCommDevListenerInfo( 7751 OnCommunicationDeviceChangedListener listener) { 7752 if (mCommDevListeners == null) { 7753 return null; 7754 } 7755 for (CommDevListenerInfo info : mCommDevListeners) { 7756 if (info.mListener == listener) { 7757 return info; 7758 } 7759 } 7760 return null; 7761 } 7762 7763 @GuardedBy("mCommDevListenerLock") hasCommDevListener(OnCommunicationDeviceChangedListener listener)7764 private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) { 7765 return getCommDevListenerInfo(listener) != null; 7766 } 7767 7768 @GuardedBy("mCommDevListenerLock") 7769 /** 7770 * @return true if the listener was removed from the list 7771 */ removeCommDevListener(OnCommunicationDeviceChangedListener listener)7772 private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) { 7773 final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener); 7774 if (infoToRemove != null) { 7775 mCommDevListeners.remove(infoToRemove); 7776 return true; 7777 } 7778 return false; 7779 } 7780 7781 //--------------------------------------------------------- 7782 // Inner classes 7783 //-------------------- 7784 /** 7785 * Helper class to handle the forwarding of native events to the appropriate listener 7786 * (potentially) handled in a different thread. 7787 */ 7788 private class NativeEventHandlerDelegate { 7789 private final Handler mHandler; 7790 NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)7791 NativeEventHandlerDelegate(final AudioDeviceCallback callback, 7792 Handler handler) { 7793 // find the looper for our new event handler 7794 Looper looper; 7795 if (handler != null) { 7796 looper = handler.getLooper(); 7797 } else { 7798 // no given handler, use the looper the addListener call was called in 7799 looper = Looper.getMainLooper(); 7800 } 7801 7802 // construct the event handler with this looper 7803 if (looper != null) { 7804 // implement the event handler delegate 7805 mHandler = new Handler(looper) { 7806 @Override 7807 public void handleMessage(Message msg) { 7808 switch(msg.what) { 7809 case MSG_DEVICES_CALLBACK_REGISTERED: 7810 case MSG_DEVICES_DEVICES_ADDED: 7811 if (callback != null) { 7812 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj); 7813 } 7814 break; 7815 7816 case MSG_DEVICES_DEVICES_REMOVED: 7817 if (callback != null) { 7818 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj); 7819 } 7820 break; 7821 7822 default: 7823 Log.e(TAG, "Unknown native event type: " + msg.what); 7824 break; 7825 } 7826 } 7827 }; 7828 } else { 7829 mHandler = null; 7830 } 7831 } 7832 getHandler()7833 Handler getHandler() { 7834 return mHandler; 7835 } 7836 } 7837 } 7838