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