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