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