• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
20 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
21 import static android.content.Context.DEVICE_ID_DEFAULT;
22 import static android.media.audio.Flags.autoPublicVolumeApiHardening;
23 import static android.media.audio.Flags.automaticBtDeviceType;
24 import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING;
25 import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API;
26 import static android.media.audio.Flags.FLAG_SUPPORTED_DEVICE_TYPES_API;
27 import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION;
28 
29 import android.Manifest;
30 import android.annotation.CallbackExecutor;
31 import android.annotation.FlaggedApi;
32 import android.annotation.IntDef;
33 import android.annotation.IntRange;
34 import android.annotation.NonNull;
35 import android.annotation.Nullable;
36 import android.annotation.RequiresPermission;
37 import android.annotation.SdkConstant;
38 import android.annotation.SdkConstant.SdkConstantType;
39 import android.annotation.SuppressLint;
40 import android.annotation.SystemApi;
41 import android.annotation.SystemService;
42 import android.annotation.TestApi;
43 import android.app.NotificationManager;
44 import android.app.PendingIntent;
45 import android.app.compat.CompatChanges;
46 import android.bluetooth.BluetoothCodecConfig;
47 import android.bluetooth.BluetoothDevice;
48 import android.bluetooth.BluetoothLeAudioCodecConfig;
49 import android.companion.virtual.VirtualDeviceManager;
50 import android.compat.annotation.ChangeId;
51 import android.compat.annotation.EnabledSince;
52 import android.compat.annotation.Overridable;
53 import android.compat.annotation.UnsupportedAppUsage;
54 import android.content.ComponentName;
55 import android.content.Context;
56 import android.content.Intent;
57 import android.content.pm.PackageManager;
58 import android.media.AudioAttributes.AttributeSystemUsage;
59 import android.media.CallbackUtil.ListenerInfo;
60 import android.media.audiopolicy.AudioPolicy;
61 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
62 import android.media.audiopolicy.AudioProductStrategy;
63 import android.media.audiopolicy.AudioVolumeGroup;
64 import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
65 import android.media.projection.MediaProjection;
66 import android.media.session.MediaController;
67 import android.media.session.MediaSession;
68 import android.media.session.MediaSessionLegacyHelper;
69 import android.media.session.MediaSessionManager;
70 import android.net.Uri;
71 import android.os.Binder;
72 import android.os.Build;
73 import android.os.Handler;
74 import android.os.IBinder;
75 import android.os.Looper;
76 import android.os.Message;
77 import android.os.RemoteException;
78 import android.os.ServiceManager;
79 import android.os.SystemClock;
80 import android.os.UserHandle;
81 import android.provider.Settings;
82 import android.text.TextUtils;
83 import android.util.ArrayMap;
84 import android.util.IntArray;
85 import android.util.Log;
86 import android.util.Pair;
87 import android.view.KeyEvent;
88 
89 import com.android.internal.annotations.GuardedBy;
90 import com.android.internal.util.Preconditions;
91 
92 import java.io.IOException;
93 import java.lang.annotation.Retention;
94 import java.lang.annotation.RetentionPolicy;
95 import java.lang.ref.WeakReference;
96 import java.util.ArrayList;
97 import java.util.Arrays;
98 import java.util.Collections;
99 import java.util.HashMap;
100 import java.util.HashSet;
101 import java.util.Iterator;
102 import java.util.List;
103 import java.util.Map;
104 import java.util.Objects;
105 import java.util.Set;
106 import java.util.TreeMap;
107 import java.util.concurrent.ConcurrentHashMap;
108 import java.util.concurrent.Executor;
109 import java.util.concurrent.Executors;
110 import java.util.concurrent.TimeUnit;
111 
112 /**
113  * AudioManager provides access to volume and ringer mode control.
114  */
115 @SystemService(Context.AUDIO_SERVICE)
116 public class AudioManager {
117 
118     private Context mOriginalContext;
119     private Context mApplicationContext;
120     private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT;
121     private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
122     private static final String TAG = "AudioManager";
123     private static final boolean DEBUG = false;
124     private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
125     private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
126             new AudioVolumeGroupChangeHandler();
127 
128     private static WeakReference<Context> sContext;
129 
130     /**
131      * Broadcast intent, a hint for applications that audio is about to become
132      * 'noisy' due to a change in audio outputs. For example, this intent may
133      * be sent when a wired headset is unplugged, or when an A2DP audio
134      * sink is disconnected, and the audio system is about to automatically
135      * switch audio route to the speaker. Applications that are controlling
136      * audio streams may consider pausing, reducing volume or some other action
137      * on receipt of this intent so as not to surprise the user with audio
138      * from the speaker.
139      */
140     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141     public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
142 
143     /**
144      * Sticky broadcast intent action indicating that the ringer mode has
145      * changed. Includes the new ringer mode.
146      *
147      * @see #EXTRA_RINGER_MODE
148      */
149     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
150     public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
151 
152     /**
153      * @hide
154      * Sticky broadcast intent action indicating that the internal ringer mode has
155      * changed. Includes the new ringer mode.
156      *
157      * @see #EXTRA_RINGER_MODE
158      */
159     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
160     public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
161             "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
162 
163     /**
164      * The new ringer mode.
165      *
166      * @see #RINGER_MODE_CHANGED_ACTION
167      * @see #RINGER_MODE_NORMAL
168      * @see #RINGER_MODE_SILENT
169      * @see #RINGER_MODE_VIBRATE
170      */
171     public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
172 
173     /**
174      * Broadcast intent action indicating that the vibrate setting has
175      * changed. Includes the vibrate type and its new setting.
176      *
177      * @see #EXTRA_VIBRATE_TYPE
178      * @see #EXTRA_VIBRATE_SETTING
179      * @deprecated Applications should maintain their own vibrate policy based on
180      * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
181      */
182     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
183     public static final String VIBRATE_SETTING_CHANGED_ACTION =
184         "android.media.VIBRATE_SETTING_CHANGED";
185 
186     /**
187      * @hide Broadcast intent when the volume for a particular stream type changes.
188      * Includes the stream, the new volume and previous volumes.
189      * Notes:
190      *  - for internal platform use only, do not make public,
191      *  - never used for "remote" volume changes
192      *
193      * @see #EXTRA_VOLUME_STREAM_TYPE
194      * @see #EXTRA_VOLUME_STREAM_VALUE
195      * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
196      */
197     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
198     @UnsupportedAppUsage
199     public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
200 
201     /**
202      * @hide Broadcast intent when the volume for a particular stream type changes.
203      * Includes the stream, the new volume and previous volumes.
204      * Notes:
205      *  - for internal platform use only, do not make public,
206      *  - never used for "remote" volume changes
207      *
208      * @see #EXTRA_VOLUME_STREAM_TYPE
209      * @see #EXTRA_VOLUME_STREAM_VALUE
210      * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
211      */
212     @SystemApi
213     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
214     @SuppressLint("ActionValue")
215     public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION";
216 
217     /**
218      * @hide Broadcast intent when the devices for a particular stream type changes.
219      * Includes the stream, the new devices and previous devices.
220      * Notes:
221      *  - for internal platform use only, do not make public,
222      *  - never used for "remote" volume changes
223      *
224      * @see #EXTRA_VOLUME_STREAM_TYPE
225      * @see #EXTRA_VOLUME_STREAM_DEVICES
226      * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
227      * @see #getDevicesForStream
228      */
229     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
230     public static final String STREAM_DEVICES_CHANGED_ACTION =
231         "android.media.STREAM_DEVICES_CHANGED_ACTION";
232 
233     /**
234      * @hide Broadcast intent when a stream mute state changes.
235      * Includes the stream that changed and the new mute state
236      *
237      * @see #EXTRA_VOLUME_STREAM_TYPE
238      * @see #EXTRA_STREAM_VOLUME_MUTED
239      */
240     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
241     public static final String STREAM_MUTE_CHANGED_ACTION =
242         "android.media.STREAM_MUTE_CHANGED_ACTION";
243 
244     /**
245      * @hide Broadcast intent when the master mute state changes.
246      * Includes the the new volume
247      *
248      * @see #EXTRA_MASTER_VOLUME_MUTED
249      */
250     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
251     public static final String MASTER_MUTE_CHANGED_ACTION =
252         "android.media.MASTER_MUTE_CHANGED_ACTION";
253 
254     /**
255      * The new vibrate setting for a particular type.
256      *
257      * @see #VIBRATE_SETTING_CHANGED_ACTION
258      * @see #EXTRA_VIBRATE_TYPE
259      * @see #VIBRATE_SETTING_ON
260      * @see #VIBRATE_SETTING_OFF
261      * @see #VIBRATE_SETTING_ONLY_SILENT
262      * @deprecated Applications should maintain their own vibrate policy based on
263      * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
264      */
265     public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
266 
267     /**
268      * The vibrate type whose setting has changed.
269      *
270      * @see #VIBRATE_SETTING_CHANGED_ACTION
271      * @see #VIBRATE_TYPE_NOTIFICATION
272      * @see #VIBRATE_TYPE_RINGER
273      * @deprecated Applications should maintain their own vibrate policy based on
274      * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
275      */
276     public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
277 
278     /**
279      * @hide The stream type for the volume changed intent.
280      */
281     @SystemApi
282     @SuppressLint("ActionValue")
283     public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
284 
285     /**
286      * @hide
287      * The stream type alias for the volume changed intent.
288      * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
289      * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
290      * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
291      * {@link #STREAM_MUSIC} on others (e.g. a television).
292      */
293     public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
294             "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
295 
296     /**
297      * @hide The volume associated with the stream for the volume changed intent.
298      */
299     @SystemApi
300     @SuppressLint("ActionValue")
301     public static final String EXTRA_VOLUME_STREAM_VALUE =
302         "android.media.EXTRA_VOLUME_STREAM_VALUE";
303 
304     /**
305      * @hide The previous volume associated with the stream for the volume changed intent.
306      */
307     public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
308         "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
309 
310     /**
311      * @hide The devices associated with the stream for the stream devices changed intent.
312      */
313     public static final String EXTRA_VOLUME_STREAM_DEVICES =
314         "android.media.EXTRA_VOLUME_STREAM_DEVICES";
315 
316     /**
317      * @hide The previous devices associated with the stream for the stream devices changed intent.
318      */
319     public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
320         "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
321 
322     /**
323      * @hide The new master volume mute state for the master mute changed intent.
324      * Value is boolean
325      */
326     public static final String EXTRA_MASTER_VOLUME_MUTED =
327         "android.media.EXTRA_MASTER_VOLUME_MUTED";
328 
329     /**
330      * @hide The new stream volume mute state for the stream mute changed intent.
331      * Value is boolean
332      */
333     public static final String EXTRA_STREAM_VOLUME_MUTED =
334         "android.media.EXTRA_STREAM_VOLUME_MUTED";
335 
336     /**
337      * Broadcast Action: Wired Headset plugged in or unplugged.
338      *
339      * You <em>cannot</em> receive this through components declared
340      * in manifests, only by explicitly registering for it with
341      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
342      * Context.registerReceiver()}.
343      *
344      * <p>The intent will have the following extra values:
345      * <ul>
346      *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
347      *   <li><em>name</em> - Headset type, human readable string </li>
348      *   <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
349      * </ul>
350      * </ul>
351      */
352     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
353     public static final String ACTION_HEADSET_PLUG =
354             "android.intent.action.HEADSET_PLUG";
355 
356     /**
357      * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
358      *
359      * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
360      * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
361      * <p>It can only be received by explicitly registering for it with
362      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
363      */
364     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
365     public static final String ACTION_HDMI_AUDIO_PLUG =
366             "android.media.action.HDMI_AUDIO_PLUG";
367 
368     /**
369      * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
370      * or unplugged.
371      * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
372      */
373     public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
374 
375     /**
376      * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
377      * supported by the HDMI device.
378      * The corresponding integer value is only available when the device is plugged in (as expressed
379      * by {@link #EXTRA_AUDIO_PLUG_STATE}).
380      */
381     public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
382 
383     /**
384      * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
385      * the connected HDMI device.
386      * The corresponding array of encoding values is only available when the device is plugged in
387      * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
388      * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
389      * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
390      */
391     public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
392 
393     /** Used to identify the volume of audio streams for phone calls */
394     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
395     /** Used to identify the volume of audio streams for system sounds */
396     public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
397     /** Used to identify the volume of audio streams for the phone ring */
398     public static final int STREAM_RING = AudioSystem.STREAM_RING;
399     /** Used to identify the volume of audio streams for music playback */
400     public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
401     /** Used to identify the volume of audio streams for alarms */
402     public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
403     /** Used to identify the volume of audio streams for notifications */
404     public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
405     /** @hide Used to identify the volume of audio streams for phone calls when connected
406      *        to bluetooth */
407     @SystemApi
408     public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
409     /** @hide Used to identify the volume of audio streams for enforced system sounds
410      *        in certain countries (e.g camera in Japan) */
411     @UnsupportedAppUsage
412     public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
413     /** Used to identify the volume of audio streams for DTMF Tones */
414     public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
415     /** @hide Used to identify the volume of audio streams exclusively transmitted through the
416      *        speaker (TTS) of the device */
417     @UnsupportedAppUsage
418     public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
419     /** Used to identify the volume of audio streams for accessibility prompts */
420     public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
421     /** @hide Used to identify the volume of audio streams for virtual assistant */
422     @SystemApi
423     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
424     public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
425 
426     /** Number of audio streams */
427     /**
428      * @deprecated Do not iterate on volume stream type values.
429      */
430     @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
431 
432     /** @hide */
433     private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
434             AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
435             AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
436             AudioManager.STREAM_DTMF,  AudioManager.STREAM_ACCESSIBILITY };
437 
438     /** @hide */
439     @TestApi
getPublicStreamTypes()440     public static final int[] getPublicStreamTypes() {
441         return PUBLIC_STREAM_TYPES;
442     }
443 
444     /**
445      * Increase the ringer volume.
446      *
447      * @see #adjustVolume(int, int)
448      * @see #adjustStreamVolume(int, int, int)
449      */
450     public static final int ADJUST_RAISE = 1;
451 
452     /**
453      * Decrease the ringer volume.
454      *
455      * @see #adjustVolume(int, int)
456      * @see #adjustStreamVolume(int, int, int)
457      */
458     public static final int ADJUST_LOWER = -1;
459 
460     /**
461      * Maintain the previous ringer volume. This may be useful when needing to
462      * show the volume toast without actually modifying the volume.
463      *
464      * @see #adjustVolume(int, int)
465      * @see #adjustStreamVolume(int, int, int)
466      */
467     public static final int ADJUST_SAME = 0;
468 
469     /**
470      * Mute the volume. Has no effect if the stream is already muted.
471      *
472      * @see #adjustVolume(int, int)
473      * @see #adjustStreamVolume(int, int, int)
474      */
475     public static final int ADJUST_MUTE = -100;
476 
477     /**
478      * Unmute the volume. Has no effect if the stream is not muted.
479      *
480      * @see #adjustVolume(int, int)
481      * @see #adjustStreamVolume(int, int, int)
482      */
483     public static final int ADJUST_UNMUTE = 100;
484 
485     /**
486      * Toggle the mute state. If muted the stream will be unmuted. If not muted
487      * the stream will be muted.
488      *
489      * @see #adjustVolume(int, int)
490      * @see #adjustStreamVolume(int, int, int)
491      */
492     public static final int ADJUST_TOGGLE_MUTE = 101;
493 
494     /** @hide */
495     @IntDef(flag = false, prefix = "ADJUST", value = {
496             ADJUST_RAISE,
497             ADJUST_LOWER,
498             ADJUST_SAME,
499             ADJUST_MUTE,
500             ADJUST_UNMUTE,
501             ADJUST_TOGGLE_MUTE }
502             )
503     @Retention(RetentionPolicy.SOURCE)
504     public @interface VolumeAdjustment {}
505 
506     /** @hide */
adjustToString(int adj)507     public static final String adjustToString(int adj) {
508         switch (adj) {
509             case ADJUST_RAISE: return "ADJUST_RAISE";
510             case ADJUST_LOWER: return "ADJUST_LOWER";
511             case ADJUST_SAME: return "ADJUST_SAME";
512             case ADJUST_MUTE: return "ADJUST_MUTE";
513             case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
514             case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
515             default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
516         }
517     }
518 
519     // Flags should be powers of 2!
520 
521     /**
522      * Show a toast containing the current volume.
523      *
524      * @see #adjustStreamVolume(int, int, int)
525      * @see #adjustVolume(int, int)
526      * @see #setStreamVolume(int, int, int)
527      * @see #setRingerMode(int)
528      */
529     public static final int FLAG_SHOW_UI = 1 << 0;
530 
531     /**
532      * Whether to include ringer modes as possible options when changing volume.
533      * For example, if true and volume level is 0 and the volume is adjusted
534      * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
535      * vibrate mode.
536      * <p>
537      * By default this is on for the ring stream. If this flag is included,
538      * this behavior will be present regardless of the stream type being
539      * affected by the ringer mode.
540      *
541      * @see #adjustVolume(int, int)
542      * @see #adjustStreamVolume(int, int, int)
543      */
544     public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
545 
546     /**
547      * Whether to play a sound when changing the volume.
548      * <p>
549      * If this is given to {@link #adjustVolume(int, int)} or
550      * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
551      * in some cases (for example, the decided stream type is not
552      * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
553      * downward).
554      *
555      * @see #adjustStreamVolume(int, int, int)
556      * @see #adjustVolume(int, int)
557      * @see #setStreamVolume(int, int, int)
558      */
559     public static final int FLAG_PLAY_SOUND = 1 << 2;
560 
561     /**
562      * Removes any sounds/vibrate that may be in the queue, or are playing (related to
563      * changing volume).
564      */
565     public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
566 
567     /**
568      * Whether to vibrate if going into the vibrate ringer mode.
569      */
570     public static final int FLAG_VIBRATE = 1 << 4;
571 
572     /**
573      * Indicates to VolumePanel that the volume slider should be disabled as user
574      * cannot change the stream volume
575      * @hide
576      */
577     public static final int FLAG_FIXED_VOLUME = 1 << 5;
578 
579     /**
580      * Indicates the volume set/adjust call is for Bluetooth absolute volume
581      * @hide
582      */
583     @SystemApi
584     public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
585 
586     /**
587      * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
588      * @hide
589      */
590     public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
591 
592     /**
593      * Indicates the volume call is for Hdmi Cec system audio volume
594      * @hide
595      */
596     public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
597 
598     /**
599      * Indicates that this should only be handled if media is actively playing.
600      * @hide
601      */
602     public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
603 
604     /**
605      * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
606      * @hide
607      */
608     public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
609 
610     /**
611      * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
612      * @hide
613      */
614     public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
615 
616     /**
617      * Adjusting the volume due to a hardware key press.
618      * This flag can be used in the places in order to denote (or check) that a volume adjustment
619      * request is from a hardware key press. (e.g. {@link MediaController}).
620      * @hide
621      */
622     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
623     public static final int FLAG_FROM_KEY = 1 << 12;
624 
625     /**
626      * Indicates that an absolute volume controller is notifying AudioService of a change in the
627      * volume or mute status of an external audio system.
628      * @hide
629      */
630     public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13;
631 
632     /** @hide */
633     @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
634             ENCODED_SURROUND_OUTPUT_UNKNOWN,
635             ENCODED_SURROUND_OUTPUT_AUTO,
636             ENCODED_SURROUND_OUTPUT_NEVER,
637             ENCODED_SURROUND_OUTPUT_ALWAYS,
638             ENCODED_SURROUND_OUTPUT_MANUAL
639     })
640     @Retention(RetentionPolicy.SOURCE)
641     public @interface EncodedSurroundOutputMode {}
642 
643     /**
644      * The mode for surround sound formats is unknown.
645      */
646     public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
647 
648     /**
649      * The surround sound formats are available for use if they are detected. This is the default
650      * mode.
651      */
652     public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
653 
654     /**
655      * The surround sound formats are NEVER available, even if they are detected by the hardware.
656      * Those formats will not be reported.
657      */
658     public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
659 
660     /**
661      * The surround sound formats are ALWAYS available, even if they are not detected by the
662      * hardware. Those formats will be reported as part of the HDMI output capability.
663      * Applications are then free to use either PCM or encoded output.
664      */
665     public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
666 
667     /**
668      * Surround sound formats are available according to the choice of user, even if they are not
669      * detected by the hardware. Those formats will be reported as part of the HDMI output
670      * capability. Applications are then free to use either PCM or encoded output.
671      */
672     public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
673 
674     /**
675      * @hide
676      * This list contains all the flags that can be used in internal APIs for volume
677      * related operations */
678     @IntDef(flag = true, prefix = "FLAG", value = {
679             FLAG_SHOW_UI,
680             FLAG_ALLOW_RINGER_MODES,
681             FLAG_PLAY_SOUND,
682             FLAG_REMOVE_SOUND_AND_VIBRATE,
683             FLAG_VIBRATE,
684             FLAG_FIXED_VOLUME,
685             FLAG_BLUETOOTH_ABS_VOLUME,
686             FLAG_SHOW_SILENT_HINT,
687             FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
688             FLAG_ACTIVE_MEDIA_ONLY,
689             FLAG_SHOW_UI_WARNINGS,
690             FLAG_SHOW_VIBRATE_HINT,
691             FLAG_FROM_KEY,
692             FLAG_ABSOLUTE_VOLUME,
693     })
694     @Retention(RetentionPolicy.SOURCE)
695     // TODO(308698465) remove due to potential conflict with the new flags class
696     public @interface Flags {}
697 
698     /**
699      * @hide
700      * This list contains all the flags that can be used in SDK-visible methods for volume
701      * related operations.
702      * See for instance {@link #adjustVolume(int, int)},
703      * {@link #adjustStreamVolume(int, int, int)},
704      * {@link #adjustSuggestedStreamVolume(int, int, int)},
705      * {@link #adjustVolumeGroupVolume(int, int, int)},
706      * {@link #setStreamVolume(int, int, int)}
707      * The list contains all volume flags, but the values commented out of the list are there for
708      * maintenance reasons (for when adding flags or changing their visibility),
709      * and to document why some are not in the list (hidden or SystemApi). */
710     @IntDef(flag = true, prefix = "FLAG", value = {
711             FLAG_SHOW_UI,
712             FLAG_ALLOW_RINGER_MODES,
713             FLAG_PLAY_SOUND,
714             FLAG_REMOVE_SOUND_AND_VIBRATE,
715             FLAG_VIBRATE,
716             //FLAG_FIXED_VOLUME,             removed due to @hide
717             //FLAG_BLUETOOTH_ABS_VOLUME,     removed due to @SystemApi
718             //FLAG_SHOW_SILENT_HINT,         removed due to @hide
719             //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
720             //FLAG_ACTIVE_MEDIA_ONLY,        removed due to @hide
721             //FLAG_SHOW_UI_WARNINGS,         removed due to @hide
722             //FLAG_SHOW_VIBRATE_HINT,        removed due to @hide
723             //FLAG_FROM_KEY,                 removed due to @SystemApi
724             //FLAG_ABSOLUTE_VOLUME,          removed due to @hide
725     })
726     @Retention(RetentionPolicy.SOURCE)
727     public @interface PublicVolumeFlags {}
728 
729     /**
730      * @hide
731      * Like PublicVolumeFlags, but for all the flags that can be used in @SystemApi methods for
732      * volume related operations.
733      * See for instance {@link #setVolumeIndexForAttributes(AudioAttributes, int, int)},
734      * {@link #setVolumeGroupVolumeIndex(int, int, int)},
735      * {@link #setStreamVolumeForUid(int, int, int, String, int, int, int)},
736      * {@link #adjustStreamVolumeForUid(int, int, int, String, int, int, int)},
737      * {@link #adjustSuggestedStreamVolumeForUid(int, int, int, String, int, int, int)}
738      * The list contains all volume flags, but the values commented out of the list are there for
739      * maintenance reasons (for when adding flags or changing their visibility),
740      * and to document which hidden values are not in the list. */
741     @IntDef(flag = true, prefix = "FLAG", value = {
742             FLAG_SHOW_UI,
743             FLAG_ALLOW_RINGER_MODES,
744             FLAG_PLAY_SOUND,
745             FLAG_REMOVE_SOUND_AND_VIBRATE,
746             FLAG_VIBRATE,
747             //FLAG_FIXED_VOLUME,             removed due to @hide
748             FLAG_BLUETOOTH_ABS_VOLUME,
749             //FLAG_SHOW_SILENT_HINT,         removed due to @hide
750             //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
751             //FLAG_ACTIVE_MEDIA_ONLY,        removed due to @hide
752             //FLAG_SHOW_UI_WARNINGS,         removed due to @hide
753             //FLAG_SHOW_VIBRATE_HINT,        removed due to @hide
754             FLAG_FROM_KEY,
755             //FLAG_ABSOLUTE_VOLUME,          removed due to @hide
756     })
757     @Retention(RetentionPolicy.SOURCE)
758     public @interface SystemVolumeFlags {}
759 
760     // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
761     private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
762 
763     static {
FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI")764         FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES")765         FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND")766         FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE")767         FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE")768         FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME")769         FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME")770         FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT")771         FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME")772         FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY")773         FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS")774         FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT")775         FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY")776         FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME")777         FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME");
778     }
779 
780     /** @hide */
flagsToString(int flags)781     public static String flagsToString(int flags) {
782         final StringBuilder sb = new StringBuilder();
783         for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
784             final int flag = entry.getKey();
785             if ((flags & flag) != 0) {
786                 if (sb.length() > 0) {
787                     sb.append(',');
788                 }
789                 sb.append(entry.getValue());
790                 flags &= ~flag;
791             }
792         }
793         if (flags != 0) {
794             if (sb.length() > 0) {
795                 sb.append(',');
796             }
797             sb.append(flags);
798         }
799         return sb.toString();
800     }
801 
802     /**
803      * Ringer mode that will be silent and will not vibrate. (This overrides the
804      * vibrate setting.)
805      *
806      * @see #setRingerMode(int)
807      * @see #getRingerMode()
808      */
809     public static final int RINGER_MODE_SILENT = 0;
810 
811     /**
812      * Ringer mode that will be silent and will vibrate. (This will cause the
813      * phone ringer to always vibrate, but the notification vibrate to only
814      * vibrate if set.)
815      *
816      * @see #setRingerMode(int)
817      * @see #getRingerMode()
818      */
819     public static final int RINGER_MODE_VIBRATE = 1;
820 
821     /**
822      * Ringer mode that may be audible and may vibrate. It will be audible if
823      * the volume before changing out of this mode was audible. It will vibrate
824      * if the vibrate setting is on.
825      *
826      * @see #setRingerMode(int)
827      * @see #getRingerMode()
828      */
829     public static final int RINGER_MODE_NORMAL = 2;
830 
831     /**
832      * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
833      * @hide
834      */
835     public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
836 
837     /**
838      * Vibrate type that corresponds to the ringer.
839      *
840      * @see #setVibrateSetting(int, int)
841      * @see #getVibrateSetting(int)
842      * @see #shouldVibrate(int)
843      * @deprecated Applications should maintain their own vibrate policy based on
844      * current ringer mode that can be queried via {@link #getRingerMode()}.
845      */
846     public static final int VIBRATE_TYPE_RINGER = 0;
847 
848     /**
849      * Vibrate type that corresponds to notifications.
850      *
851      * @see #setVibrateSetting(int, int)
852      * @see #getVibrateSetting(int)
853      * @see #shouldVibrate(int)
854      * @deprecated Applications should maintain their own vibrate policy based on
855      * current ringer mode that can be queried via {@link #getRingerMode()}.
856      */
857     public static final int VIBRATE_TYPE_NOTIFICATION = 1;
858 
859     /**
860      * Vibrate setting that suggests to never vibrate.
861      *
862      * @see #setVibrateSetting(int, int)
863      * @see #getVibrateSetting(int)
864      * @deprecated Applications should maintain their own vibrate policy based on
865      * current ringer mode that can be queried via {@link #getRingerMode()}.
866      */
867     public static final int VIBRATE_SETTING_OFF = 0;
868 
869     /**
870      * Vibrate setting that suggests to vibrate when possible.
871      *
872      * @see #setVibrateSetting(int, int)
873      * @see #getVibrateSetting(int)
874      * @deprecated Applications should maintain their own vibrate policy based on
875      * current ringer mode that can be queried via {@link #getRingerMode()}.
876      */
877     public static final int VIBRATE_SETTING_ON = 1;
878 
879     /**
880      * Vibrate setting that suggests to only vibrate when in the vibrate ringer
881      * mode.
882      *
883      * @see #setVibrateSetting(int, int)
884      * @see #getVibrateSetting(int)
885      * @deprecated Applications should maintain their own vibrate policy based on
886      * current ringer mode that can be queried via {@link #getRingerMode()}.
887      */
888     public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
889 
890     /**
891      * Suggests using the default stream type. This may not be used in all
892      * places a stream type is needed.
893      */
894     public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
895 
896     private static IAudioService sService;
897 
898     /**
899      * @hide
900      * For test purposes only, will throw NPE with some methods that require a Context.
901      */
902     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
AudioManager()903     public AudioManager() {
904     }
905 
906     /**
907      * @hide
908      */
909     @UnsupportedAppUsage
AudioManager(Context context)910     public AudioManager(Context context) {
911         setContext(context);
912         initPlatform();
913     }
914 
getContext()915     private Context getContext() {
916         if (mApplicationContext == null) {
917             setContext(mOriginalContext);
918         }
919         if (mApplicationContext != null) {
920             return mApplicationContext;
921         }
922         return mOriginalContext;
923     }
924 
setContext(Context context)925     private void setContext(Context context) {
926         if (context == null) {
927             return;
928         }
929         mOriginalContextDeviceId = context.getDeviceId();
930         mApplicationContext = context.getApplicationContext();
931         if (mApplicationContext != null) {
932             mOriginalContext = null;
933         } else {
934             mOriginalContext = context;
935         }
936         sContext = new WeakReference<>(context);
937     }
938 
939     @UnsupportedAppUsage
getService()940     static IAudioService getService()
941     {
942         if (sService != null) {
943             return sService;
944         }
945         IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
946         sService = IAudioService.Stub.asInterface(b);
947         return sService;
948     }
949 
getVirtualDeviceManager()950     private VirtualDeviceManager getVirtualDeviceManager() {
951         if (mVirtualDeviceManager != null) {
952             return mVirtualDeviceManager;
953         }
954         mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class);
955         return mVirtualDeviceManager;
956     }
957 
958     /**
959      * Sends a simulated key event for a media button. To simulate a key press, you must first send
960      * a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then another event with the
961      * {@link KeyEvent#ACTION_UP} action.
962      *
963      * <p>The key event will be sent to the current media key event consumer which registered with
964      * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
965      *
966      * @param keyEvent a media session {@link KeyEvent}, as defined by {@link
967      *     KeyEvent#isMediaSessionKey}.
968      */
dispatchMediaKeyEvent(KeyEvent keyEvent)969     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
970         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
971         helper.sendMediaButtonEvent(keyEvent, false);
972     }
973 
974     /**
975      * @hide
976      */
preDispatchKeyEvent(KeyEvent event, int stream)977     public void preDispatchKeyEvent(KeyEvent event, int stream) {
978         /*
979          * If the user hits another key within the play sound delay, then
980          * cancel the sound
981          */
982         int keyCode = event.getKeyCode();
983         if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
984                 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
985                 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
986             /*
987              * The user has hit another key during the delay (e.g., 300ms)
988              * since the last volume key up, so cancel any sounds.
989              */
990             adjustSuggestedStreamVolume(ADJUST_SAME,
991                     stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
992         }
993     }
994 
995     /**
996      * Indicates if the device implements a fixed volume policy.
997      * <p>Some devices may not have volume control and may operate at a fixed volume,
998      * and may not enable muting or changing the volume of audio streams.
999      * This method will return true on such devices.
1000      * <p>The following APIs have no effect when volume is fixed:
1001      * <ul>
1002      *   <li> {@link #adjustVolume(int, int)}
1003      *   <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
1004      *   <li> {@link #adjustStreamVolume(int, int, int)}
1005      *   <li> {@link #setStreamVolume(int, int, int)}
1006      *   <li> {@link #setRingerMode(int)}
1007      *   <li> {@link #setStreamSolo(int, boolean)}
1008      *   <li> {@link #setStreamMute(int, boolean)}
1009      * </ul>
1010      */
isVolumeFixed()1011     public boolean isVolumeFixed() {
1012         boolean res = false;
1013         try {
1014             res = getService().isVolumeFixed();
1015         } catch (RemoteException e) {
1016             Log.e(TAG, "Error querying isVolumeFixed", e);
1017         }
1018         return res;
1019     }
1020 
1021     /**
1022      * Adjusts the volume of a particular stream by one step in a direction.
1023      * <p>
1024      * This method should only be used by applications that replace the platform-wide
1025      * management of audio settings or the main telephony application.
1026      * <p>This method has no effect if the device implements a fixed volume policy
1027      * as indicated by {@link #isVolumeFixed()}.
1028      * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1029      * unless the app has been granted Do Not Disturb Access.
1030      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
1031      *
1032      * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
1033      * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
1034      * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
1035      * @param direction The direction to adjust the volume. One of
1036      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1037      *            {@link #ADJUST_SAME}.
1038      * @param flags
1039      * @see #adjustVolume(int, int)
1040      * @see #setStreamVolume(int, int, int)
1041      * @throws SecurityException if the adjustment triggers a Do Not Disturb change
1042      *   and the caller is not granted notification policy access.
1043      */
adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags)1044     public void adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags) {
1045         final IAudioService service = getService();
1046         try {
1047             service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
1048                     getContext().getOpPackageName(), getContext().getAttributionTag());
1049         } catch (RemoteException e) {
1050             throw e.rethrowFromSystemServer();
1051         }
1052     }
1053 
1054     /**
1055      * Adjusts the volume of the most relevant stream. For example, if a call is
1056      * active, it will have the highest priority regardless of if the in-call
1057      * screen is showing. Another example, if music is playing in the background
1058      * and a call is not active, the music stream will be adjusted.
1059      * <p>
1060      * This method should only be used by applications that replace the
1061      * platform-wide management of audio settings or the main telephony
1062      * application.
1063      * <p>
1064      * This method has no effect if the device implements a fixed volume policy
1065      * as indicated by {@link #isVolumeFixed()}.
1066      *
1067      * @param direction The direction to adjust the volume. One of
1068      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1069      *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1070      *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
1071      * @param flags
1072      * @see #adjustSuggestedStreamVolume(int, int, int)
1073      * @see #adjustStreamVolume(int, int, int)
1074      * @see #setStreamVolume(int, int, int)
1075      * @see #isVolumeFixed()
1076      */
adjustVolume(int direction, @PublicVolumeFlags int flags)1077     public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
1078         if (applyAutoHardening()) {
1079             final IAudioService service = getService();
1080             try {
1081                 service.adjustVolume(direction, flags);
1082             } catch (RemoteException e) {
1083                 throw e.rethrowFromSystemServer();
1084             }
1085         } else {
1086             MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
1087             helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
1088         }
1089     }
1090 
1091     /**
1092      * Adjusts the volume of the most relevant stream, or the given fallback
1093      * stream.
1094      * <p>
1095      * This method should only be used by applications that replace the
1096      * platform-wide management of audio settings or the main telephony
1097      * application.
1098      * <p>
1099      * This method has no effect if the device implements a fixed volume policy
1100      * as indicated by {@link #isVolumeFixed()}.
1101      *
1102      * @param direction The direction to adjust the volume. One of
1103      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
1104      *            {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
1105      *            {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
1106      * @param suggestedStreamType The stream type that will be used if there
1107      *            isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
1108      *            valid here.
1109      * @param flags
1110      * @see #adjustVolume(int, int)
1111      * @see #adjustStreamVolume(int, int, int)
1112      * @see #setStreamVolume(int, int, int)
1113      * @see #isVolumeFixed()
1114      */
adjustSuggestedStreamVolume(int direction, int suggestedStreamType, @PublicVolumeFlags int flags)1115     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
1116             @PublicVolumeFlags int flags) {
1117         if (applyAutoHardening()) {
1118             final IAudioService service = getService();
1119             try {
1120                 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
1121             } catch (RemoteException e) {
1122                 throw e.rethrowFromSystemServer();
1123             }
1124         } else {
1125             MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
1126             helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
1127         }
1128     }
1129 
1130     /** @hide */
1131     @UnsupportedAppUsage
1132     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setMasterMute(boolean mute, int flags)1133     public void setMasterMute(boolean mute, int flags) {
1134         final IAudioService service = getService();
1135         try {
1136             service.setMasterMute(mute, flags, getContext().getOpPackageName(),
1137                     UserHandle.getCallingUserId(), getContext().getAttributionTag());
1138         } catch (RemoteException e) {
1139             throw e.rethrowFromSystemServer();
1140         }
1141     }
1142 
1143     /**
1144      * Returns the current ringtone mode.
1145      *
1146      * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1147      *         {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1148      * @see #setRingerMode(int)
1149      */
getRingerMode()1150     public int getRingerMode() {
1151         final IAudioService service = getService();
1152         try {
1153             return service.getRingerModeExternal();
1154         } catch (RemoteException e) {
1155             throw e.rethrowFromSystemServer();
1156         }
1157     }
1158 
1159     /**
1160      * Returns the current user setting for ramping ringer on incoming phone call ringtone.
1161      *
1162      * @return true if the incoming phone call ringtone is configured to gradually increase its
1163      * volume, false otherwise.
1164      */
isRampingRingerEnabled()1165     public boolean isRampingRingerEnabled() {
1166         return Settings.System.getInt(getContext().getContentResolver(),
1167                 Settings.System.APPLY_RAMPING_RINGER, 0) != 0;
1168     }
1169 
1170     /**
1171      * Sets the flag for enabling ramping ringer on incoming phone call ringtone.
1172      *
1173      * @see #isRampingRingerEnabled()
1174      * @hide
1175      */
1176     @TestApi
setRampingRingerEnabled(boolean enabled)1177     public void setRampingRingerEnabled(boolean enabled) {
1178         Settings.System.putInt(getContext().getContentResolver(),
1179                 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0);
1180     }
1181 
1182     /**
1183      * Checks valid ringer mode values.
1184      *
1185      * @return true if the ringer mode indicated is valid, false otherwise.
1186      *
1187      * @see #setRingerMode(int)
1188      * @hide
1189      */
1190     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isValidRingerMode(int ringerMode)1191     public static boolean isValidRingerMode(int ringerMode) {
1192         if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1193             return false;
1194         }
1195         final IAudioService service = getService();
1196         try {
1197             return service.isValidRingerMode(ringerMode);
1198         } catch (RemoteException e) {
1199             throw e.rethrowFromSystemServer();
1200         }
1201     }
1202 
1203     /**
1204      * Returns the maximum volume index for a particular stream.
1205      *
1206      * @param streamType The stream type whose maximum volume index is returned.
1207      * @return The maximum valid volume index for the stream.
1208      * @see #getStreamVolume(int)
1209      */
getStreamMaxVolume(int streamType)1210     public int getStreamMaxVolume(int streamType) {
1211         final IAudioService service = getService();
1212         try {
1213             return service.getStreamMaxVolume(streamType);
1214         } catch (RemoteException e) {
1215             throw e.rethrowFromSystemServer();
1216         }
1217     }
1218 
1219     /**
1220      * Returns the minimum volume index for a particular stream.
1221      * @param streamType The stream type whose minimum volume index is returned. Must be one of
1222      *     {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1223      *     {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1224      *     {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1225      * @return The minimum valid volume index for the stream.
1226      * @see #getStreamVolume(int)
1227      */
getStreamMinVolume(int streamType)1228     public int getStreamMinVolume(int streamType) {
1229         if (!isPublicStreamType(streamType)) {
1230             throw new IllegalArgumentException("Invalid stream type " + streamType);
1231         }
1232         return getStreamMinVolumeInt(streamType);
1233     }
1234 
1235     /**
1236      * @hide
1237      * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
1238      * @param streamType The stream type whose minimum volume index is returned.
1239      * @return The minimum valid volume index for the stream.
1240      * @see #getStreamVolume(int)
1241      */
1242     @TestApi
getStreamMinVolumeInt(int streamType)1243     public int getStreamMinVolumeInt(int streamType) {
1244         final IAudioService service = getService();
1245         try {
1246             return service.getStreamMinVolume(streamType);
1247         } catch (RemoteException e) {
1248             throw e.rethrowFromSystemServer();
1249         }
1250     }
1251 
1252     /**
1253      * Returns the current volume index for a particular stream.
1254      *
1255      * @param streamType The stream type whose volume index is returned.
1256      * @return The current volume index for the stream.
1257      * @see #getStreamMaxVolume(int)
1258      * @see #setStreamVolume(int, int, int)
1259      */
getStreamVolume(int streamType)1260     public int getStreamVolume(int streamType) {
1261         final IAudioService service = getService();
1262         try {
1263             return service.getStreamVolume(streamType);
1264         } catch (RemoteException e) {
1265             throw e.rethrowFromSystemServer();
1266         }
1267     }
1268 
1269     // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1270     private static final float VOLUME_MIN_DB = -758.0f;
1271 
1272     /** @hide */
1273     @IntDef(flag = false, prefix = "STREAM", value = {
1274             STREAM_VOICE_CALL,
1275             STREAM_SYSTEM,
1276             STREAM_RING,
1277             STREAM_MUSIC,
1278             STREAM_ALARM,
1279             STREAM_NOTIFICATION,
1280             STREAM_DTMF,
1281             STREAM_ACCESSIBILITY }
1282     )
1283     @Retention(RetentionPolicy.SOURCE)
1284     public @interface PublicStreamTypes {}
1285 
1286     /**
1287      * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1288      * the given type of audio output device.
1289      * @param streamType stream type for which the volume is queried.
1290      * @param index the volume index for which the volume is queried. The index value must be
1291      *     between the minimum and maximum index values for the given stream type (see
1292      *     {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1293      * @param deviceType the type of audio output device for which volume is queried.
1294      * @return a volume expressed in dB.
1295      *     A negative value indicates the audio signal is attenuated. A typical maximum value
1296      *     at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1297      *     reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1298      */
getStreamVolumeDb(@ublicStreamTypes int streamType, int index, @AudioDeviceInfo.AudioDeviceTypeOut int deviceType)1299     public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1300             @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1301         if (!isPublicStreamType(streamType)) {
1302             throw new IllegalArgumentException("Invalid stream type " + streamType);
1303         }
1304         if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1305             throw new IllegalArgumentException("Invalid stream volume index " + index);
1306         }
1307         if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1308             throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1309         }
1310         final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1311                 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1312         if (gain <= VOLUME_MIN_DB) {
1313             return Float.NEGATIVE_INFINITY;
1314         } else {
1315             return gain;
1316         }
1317     }
1318 
1319     /**
1320      * @hide
1321      * Checks whether a stream type is part of the public SDK
1322      * @param streamType
1323      * @return true if the stream type is available in SDK
1324      */
isPublicStreamType(int streamType)1325     public static boolean isPublicStreamType(int streamType) {
1326         switch (streamType) {
1327             case STREAM_VOICE_CALL:
1328             case STREAM_SYSTEM:
1329             case STREAM_RING:
1330             case STREAM_MUSIC:
1331             case STREAM_ALARM:
1332             case STREAM_NOTIFICATION:
1333             case STREAM_DTMF:
1334             case STREAM_ACCESSIBILITY:
1335                 return true;
1336             default:
1337                 return false;
1338         }
1339     }
1340 
1341     /**
1342      * Get last audible volume before stream was muted.
1343      *
1344      * @hide
1345      */
1346     @SystemApi
1347     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getLastAudibleStreamVolume(int streamType)1348     public int getLastAudibleStreamVolume(int streamType) {
1349         final IAudioService service = getService();
1350         try {
1351             return service.getLastAudibleStreamVolume(streamType);
1352         } catch (RemoteException e) {
1353             throw e.rethrowFromSystemServer();
1354         }
1355     }
1356 
1357     /**
1358      * Get the stream type whose volume is driving the UI sounds volume.
1359      * UI sounds are screen lock/unlock, camera shutter, key clicks...
1360      * It is assumed that this stream type is also tied to ringer mode changes.
1361      * @hide
1362      */
getUiSoundsStreamType()1363     public int getUiSoundsStreamType() {
1364         final IAudioService service = getService();
1365         try {
1366             return service.getUiSoundsStreamType();
1367         } catch (RemoteException e) {
1368             throw e.rethrowFromSystemServer();
1369         }
1370     }
1371 
1372     /**
1373      * Sets the ringer mode.
1374      * <p>
1375      * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1376      * mute the volume and vibrate. Normal mode will be audible and may vibrate
1377      * according to user settings.
1378      * <p>This method has no effect if the device implements a fixed volume policy
1379      * as indicated by {@link #isVolumeFixed()}.
1380      * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1381      * unless the app has been granted Do Not Disturb Access.
1382      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
1383      * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1384      *            {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1385      * @see #getRingerMode()
1386      * @see #isVolumeFixed()
1387      */
setRingerMode(int ringerMode)1388     public void setRingerMode(int ringerMode) {
1389         if (!isValidRingerMode(ringerMode)) {
1390             return;
1391         }
1392         final IAudioService service = getService();
1393         try {
1394             service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
1395         } catch (RemoteException e) {
1396             throw e.rethrowFromSystemServer();
1397         }
1398     }
1399 
1400     /**
1401      * Sets the volume index for a particular stream.
1402      * <p>This method has no effect if the device implements a fixed volume policy
1403      * as indicated by {@link #isVolumeFixed()}.
1404      * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1405      * the app has been granted Do Not Disturb Access.
1406      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
1407      * @param streamType The stream whose volume index should be set.
1408      * @param index The volume index to set. See
1409      *            {@link #getStreamMaxVolume(int)} for the largest valid value.
1410      * @param flags
1411      * @see #getStreamMaxVolume(int)
1412      * @see #getStreamVolume(int)
1413      * @see #isVolumeFixed()
1414      * @throws SecurityException if the volume change triggers a Do Not Disturb change
1415      *   and the caller is not granted notification policy access.
1416      */
setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags)1417     public void setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags) {
1418         final IAudioService service = getService();
1419         try {
1420             service.setStreamVolumeWithAttribution(streamType, index, flags,
1421                     getContext().getOpPackageName(), getContext().getAttributionTag());
1422         } catch (RemoteException e) {
1423             throw e.rethrowFromSystemServer();
1424         }
1425     }
1426 
1427     /**
1428      * Sets the volume index for a particular {@link AudioAttributes}.
1429      * @param attr The {@link AudioAttributes} whose volume index should be set.
1430      * @param index The volume index to set. See
1431      *          {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1432      *          {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1433      * @param flags
1434      * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1435      * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1436      * @see #isVolumeFixed()
1437      * @hide
1438      */
1439     @SystemApi
1440     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setVolumeIndexForAttributes(@onNull AudioAttributes attr, int index, @SystemVolumeFlags int flags)1441     public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index,
1442             @SystemVolumeFlags int flags) {
1443         Preconditions.checkNotNull(attr, "attr must not be null");
1444         final IAudioService service = getService();
1445         int groupId = getVolumeGroupIdForAttributes(attr);
1446         setVolumeGroupVolumeIndex(groupId, index, flags);
1447     }
1448 
1449     /**
1450      * Returns the current volume index for a particular {@link AudioAttributes}.
1451      *
1452      * @param attr The {@link AudioAttributes} whose volume index is returned.
1453      * @return The current volume index for the stream.
1454      * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1455      * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1456      * @see #setVolumeForAttributes(AudioAttributes, int, int)
1457      * @hide
1458      */
1459     @SystemApi
1460     @IntRange(from = 0)
1461     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getVolumeIndexForAttributes(@onNull AudioAttributes attr)1462     public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1463         Preconditions.checkNotNull(attr, "attr must not be null");
1464         final IAudioService service = getService();
1465         int groupId = getVolumeGroupIdForAttributes(attr);
1466         return getVolumeGroupVolumeIndex(groupId);
1467     }
1468 
1469     /**
1470      * Returns the maximum volume index for a particular {@link AudioAttributes}.
1471      *
1472      * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1473      * @return The maximum valid volume index for the {@link AudioAttributes}.
1474      * @see #getVolumeIndexForAttributes(AudioAttributes)
1475      * @hide
1476      */
1477     @SystemApi
1478     @IntRange(from = 0)
1479     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getMaxVolumeIndexForAttributes(@onNull AudioAttributes attr)1480     public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1481         Preconditions.checkNotNull(attr, "attr must not be null");
1482         final IAudioService service = getService();
1483         int groupId = getVolumeGroupIdForAttributes(attr);
1484         return getVolumeGroupMaxVolumeIndex(groupId);
1485     }
1486 
1487     /**
1488      * Returns the minimum volume index for a particular {@link AudioAttributes}.
1489      *
1490      * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1491      * @return The minimum valid volume index for the {@link AudioAttributes}.
1492      * @see #getVolumeIndexForAttributes(AudioAttributes)
1493      * @hide
1494      */
1495     @SystemApi
1496     @IntRange(from = 0)
1497     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getMinVolumeIndexForAttributes(@onNull AudioAttributes attr)1498     public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1499         Preconditions.checkNotNull(attr, "attr must not be null");
1500         final IAudioService service = getService();
1501         int groupId = getVolumeGroupIdForAttributes(attr);
1502         return getVolumeGroupMinVolumeIndex(groupId);
1503     }
1504 
1505     /**
1506      * Returns the volume group id associated to the given {@link AudioAttributes}.
1507      *
1508      * @param attributes The {@link AudioAttributes} to consider.
1509      * @return audio volume group id supporting the given {@link AudioAttributes} if found,
1510      * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise.
1511      */
getVolumeGroupIdForAttributes(@onNull AudioAttributes attributes)1512     public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) {
1513         Preconditions.checkNotNull(attributes, "Audio Attributes must not be null");
1514         return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes,
1515                 /* fallbackOnDefault= */ true);
1516     }
1517 
1518     /**
1519      * Sets the volume index for a particular group associated to given id.
1520      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1521      * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1522      *
1523      * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1524      * @param index The volume index to set. See
1525      *          {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
1526      *          {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
1527      * @param flags
1528      * @hide
1529      */
1530     @SystemApi
1531     @RequiresPermission(anyOf = {
1532             android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
1533             android.Manifest.permission.MODIFY_AUDIO_ROUTING
1534     })
setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags)1535     public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) {
1536         final IAudioService service = getService();
1537         try {
1538             service.setVolumeGroupVolumeIndex(groupId, index, flags,
1539                     getContext().getOpPackageName(), getContext().getAttributionTag());
1540         } catch (RemoteException e) {
1541             throw e.rethrowFromSystemServer();
1542         }
1543     }
1544 
1545     /**
1546      * Returns the current volume index for a particular group associated to given id.
1547      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1548      * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1549      *
1550      * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1551      * @return The current volume index for the stream.
1552      * @hide
1553      */
1554     @SystemApi
1555     @IntRange(from = 0)
1556     @RequiresPermission(anyOf = {
1557             android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
1558             android.Manifest.permission.MODIFY_AUDIO_ROUTING
1559     })
getVolumeGroupVolumeIndex(int groupId)1560     public int getVolumeGroupVolumeIndex(int groupId) {
1561         final IAudioService service = getService();
1562         try {
1563             return service.getVolumeGroupVolumeIndex(groupId);
1564         } catch (RemoteException e) {
1565             throw e.rethrowFromSystemServer();
1566         }
1567     }
1568 
1569     /**
1570      * Returns the maximum volume index for a particular group associated to given id.
1571      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1572      * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1573      *
1574      * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1575      * @return The maximum valid volume index for the {@link AudioAttributes}.
1576      * @hide
1577      */
1578     @SystemApi
1579     @IntRange(from = 0)
1580     @RequiresPermission(anyOf = {
1581             android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
1582             android.Manifest.permission.MODIFY_AUDIO_ROUTING
1583     })
getVolumeGroupMaxVolumeIndex(int groupId)1584     public int getVolumeGroupMaxVolumeIndex(int groupId) {
1585         final IAudioService service = getService();
1586         try {
1587             return service.getVolumeGroupMaxVolumeIndex(groupId);
1588         } catch (RemoteException e) {
1589             throw e.rethrowFromSystemServer();
1590         }
1591     }
1592 
1593     /**
1594      * Returns the minimum volume index for a particular group associated to given id.
1595      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)}
1596      * to retrieve the volume group id supporting the given {@link AudioAttributes}.
1597      *
1598      * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1599      * @return The minimum valid volume index for the {@link AudioAttributes}.
1600      * @hide
1601      */
1602     @SystemApi
1603     @IntRange(from = 0)
1604     @RequiresPermission(anyOf = {
1605             android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
1606             android.Manifest.permission.MODIFY_AUDIO_ROUTING
1607     })
getVolumeGroupMinVolumeIndex(int groupId)1608     public int getVolumeGroupMinVolumeIndex(int groupId) {
1609         final IAudioService service = getService();
1610         try {
1611             return service.getVolumeGroupMinVolumeIndex(groupId);
1612         } catch (RemoteException e) {
1613             throw e.rethrowFromSystemServer();
1614         }
1615     }
1616 
1617     /**
1618      * Adjusts the volume of a particular group associated to given id by one step in a direction.
1619      * <p> If the volume group is associated to a stream type, it fallbacks on
1620      * {@link #adjustStreamVolume(int, int, int)} for compatibility reason.
1621      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1622      * the volume group id supporting the given {@link AudioAttributes}.
1623      *
1624      * @param groupId of the audio volume group to consider.
1625      * @param direction The direction to adjust the volume. One of
1626      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
1627      *            {@link #ADJUST_SAME}.
1628      * @param flags
1629      * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
1630      * is not granted notification policy access.
1631      */
adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags)1632     public void adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags) {
1633         IAudioService service = getService();
1634         try {
1635             service.adjustVolumeGroupVolume(groupId, direction, flags,
1636                     getContext().getOpPackageName());
1637         } catch (RemoteException e) {
1638             throw e.rethrowFromSystemServer();
1639         }
1640     }
1641 
1642     /**
1643      * Get last audible volume of the group associated to given id before it was muted.
1644      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1645      * the volume group id supporting the given {@link AudioAttributes}.
1646      *
1647      * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider.
1648      * @return current volume if not muted, volume before muted otherwise.
1649      * @hide
1650      */
1651     @SystemApi
1652     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
1653     @IntRange(from = 0)
getLastAudibleVolumeForVolumeGroup(int groupId)1654     public int getLastAudibleVolumeForVolumeGroup(int groupId) {
1655         IAudioService service = getService();
1656         try {
1657             return service.getLastAudibleVolumeForVolumeGroup(groupId);
1658         } catch (RemoteException e) {
1659             throw e.rethrowFromSystemServer();
1660         }
1661     }
1662 
1663     /**
1664      * Returns the current mute state for a particular volume group associated to the given id.
1665      * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve
1666      * the volume group id supporting the given {@link AudioAttributes}.
1667      *
1668      * @param groupId of the audio volume group to consider.
1669      * @return The mute state for the given audio volume group id.
1670      * @see #adjustVolumeGroupVolume(int, int, int)
1671      */
isVolumeGroupMuted(int groupId)1672     public boolean isVolumeGroupMuted(int groupId) {
1673         IAudioService service = getService();
1674         try {
1675             return service.isVolumeGroupMuted(groupId);
1676         } catch (RemoteException e) {
1677             throw e.rethrowFromSystemServer();
1678         }
1679     }
1680 
1681     /**
1682      * Set the system usages to be supported on this device.
1683      * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1684      * @hide
1685      */
1686     @SystemApi
1687     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setSupportedSystemUsages(@onNull @ttributeSystemUsage int[] systemUsages)1688     public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1689         Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1690         final IAudioService service = getService();
1691         try {
1692             service.setSupportedSystemUsages(systemUsages);
1693         } catch (RemoteException e) {
1694             throw e.rethrowFromSystemServer();
1695         }
1696     }
1697 
1698     /**
1699      * Get the system usages supported on this device.
1700      * @return array of supported system usages {@link AttributeSystemUsage}
1701      * @hide
1702      */
1703     @SystemApi
1704     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getSupportedSystemUsages()1705     public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1706         final IAudioService service = getService();
1707         try {
1708             return service.getSupportedSystemUsages();
1709         } catch (RemoteException e) {
1710             throw e.rethrowFromSystemServer();
1711         }
1712     }
1713 
1714     /**
1715      * Solo or unsolo a particular stream.
1716      * <p>
1717      * Do not use. This method has been deprecated and is now a no-op.
1718      * {@link #requestAudioFocus} should be used for exclusive audio playback.
1719      *
1720      * @param streamType The stream to be soloed/unsoloed.
1721      * @param state The required solo state: true for solo ON, false for solo
1722      *            OFF
1723      * @see #isVolumeFixed()
1724      * @deprecated Do not use. If you need exclusive audio playback use
1725      *             {@link #requestAudioFocus}.
1726      */
1727     @Deprecated
setStreamSolo(int streamType, boolean state)1728     public void setStreamSolo(int streamType, boolean state) {
1729         Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
1730     }
1731 
1732     /**
1733      * Mute or unmute an audio stream.
1734      * <p>
1735      * This method should only be used by applications that replace the
1736      * platform-wide management of audio settings or the main telephony
1737      * application.
1738      * <p>
1739      * This method has no effect if the device implements a fixed volume policy
1740      * as indicated by {@link #isVolumeFixed()}.
1741      * <p>
1742      * This method was deprecated in API level 22. Prior to API level 22 this
1743      * method had significantly different behavior and should be used carefully.
1744      * The following applies only to pre-22 platforms:
1745      * <ul>
1746      * <li>The mute command is protected against client process death: if a
1747      * process with an active mute request on a stream dies, this stream will be
1748      * unmuted automatically.</li>
1749      * <li>The mute requests for a given stream are cumulative: the AudioManager
1750      * can receive several mute requests from one or more clients and the stream
1751      * will be unmuted only when the same number of unmute requests are
1752      * received.</li>
1753      * <li>For a better user experience, applications MUST unmute a muted stream
1754      * in onPause() and mute is again in onResume() if appropriate.</li>
1755      * </ul>
1756      *
1757      * @param streamType The stream to be muted/unmuted.
1758      * @param state The required mute state: true for mute ON, false for mute
1759      *            OFF
1760      * @see #isVolumeFixed()
1761      * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1762      *             {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
1763      */
1764     @Deprecated
setStreamMute(int streamType, boolean state)1765     public void setStreamMute(int streamType, boolean state) {
1766         Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1767         int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1768         if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1769             adjustSuggestedStreamVolume(direction, streamType, 0);
1770         } else {
1771             adjustStreamVolume(streamType, direction, 0);
1772         }
1773     }
1774 
1775     /**
1776      * Returns the current mute state for a particular stream.
1777      *
1778      * @param streamType The stream to get mute state for.
1779      * @return The mute state for the given stream.
1780      * @see #adjustStreamVolume(int, int, int)
1781      */
isStreamMute(int streamType)1782     public boolean isStreamMute(int streamType) {
1783         final IAudioService service = getService();
1784         try {
1785             return service.isStreamMute(streamType);
1786         } catch (RemoteException e) {
1787             throw e.rethrowFromSystemServer();
1788         }
1789     }
1790 
1791     /**
1792      * get master mute state.
1793      *
1794      * @hide
1795      */
1796     @UnsupportedAppUsage
isMasterMute()1797     public boolean isMasterMute() {
1798         final IAudioService service = getService();
1799         try {
1800             return service.isMasterMute();
1801         } catch (RemoteException e) {
1802             throw e.rethrowFromSystemServer();
1803         }
1804     }
1805 
1806     /**
1807      * forces the stream controlled by hard volume keys
1808      * specifying streamType == -1 releases control to the
1809      * logic.
1810      *
1811      * @hide
1812      */
1813     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
1814     @UnsupportedAppUsage
forceVolumeControlStream(int streamType)1815     public void forceVolumeControlStream(int streamType) {
1816         final IAudioService service = getService();
1817         try {
1818             service.forceVolumeControlStream(streamType, mICallBack);
1819         } catch (RemoteException e) {
1820             throw e.rethrowFromSystemServer();
1821         }
1822     }
1823 
1824     /**
1825      * Returns whether a particular type should vibrate according to user
1826      * settings and the current ringer mode.
1827      * <p>
1828      * This shouldn't be needed by most clients that use notifications to
1829      * vibrate. The notification manager will not vibrate if the policy doesn't
1830      * allow it, so the client should always set a vibrate pattern and let the
1831      * notification manager control whether or not to actually vibrate.
1832      *
1833      * @param vibrateType The type of vibrate. One of
1834      *            {@link #VIBRATE_TYPE_NOTIFICATION} or
1835      *            {@link #VIBRATE_TYPE_RINGER}.
1836      * @return Whether the type should vibrate at the instant this method is
1837      *         called.
1838      * @see #setVibrateSetting(int, int)
1839      * @see #getVibrateSetting(int)
1840      * @deprecated Applications should maintain their own vibrate policy based on
1841      * current ringer mode that can be queried via {@link #getRingerMode()}.
1842      */
shouldVibrate(int vibrateType)1843     public boolean shouldVibrate(int vibrateType) {
1844         final IAudioService service = getService();
1845         try {
1846             return service.shouldVibrate(vibrateType);
1847         } catch (RemoteException e) {
1848             throw e.rethrowFromSystemServer();
1849         }
1850     }
1851 
1852     /**
1853      * Returns whether the user's vibrate setting for a vibrate type.
1854      * <p>
1855      * This shouldn't be needed by most clients that want to vibrate, instead
1856      * see {@link #shouldVibrate(int)}.
1857      *
1858      * @param vibrateType The type of vibrate. One of
1859      *            {@link #VIBRATE_TYPE_NOTIFICATION} or
1860      *            {@link #VIBRATE_TYPE_RINGER}.
1861      * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1862      *         {@link #VIBRATE_SETTING_OFF}, or
1863      *         {@link #VIBRATE_SETTING_ONLY_SILENT}.
1864      * @see #setVibrateSetting(int, int)
1865      * @see #shouldVibrate(int)
1866      * @deprecated Applications should maintain their own vibrate policy based on
1867      * current ringer mode that can be queried via {@link #getRingerMode()}.
1868      */
getVibrateSetting(int vibrateType)1869     public int getVibrateSetting(int vibrateType) {
1870         final IAudioService service = getService();
1871         try {
1872             return service.getVibrateSetting(vibrateType);
1873         } catch (RemoteException e) {
1874             throw e.rethrowFromSystemServer();
1875         }
1876     }
1877 
1878     /**
1879      * Sets the setting for when the vibrate type should vibrate.
1880      * <p>
1881      * This method should only be used by applications that replace the platform-wide
1882      * management of audio settings or the main telephony application.
1883      *
1884      * @param vibrateType The type of vibrate. One of
1885      *            {@link #VIBRATE_TYPE_NOTIFICATION} or
1886      *            {@link #VIBRATE_TYPE_RINGER}.
1887      * @param vibrateSetting The vibrate setting, one of
1888      *            {@link #VIBRATE_SETTING_ON},
1889      *            {@link #VIBRATE_SETTING_OFF}, or
1890      *            {@link #VIBRATE_SETTING_ONLY_SILENT}.
1891      * @see #getVibrateSetting(int)
1892      * @see #shouldVibrate(int)
1893      * @deprecated Applications should maintain their own vibrate policy based on
1894      * current ringer mode that can be queried via {@link #getRingerMode()}.
1895      */
setVibrateSetting(int vibrateType, int vibrateSetting)1896     public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1897         final IAudioService service = getService();
1898         try {
1899             service.setVibrateSetting(vibrateType, vibrateSetting);
1900         } catch (RemoteException e) {
1901             throw e.rethrowFromSystemServer();
1902         }
1903     }
1904 
1905     /**
1906      * Sets the speakerphone on or off.
1907      * <p>
1908      * This method should only be used by applications that replace the platform-wide
1909      * management of audio settings or the main telephony application.
1910      *
1911      * @param on set <var>true</var> to turn on speakerphone;
1912      *           <var>false</var> to turn it off
1913      * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or
1914      *           {@link AudioManager#clearCommunicationDevice()} instead.
1915      */
setSpeakerphoneOn(boolean on)1916     @Deprecated public void setSpeakerphoneOn(boolean on) {
1917         final IAudioService service = getService();
1918         try {
1919             service.setSpeakerphoneOn(mICallBack, on);
1920         } catch (RemoteException e) {
1921             throw e.rethrowFromSystemServer();
1922         }
1923     }
1924 
1925     /**
1926      * Checks whether the speakerphone is on or off.
1927      *
1928      * @return true if speakerphone is on, false if it's off
1929      * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
1930      */
isSpeakerphoneOn()1931     @Deprecated public boolean isSpeakerphoneOn() {
1932         final IAudioService service = getService();
1933         try {
1934             return service.isSpeakerphoneOn();
1935         } catch (RemoteException e) {
1936             throw e.rethrowFromSystemServer();
1937         }
1938      }
1939 
1940     /**
1941      * Specifies whether the audio played by this app may or may not be captured by other apps or
1942      * the system.
1943      *
1944      * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1945      *
1946      * There are multiple ways to set this policy:
1947      * <ul>
1948      * <li> for each track independently, see
1949      *    {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1950      * <li> application-wide at runtime, with this method </li>
1951      * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1952      *       manifest. </li>
1953      * </ul>
1954      * The most restrictive policy is always applied.
1955      *
1956      * See {@link AudioPlaybackCaptureConfiguration} for more details on
1957      * which audio signals can be captured.
1958      *
1959      * @param capturePolicy one of
1960      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1961      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1962      *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
1963      * @throws RuntimeException if the argument is not a valid value.
1964      */
setAllowedCapturePolicy(@udioAttributes.CapturePolicy int capturePolicy)1965     public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
1966         // TODO: also pass the package in case multiple packages have the same UID
1967         final IAudioService service = getService();
1968         try {
1969             int result = service.setAllowedCapturePolicy(capturePolicy);
1970             if (result != AudioSystem.AUDIO_STATUS_OK) {
1971                 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1972                 return;
1973             }
1974         } catch (RemoteException e) {
1975             throw e.rethrowFromSystemServer();
1976         }
1977     }
1978 
1979     /**
1980      * Return the capture policy.
1981      * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1982      *         the default if it was not called.
1983      */
1984     @AudioAttributes.CapturePolicy
getAllowedCapturePolicy()1985     public int getAllowedCapturePolicy() {
1986         int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1987         try {
1988             result = getService().getAllowedCapturePolicy();
1989         } catch (RemoteException e) {
1990             Log.e(TAG, "Failed to query allowed capture policy: " + e);
1991         }
1992         return result;
1993     }
1994 
1995     //====================================================================
1996     // Audio Product Strategy routing
1997 
1998     /**
1999      * @hide
2000      * Set the preferred device for a given strategy, i.e. the audio routing to be used by
2001      * this audio strategy. Note that the device may not be available at the time the preferred
2002      * device is set, but it will be used once made available.
2003      * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
2004      * this preference for this strategy.</p>
2005      * @param strategy the audio strategy whose routing will be affected
2006      * @param device the audio device to route to when available
2007      * @return true if the operation was successful, false otherwise
2008      */
2009     @SystemApi
2010     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setPreferredDeviceForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2011     public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
2012             @NonNull AudioDeviceAttributes device) {
2013         return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
2014     }
2015 
2016     /**
2017      * @hide
2018      * Removes the preferred audio device(s) previously set with
2019      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
2020      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
2021      * @param strategy the audio strategy whose routing will be affected
2022      * @return true if the operation was successful, false otherwise (invalid strategy, or no
2023      *     device set for example)
2024      */
2025     @SystemApi
2026     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removePreferredDeviceForStrategy(@onNull AudioProductStrategy strategy)2027     public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
2028         Objects.requireNonNull(strategy);
2029         try {
2030             final int status =
2031                     getService().removePreferredDevicesForStrategy(strategy.getId());
2032             return status == AudioSystem.SUCCESS;
2033         } catch (RemoteException e) {
2034             throw e.rethrowFromSystemServer();
2035         }
2036     }
2037 
2038     /**
2039      * @hide
2040      * Return the preferred device for an audio strategy, previously set with
2041      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
2042      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
2043      * @param strategy the strategy to query
2044      * @return the preferred device for that strategy, if multiple devices are set as preferred
2045      *    devices, the first one in the list will be returned. Null will be returned if none was
2046      *    ever set or if the strategy is invalid
2047      */
2048     @SystemApi
2049     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
2050     @Nullable
getPreferredDeviceForStrategy( @onNull AudioProductStrategy strategy)2051     public AudioDeviceAttributes getPreferredDeviceForStrategy(
2052             @NonNull AudioProductStrategy strategy) {
2053         List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
2054         return devices.isEmpty() ? null : devices.get(0);
2055     }
2056 
2057     /**
2058      * @hide
2059      * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
2060      * this audio strategy. Note that the devices may not be available at the time the preferred
2061      * devices is set, but it will be used once made available.
2062      * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
2063      * this preference for this strategy.</p>
2064      * Note that the list of devices is not a list ranked by preference, but a list of one or more
2065      * devices used simultaneously to output the same audio signal.
2066      * @param strategy the audio strategy whose routing will be affected
2067      * @param devices a non-empty list of the audio devices to route to when available
2068      * @return true if the operation was successful, false otherwise
2069      */
2070     @SystemApi
2071     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setPreferredDevicesForStrategy(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2072     public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
2073                                                   @NonNull List<AudioDeviceAttributes> devices) {
2074         Objects.requireNonNull(strategy);
2075         Objects.requireNonNull(devices);
2076         if (devices.isEmpty()) {
2077             throw new IllegalArgumentException(
2078                     "Tried to set preferred devices for strategy with a empty list");
2079         }
2080         for (AudioDeviceAttributes device : devices) {
2081             Objects.requireNonNull(device);
2082         }
2083         try {
2084             final int status =
2085                     getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
2086             return status == AudioSystem.SUCCESS;
2087         } catch (RemoteException e) {
2088             throw e.rethrowFromSystemServer();
2089         }
2090     }
2091 
2092     /**
2093      * @hide
2094      * Return the preferred devices for an audio strategy, previously set with
2095      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2096      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
2097      * @param strategy the strategy to query
2098      * @return list of the preferred devices for that strategy
2099      */
2100     @SystemApi
2101     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
2102     @NonNull
getPreferredDevicesForStrategy( @onNull AudioProductStrategy strategy)2103     public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
2104             @NonNull AudioProductStrategy strategy) {
2105         Objects.requireNonNull(strategy);
2106         try {
2107             return getService().getPreferredDevicesForStrategy(strategy.getId());
2108         } catch (RemoteException e) {
2109             throw e.rethrowFromSystemServer();
2110         }
2111     }
2112 
2113     /**
2114      * @hide
2115      * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by
2116      * this audio strategy.
2117      * <p>Use
2118      * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2119      * to cancel setting this preference for this strategy.</p>
2120      * @param strategy the audio strategy whose routing will be affected
2121      * @param device the audio device to not route to when available
2122      * @return true if the operation was successful, false otherwise
2123      */
2124     @SystemApi
2125     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2126     public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2127                                                     @NonNull AudioDeviceAttributes device) {
2128         Objects.requireNonNull(strategy);
2129         Objects.requireNonNull(device);
2130         try {
2131             final int status =
2132                     getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2133             return status == AudioSystem.SUCCESS;
2134         } catch (RemoteException e) {
2135             throw e.rethrowFromSystemServer();
2136         }
2137     }
2138 
2139     /**
2140      * @hide
2141      * Removes the audio device(s) from the non-default device list previously set with
2142      * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2143      * @param strategy the audio strategy whose routing will be affected
2144      * @param device the audio device to remove from the non-default device list
2145      * @return true if the operation was successful, false otherwise (invalid strategy, or no
2146      *     device set for example)
2147      */
2148     @SystemApi
2149     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removeDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2150     public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy,
2151                                                        @NonNull AudioDeviceAttributes device) {
2152         Objects.requireNonNull(strategy);
2153         Objects.requireNonNull(device);
2154         try {
2155             final int status =
2156                     getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device);
2157             return status == AudioSystem.SUCCESS;
2158         } catch (RemoteException e) {
2159             throw e.rethrowFromSystemServer();
2160         }
2161     }
2162 
2163     /**
2164      * @hide
2165      * Gets the audio device(s) from the non-default device list previously set with
2166      * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2167      * @param strategy the audio strategy to query
2168      * @return list of non-default devices for the strategy
2169      */
2170     @SystemApi
2171     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
2172     @NonNull
getNonDefaultDevicesForStrategy( @onNull AudioProductStrategy strategy)2173     public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy(
2174             @NonNull AudioProductStrategy strategy) {
2175         Objects.requireNonNull(strategy);
2176         try {
2177             return getService().getNonDefaultDevicesForStrategy(strategy.getId());
2178         } catch (RemoteException e) {
2179             throw e.rethrowFromSystemServer();
2180         }
2181     }
2182 
2183     /**
2184      * @hide
2185      * Interface to be notified of changes in the preferred audio device set for a given audio
2186      * strategy.
2187      * <p>Note that this listener will only be invoked whenever
2188      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
2189      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
2190      * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2191      * preferred device. It will not be invoked directly after registration with
2192      * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
2193      * to indicate which strategies had preferred devices at the time of registration.</p>
2194      * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2195      * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
2196      * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
2197      * @deprecated use #OnPreferredDevicesForStrategyChangedListener
2198      */
2199     @SystemApi
2200     @Deprecated
2201     public interface OnPreferredDeviceForStrategyChangedListener {
2202         /**
2203          * Called on the listener to indicate that the preferred audio device for the given
2204          * strategy has changed.
2205          * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2206          * @param device <code>null</code> if the preferred device was removed, or the newly set
2207          *              preferred audio device
2208          */
onPreferredDeviceForStrategyChanged(@onNull AudioProductStrategy strategy, @Nullable AudioDeviceAttributes device)2209         void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
2210                 @Nullable AudioDeviceAttributes device);
2211     }
2212 
2213     /**
2214      * @hide
2215      * Interface to be notified of changes in the preferred audio devices set for a given audio
2216      * strategy.
2217      * <p>Note that this listener will only be invoked whenever
2218      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2219      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2220      * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2221      * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2222      * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2223      * preferred device(s). It will not be invoked directly after registration with
2224      * {@link #addOnPreferredDevicesForStrategyChangedListener(
2225      * Executor, OnPreferredDevicesForStrategyChangedListener)}
2226      * to indicate which strategies had preferred devices at the time of registration.</p>
2227      * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2228      * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
2229      * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
2230      * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
2231      */
2232     @SystemApi
2233     public interface OnPreferredDevicesForStrategyChangedListener {
2234         /**
2235          * Called on the listener to indicate that the preferred audio devices for the given
2236          * strategy has changed.
2237          * @param strategy the {@link AudioProductStrategy} whose preferred device changed
2238          * @param devices a list of newly set preferred audio devices
2239          */
onPreferredDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2240         void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2241                                                   @NonNull List<AudioDeviceAttributes> devices);
2242     }
2243 
2244     /**
2245      * @hide
2246      * Adds a listener for being notified of changes to the strategy-preferred audio device.
2247      * @param executor
2248      * @param listener
2249      * @throws SecurityException if the caller doesn't hold the required permission
2250      * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
2251      *             Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2252      */
2253     @SystemApi
2254     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
2255     @Deprecated
addOnPreferredDeviceForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener)2256     public void addOnPreferredDeviceForStrategyChangedListener(
2257             @NonNull @CallbackExecutor Executor executor,
2258             @NonNull OnPreferredDeviceForStrategyChangedListener listener)
2259             throws SecurityException {
2260         // No-op, the method is deprecated.
2261     }
2262 
2263     /**
2264      * @hide
2265      * Removes a previously added listener of changes to the strategy-preferred audio device.
2266      * @param listener
2267      * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
2268      *             AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
2269      */
2270     @SystemApi
2271     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
2272     @Deprecated
removeOnPreferredDeviceForStrategyChangedListener( @onNull OnPreferredDeviceForStrategyChangedListener listener)2273     public void removeOnPreferredDeviceForStrategyChangedListener(
2274             @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
2275         // No-op, the method is deprecated.
2276     }
2277 
2278     /**
2279      * @hide
2280      * Adds a listener for being notified of changes to the strategy-preferred audio device.
2281      * @param executor
2282      * @param listener
2283      * @throws SecurityException if the caller doesn't hold the required permission
2284      */
2285     @SystemApi
2286     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
addOnPreferredDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForStrategyChangedListener listener)2287     public void addOnPreferredDevicesForStrategyChangedListener(
2288             @NonNull @CallbackExecutor Executor executor,
2289             @NonNull OnPreferredDevicesForStrategyChangedListener listener)
2290             throws SecurityException {
2291         Objects.requireNonNull(executor);
2292         Objects.requireNonNull(listener);
2293         mPrefDevListenerMgr.addListener(
2294                 executor, listener, "addOnPreferredDevicesForStrategyChangedListener",
2295                 () -> new StrategyPreferredDevicesDispatcherStub());
2296     }
2297 
2298     /**
2299      * @hide
2300      * Removes a previously added listener of changes to the strategy-preferred audio device.
2301      * @param listener
2302      */
2303     @SystemApi
2304     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removeOnPreferredDevicesForStrategyChangedListener( @onNull OnPreferredDevicesForStrategyChangedListener listener)2305     public void removeOnPreferredDevicesForStrategyChangedListener(
2306             @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
2307         Objects.requireNonNull(listener);
2308         mPrefDevListenerMgr.removeListener(
2309                 listener, "removeOnPreferredDevicesForStrategyChangedListener");
2310     }
2311 
2312     /**
2313      * @hide
2314      * Interface to be notified of changes in the non-default audio devices set for a given audio
2315      * strategy.
2316      * <p>Note that this listener will only be invoked whenever
2317      * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2318      * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)},
2319      * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)},
2320      * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
2321      * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
2322      * non-default device(s). It will not be invoked directly after registration with
2323      * {@link #addOnNonDefaultDevicesForStrategyChangedListener(
2324      * Executor, OnNonDefaultDevicesForStrategyChangedListener)}
2325      * to indicate which strategies had preferred devices at the time of registration.</p>
2326      * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2327      * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)
2328      */
2329     @SystemApi
2330     public interface OnNonDefaultDevicesForStrategyChangedListener {
2331         /**
2332          * Called on the listener to indicate that the non-default audio devices for the given
2333          * strategy has changed.
2334          * @param strategy the {@link AudioProductStrategy} whose non-default device changed
2335          * @param devices a list of newly set non-default audio devices
2336          */
onNonDefaultDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2337         void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
2338                                                    @NonNull List<AudioDeviceAttributes> devices);
2339     }
2340 
2341     /**
2342      * @hide
2343      * Adds a listener for being notified of changes to the non-default audio devices for
2344      * strategies.
2345      * @param executor
2346      * @param listener
2347      * @throws SecurityException if the caller doesn't hold the required permission
2348      */
2349     @SystemApi
2350     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
addOnNonDefaultDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)2351     public void addOnNonDefaultDevicesForStrategyChangedListener(
2352             @NonNull @CallbackExecutor Executor executor,
2353             @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)
2354             throws SecurityException {
2355         Objects.requireNonNull(executor);
2356         Objects.requireNonNull(listener);
2357 
2358         mNonDefDevListenerMgr.addListener(
2359                 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener",
2360                 () -> new StrategyNonDefaultDevicesDispatcherStub());
2361     }
2362 
2363     /**
2364      * @hide
2365      * Removes a previously added listener of changes to the non-default audio device for
2366      * strategies.
2367      * @param listener
2368      */
2369     @SystemApi
2370     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removeOnNonDefaultDevicesForStrategyChangedListener( @onNull OnNonDefaultDevicesForStrategyChangedListener listener)2371     public void removeOnNonDefaultDevicesForStrategyChangedListener(
2372             @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) {
2373         Objects.requireNonNull(listener);
2374         mNonDefDevListenerMgr.removeListener(
2375                 listener, "removeOnNonDefaultDevicesForStrategyChangedListener");
2376     }
2377 
2378     /**
2379      * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the
2380      * StrategyPreferredDevicesDispatcherStub
2381      */
2382     private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener>
2383             mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2384 
2385     /**
2386      * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the
2387      * StrategyNonDefaultDevicesDispatcherStub
2388      */
2389     private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener>
2390             mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager();
2391 
2392     private final class StrategyPreferredDevicesDispatcherStub
2393             extends IStrategyPreferredDevicesDispatcher.Stub
2394             implements CallbackUtil.DispatcherStub {
2395 
2396         @Override
dispatchPrefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2397         public void dispatchPrefDevicesChanged(int strategyId,
2398                                                @NonNull List<AudioDeviceAttributes> devices) {
2399             final AudioProductStrategy strategy =
2400                     AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2401 
2402             mPrefDevListenerMgr.callListeners(
2403                     (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices));
2404         }
2405 
2406         @Override
register(boolean register)2407         public void register(boolean register) {
2408             try {
2409                 if (register) {
2410                     getService().registerStrategyPreferredDevicesDispatcher(this);
2411                 } else {
2412                     getService().unregisterStrategyPreferredDevicesDispatcher(this);
2413                 }
2414             } catch (RemoteException e) {
2415                 e.rethrowFromSystemServer();
2416             }
2417         }
2418     }
2419 
2420     private final class StrategyNonDefaultDevicesDispatcherStub
2421             extends IStrategyNonDefaultDevicesDispatcher.Stub
2422             implements CallbackUtil.DispatcherStub {
2423 
2424         @Override
dispatchNonDefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2425         public void dispatchNonDefDevicesChanged(int strategyId,
2426                                                  @NonNull List<AudioDeviceAttributes> devices) {
2427             final AudioProductStrategy strategy =
2428                     AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
2429 
2430             mNonDefDevListenerMgr.callListeners(
2431                     (listener) -> listener.onNonDefaultDevicesForStrategyChanged(
2432                             strategy, devices));
2433         }
2434 
2435         @Override
register(boolean register)2436         public void register(boolean register) {
2437             try {
2438                 if (register) {
2439                     getService().registerStrategyNonDefaultDevicesDispatcher(this);
2440                 } else {
2441                     getService().unregisterStrategyNonDefaultDevicesDispatcher(this);
2442                 }
2443             } catch (RemoteException e) {
2444                 e.rethrowFromSystemServer();
2445             }
2446         }
2447     }
2448 
2449     //====================================================================
2450     // Audio Capture Preset routing
2451 
2452     /**
2453      * @hide
2454      * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2455      * this capture preset. Note that the device may not be available at the time the preferred
2456      * device is set, but it will be used once made available.
2457      * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2458      * for this capture preset.</p>
2459      * @param capturePreset the audio capture preset whose routing will be affected
2460      * @param device the audio device to route to when available
2461      * @return true if the operation was successful, false otherwise
2462      */
2463     @SystemApi
2464     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setPreferredDeviceForCapturePreset(@ediaRecorder.SystemSource int capturePreset, @NonNull AudioDeviceAttributes device)2465     public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
2466                                                       @NonNull AudioDeviceAttributes device) {
2467         return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2468     }
2469 
2470     /**
2471      * @hide
2472      * Remove all the preferred audio devices previously set
2473      * @param capturePreset the audio capture preset whose routing will be affected
2474      * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2475      *     device set for example)
2476      */
2477     @SystemApi
2478     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
clearPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2479     public boolean clearPreferredDevicesForCapturePreset(
2480             @MediaRecorder.SystemSource int capturePreset) {
2481         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2482             return false;
2483         }
2484         try {
2485             final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2486             return status == AudioSystem.SUCCESS;
2487         } catch (RemoteException e) {
2488             throw e.rethrowFromSystemServer();
2489         }
2490     }
2491 
2492     /**
2493      * @hide
2494      * Return the preferred devices for an audio capture preset, previously set with
2495      * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2496      * @param capturePreset the capture preset to query
2497      * @return a list that contains preferred devices for that capture preset.
2498      */
2499     @NonNull
2500     @SystemApi
2501     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2502     public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2503             @MediaRecorder.SystemSource int capturePreset) {
2504         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2505             return new ArrayList<AudioDeviceAttributes>();
2506         }
2507         try {
2508             return getService().getPreferredDevicesForCapturePreset(capturePreset);
2509         } catch (RemoteException e) {
2510             throw e.rethrowFromSystemServer();
2511         }
2512     }
2513 
setPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2514     private boolean setPreferredDevicesForCapturePreset(
2515             @MediaRecorder.SystemSource int capturePreset,
2516             @NonNull List<AudioDeviceAttributes> devices) {
2517         Objects.requireNonNull(devices);
2518         if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2519             return false;
2520         }
2521         if (devices.size() != 1) {
2522             throw new IllegalArgumentException(
2523                     "Only support setting one preferred devices for capture preset");
2524         }
2525         for (AudioDeviceAttributes device : devices) {
2526             Objects.requireNonNull(device);
2527         }
2528         try {
2529             final int status =
2530                     getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2531             return status == AudioSystem.SUCCESS;
2532         } catch (RemoteException e) {
2533             throw e.rethrowFromSystemServer();
2534         }
2535     }
2536 
2537     /**
2538      * @hide
2539      * Interface to be notified of changes in the preferred audio devices set for a given capture
2540      * preset.
2541      * <p>Note that this listener will only be invoked whenever
2542      * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2543      * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2544      * preferred device. It will not be invoked directly after registration with
2545      * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2546      * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2547      * to indicate which strategies had preferred devices at the time of registration.</p>
2548      * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2549      * @see #clearPreferredDevicesForCapturePreset(int)
2550      * @see #getPreferredDevicesForCapturePreset(int)
2551      */
2552     @SystemApi
2553     public interface OnPreferredDevicesForCapturePresetChangedListener {
2554         /**
2555          * Called on the listener to indicate that the preferred audio devices for the given
2556          * capture preset has changed.
2557          * @param capturePreset the capture preset whose preferred device changed
2558          * @param devices a list of newly set preferred audio devices
2559          */
onPreferredDevicesForCapturePresetChanged( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2560         void onPreferredDevicesForCapturePresetChanged(
2561                 @MediaRecorder.SystemSource int capturePreset,
2562                 @NonNull List<AudioDeviceAttributes> devices);
2563     }
2564 
2565     /**
2566      * @hide
2567      * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2568      * @param executor
2569      * @param listener
2570      * @throws SecurityException if the caller doesn't hold the required permission
2571      */
2572     @SystemApi
2573     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
addOnPreferredDevicesForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)2574     public void addOnPreferredDevicesForCapturePresetChangedListener(
2575             @NonNull @CallbackExecutor Executor executor,
2576             @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2577             throws SecurityException {
2578         Objects.requireNonNull(executor);
2579         Objects.requireNonNull(listener);
2580         int status = addOnDevRoleForCapturePresetChangedListener(
2581                 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2582         if (status == AudioSystem.ERROR) {
2583             // This must not happen
2584             throw new RuntimeException("Unknown error happened");
2585         }
2586         if (status == AudioSystem.BAD_VALUE) {
2587             throw new IllegalArgumentException(
2588                     "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2589                             + "on a previously registered listener");
2590         }
2591     }
2592 
2593     /**
2594      * @hide
2595      * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2596      * @param listener
2597      */
2598     @SystemApi
2599     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removeOnPreferredDevicesForCapturePresetChangedListener( @onNull OnPreferredDevicesForCapturePresetChangedListener listener)2600     public void removeOnPreferredDevicesForCapturePresetChangedListener(
2601             @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2602         Objects.requireNonNull(listener);
2603         int status = removeOnDevRoleForCapturePresetChangedListener(
2604                 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2605         if (status == AudioSystem.ERROR) {
2606             // This must not happen
2607             throw new RuntimeException("Unknown error happened");
2608         }
2609         if (status == AudioSystem.BAD_VALUE) {
2610             throw new IllegalArgumentException(
2611                     "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2612                             + "on an unregistered listener");
2613         }
2614     }
2615 
addOnDevRoleForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull T listener, int deviceRole)2616     private <T> int addOnDevRoleForCapturePresetChangedListener(
2617             @NonNull @CallbackExecutor Executor executor,
2618             @NonNull T listener, int deviceRole) {
2619         Objects.requireNonNull(executor);
2620         Objects.requireNonNull(listener);
2621         DevRoleListeners<T> devRoleListeners =
2622                 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2623         if (devRoleListeners == null) {
2624             return AudioSystem.ERROR;
2625         }
2626         synchronized (devRoleListeners.mDevRoleListenersLock) {
2627             if (devRoleListeners.hasDevRoleListener(listener)) {
2628                 return AudioSystem.BAD_VALUE;
2629             }
2630             // lazy initialization of the list of device role listener
2631             if (devRoleListeners.mListenerInfos == null) {
2632                 devRoleListeners.mListenerInfos = new ArrayList<>();
2633             }
2634             final int oldCbCount = devRoleListeners.mListenerInfos.size();
2635             devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2636             if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2637                 // register binder for callbacks
2638                 synchronized (mDevRoleForCapturePresetListenersLock) {
2639                     int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2640                     mDeviceRoleListenersStatus |= (1 << deviceRole);
2641                     if (deviceRoleListenerStatus != 0) {
2642                         // There are already device role changed listeners active.
2643                         return AudioSystem.SUCCESS;
2644                     }
2645                     if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2646                         mDevicesRoleForCapturePresetDispatcherStub =
2647                                 new CapturePresetDevicesRoleDispatcherStub();
2648                     }
2649                     try {
2650                         getService().registerCapturePresetDevicesRoleDispatcher(
2651                                 mDevicesRoleForCapturePresetDispatcherStub);
2652                     } catch (RemoteException e) {
2653                         throw e.rethrowFromSystemServer();
2654                     }
2655                 }
2656             }
2657         }
2658         return AudioSystem.SUCCESS;
2659     }
2660 
removeOnDevRoleForCapturePresetChangedListener( @onNull T listener, int deviceRole)2661     private <T> int removeOnDevRoleForCapturePresetChangedListener(
2662             @NonNull T listener, int deviceRole) {
2663         Objects.requireNonNull(listener);
2664         DevRoleListeners<T> devRoleListeners =
2665                 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2666         if (devRoleListeners == null) {
2667             return AudioSystem.ERROR;
2668         }
2669         synchronized (devRoleListeners.mDevRoleListenersLock) {
2670             if (!devRoleListeners.removeDevRoleListener(listener)) {
2671                 return AudioSystem.BAD_VALUE;
2672             }
2673             if (devRoleListeners.mListenerInfos.size() == 0) {
2674                 // unregister binder for callbacks
2675                 synchronized (mDevRoleForCapturePresetListenersLock) {
2676                     mDeviceRoleListenersStatus ^= (1 << deviceRole);
2677                     if (mDeviceRoleListenersStatus != 0) {
2678                         // There are some other device role changed listeners active.
2679                         return AudioSystem.SUCCESS;
2680                     }
2681                     try {
2682                         getService().unregisterCapturePresetDevicesRoleDispatcher(
2683                                 mDevicesRoleForCapturePresetDispatcherStub);
2684                     } catch (RemoteException e) {
2685                         throw e.rethrowFromSystemServer();
2686                     }
2687                 }
2688             }
2689         }
2690         return AudioSystem.SUCCESS;
2691     }
2692 
2693     private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of(
2694             AudioSystem.DEVICE_ROLE_PREFERRED,
2695             new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2696 
2697     private class DevRoleListenerInfo<T> {
2698         final @NonNull Executor mExecutor;
2699         final @NonNull T mListener;
DevRoleListenerInfo(Executor executor, T listener)2700         DevRoleListenerInfo(Executor executor, T listener) {
2701             mExecutor = executor;
2702             mListener = listener;
2703         }
2704     }
2705 
2706     private class DevRoleListeners<T> {
2707         private final Object mDevRoleListenersLock = new Object();
2708         @GuardedBy("mDevRoleListenersLock")
2709         private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2710 
2711         @GuardedBy("mDevRoleListenersLock")
getDevRoleListenerInfo(T listener)2712         private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2713             if (mListenerInfos == null) {
2714                 return null;
2715             }
2716             for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2717                 if (listenerInfo.mListener == listener) {
2718                     return listenerInfo;
2719                 }
2720             }
2721             return null;
2722         }
2723 
2724         @GuardedBy("mDevRoleListenersLock")
hasDevRoleListener(T listener)2725         private boolean hasDevRoleListener(T listener) {
2726             return getDevRoleListenerInfo(listener) != null;
2727         }
2728 
2729         @GuardedBy("mDevRoleListenersLock")
removeDevRoleListener(T listener)2730         private boolean removeDevRoleListener(T listener) {
2731             final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2732             if (infoToRemove != null) {
2733                 mListenerInfos.remove(infoToRemove);
2734                 return true;
2735             }
2736             return false;
2737         }
2738     }
2739 
2740     private final Object mDevRoleForCapturePresetListenersLock = new Object();
2741     /**
2742      * Record if there is a listener added for device role change. If there is a listener added for
2743      * a specified device role change, the bit at position `1 << device_role` is set.
2744      */
2745     @GuardedBy("mDevRoleForCapturePresetListenersLock")
2746     private int mDeviceRoleListenersStatus = 0;
2747     @GuardedBy("mDevRoleForCapturePresetListenersLock")
2748     private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2749 
2750     private final class CapturePresetDevicesRoleDispatcherStub
2751             extends ICapturePresetDevicesRoleDispatcher.Stub {
2752 
2753         @Override
dispatchDevicesRoleChanged( int capturePreset, int role, List<AudioDeviceAttributes> devices)2754         public void dispatchDevicesRoleChanged(
2755                 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2756             final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2757             if (listenersObj == null) {
2758                 return;
2759             }
2760             switch (role) {
2761                 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2762                     final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2763                             listeners =
2764                             (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2765                             listenersObj;
2766                     final ArrayList<DevRoleListenerInfo<
2767                             OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2768                     synchronized (listeners.mDevRoleListenersLock) {
2769                         if (listeners.mListenerInfos.isEmpty()) {
2770                             return;
2771                         }
2772                         prefDevListeners = (ArrayList<DevRoleListenerInfo<
2773                                 OnPreferredDevicesForCapturePresetChangedListener>>)
2774                                 listeners.mListenerInfos.clone();
2775                     }
2776                     final long ident = Binder.clearCallingIdentity();
2777                     try {
2778                         for (DevRoleListenerInfo<
2779                                 OnPreferredDevicesForCapturePresetChangedListener> info :
2780                                 prefDevListeners) {
2781                             info.mExecutor.execute(() ->
2782                                     info.mListener.onPreferredDevicesForCapturePresetChanged(
2783                                             capturePreset, devices));
2784                         }
2785                     } finally {
2786                         Binder.restoreCallingIdentity(ident);
2787                     }
2788                 } break;
2789                 default:
2790                     break;
2791             }
2792         }
2793     }
2794 
2795     //====================================================================
2796     // Direct playback query
2797 
2798     /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2799         direct playback not supported. */
2800     public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED;
2801     /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2802         direct offload playback supported. Compressed offload is a variant of direct playback.
2803         It is the feature that allows audio processing tasks to be done on the Android device but
2804         not on the application processor, instead, it is handled by dedicated hardware such as audio
2805         DSPs. That will allow the application processor to be idle as much as possible, which is
2806         good for power saving. Compressed offload playback supports
2807         {@link AudioTrack.StreamEventCallback} for event notifications. */
2808     public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED =
2809             AudioSystem.DIRECT_OFFLOAD_SUPPORTED;
2810     /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2811         direct offload playback supported with gapless transitions. Compressed offload is a variant
2812         of direct playback. It is the feature that allows audio processing tasks to be done on the
2813         Android device but not on the application processor, instead, it is handled by dedicated
2814         hardware such as audio DSPs. That will allow the application processor to be idle as much as
2815         possible, which is good for power saving. Compressed offload playback supports
2816         {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions
2817         indicates the ability to play consecutive audio tracks without an audio silence in
2818         between. */
2819     public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2820             AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED;
2821     /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}:
2822         direct playback supported. This value covers direct playback that is bitstream pass-through
2823         such as compressed pass-through. */
2824     public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED =
2825             AudioSystem.DIRECT_BITSTREAM_SUPPORTED;
2826 
2827     /** @hide */
2828     @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = {
2829             DIRECT_PLAYBACK_NOT_SUPPORTED,
2830             DIRECT_PLAYBACK_OFFLOAD_SUPPORTED,
2831             DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED,
2832             DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}
2833     )
2834     @Retention(RetentionPolicy.SOURCE)
2835     public @interface AudioDirectPlaybackMode {}
2836 
2837     /**
2838      * Returns a bitfield representing the different forms of direct playback currently available
2839      * for a given audio format.
2840      * <p>Direct playback means that the audio stream is not altered by the framework. The audio
2841      * stream will not be resampled, volume scaled, downmixed or mixed with other content by
2842      * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for
2843      * passthrough.
2844      * <p>Checking for direct support can help the app select the representation of audio content
2845      * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver)
2846      * connected to it. Note that the provided stream can still be re-encoded or mixed with other
2847      * streams, if needed.
2848      * @param format the audio format (codec, sample rate, channels) being checked.
2849      * @param attributes the {@link AudioAttributes} to be used for playback
2850      * @return the direct playback mode available with given format and attributes. The returned
2851      *         value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of
2852      *         {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED},
2853      *         {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and
2854      *         {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if
2855      *         {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value,
2856      *         then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too.
2857      */
2858     @AudioDirectPlaybackMode
getDirectPlaybackSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2859     public static int getDirectPlaybackSupport(@NonNull AudioFormat format,
2860                                                @NonNull AudioAttributes attributes) {
2861         Objects.requireNonNull(format);
2862         Objects.requireNonNull(attributes);
2863         return AudioSystem.getDirectPlaybackSupport(format, attributes);
2864     }
2865 
2866     //====================================================================
2867     // Offload query
2868     /**
2869      * Returns whether offloaded playback of an audio format is supported on the device.
2870      * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2871      * is not competing with other software resources. In general, it is supported by dedicated
2872      * hardware, such as audio DSPs.
2873      * <p>Note that this query only provides information about the support of an audio format,
2874      * it does not indicate whether the resources necessary for the offloaded playback are
2875      * available at that instant.
2876      * @param format the audio format (codec, sample rate, channels) being checked.
2877      * @param attributes the {@link AudioAttributes} to be used for playback
2878      * @return true if the given audio format can be offloaded.
2879      */
isOffloadedPlaybackSupported(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2880     public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2881             @NonNull AudioAttributes attributes) {
2882         if (format == null) {
2883             throw new NullPointerException("Illegal null AudioFormat");
2884         }
2885         if (attributes == null) {
2886             throw new NullPointerException("Illegal null AudioAttributes");
2887         }
2888         return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2889     }
2890 
2891     /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2892         offload playback not supported */
2893     public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2894     /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2895         offload playback supported */
2896     public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2897     /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2898         offload playback supported with gapless transitions */
2899     public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2900             AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2901 
2902     /** @hide */
2903     @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2904             PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2905             PLAYBACK_OFFLOAD_SUPPORTED,
2906             PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2907     )
2908     @Retention(RetentionPolicy.SOURCE)
2909     public @interface AudioOffloadMode {}
2910 
2911     /**
2912      * Returns whether offloaded playback of an audio format is supported on the device or not and
2913      * when supported whether gapless transitions are possible or not.
2914      * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2915      * is not competing with other software resources. In general, it is supported by dedicated
2916      * hardware, such as audio DSPs.
2917      * <p>Note that this query only provides information about the support of an audio format,
2918      * it does not indicate whether the resources necessary for the offloaded playback are
2919      * available at that instant.
2920      * @param format the audio format (codec, sample rate, channels) being checked.
2921      * @param attributes the {@link AudioAttributes} to be used for playback
2922      * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2923      *         {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2924      *         {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2925      *         also supported.
2926      * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead
2927      */
2928     @Deprecated
2929     @AudioOffloadMode
getPlaybackOffloadSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)2930     public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2931             @NonNull AudioAttributes attributes) {
2932         if (format == null) {
2933             throw new NullPointerException("Illegal null AudioFormat");
2934         }
2935         if (attributes == null) {
2936             throw new NullPointerException("Illegal null AudioAttributes");
2937         }
2938         return AudioSystem.getOffloadSupport(format, attributes);
2939     }
2940 
2941     //====================================================================
2942     // Immersive audio
2943 
2944     /**
2945      * Return a handle to the optional platform's {@link Spatializer}
2946      * @return the {@code Spatializer} instance.
2947      * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect
2948      *   on the platform
2949      */
getSpatializer()2950     public @NonNull Spatializer getSpatializer() {
2951         return new Spatializer(this);
2952     }
2953 
2954     //====================================================================
2955     // Bluetooth SCO control
2956     /**
2957      * Sticky broadcast intent action indicating that the Bluetooth SCO audio
2958      * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
2959      * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2960      * or {@link #SCO_AUDIO_STATE_CONNECTED}
2961      *
2962      * @see #startBluetoothSco()
2963      * @deprecated Use  {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
2964      */
2965     @Deprecated
2966     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2967     public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2968             "android.media.SCO_AUDIO_STATE_CHANGED";
2969 
2970      /**
2971      * Sticky broadcast intent action indicating that the Bluetooth SCO audio
2972      * connection state has been updated.
2973      * <p>This intent has two extras:
2974      * <ul>
2975      *   <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2976      *   <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2977      * </ul>
2978      * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2979      * <ul>
2980      *   <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2981      *   <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2982      *   <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2983      * </ul>
2984      * @see #startBluetoothSco()
2985      */
2986     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2987     public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2988             "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2989 
2990     /**
2991      * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2992      * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
2993      */
2994     public static final String EXTRA_SCO_AUDIO_STATE =
2995             "android.media.extra.SCO_AUDIO_STATE";
2996 
2997     /**
2998      * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2999      * bluetooth SCO connection state.
3000      */
3001     public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
3002             "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
3003 
3004     /**
3005      * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
3006      * indicating that the SCO audio channel is not established
3007      */
3008     public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
3009     /**
3010      * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
3011      * indicating that the SCO audio channel is established
3012      */
3013     public static final int SCO_AUDIO_STATE_CONNECTED = 1;
3014     /**
3015      * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
3016      * indicating that the SCO audio channel is being established
3017      */
3018     public static final int SCO_AUDIO_STATE_CONNECTING = 2;
3019     /**
3020      * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
3021      * there was an error trying to obtain the state
3022      */
3023     public static final int SCO_AUDIO_STATE_ERROR = -1;
3024 
3025 
3026     /**
3027      * Indicates if current platform supports use of SCO for off call use cases.
3028      * Application wanted to use bluetooth SCO audio when the phone is not in call
3029      * must first call this method to make sure that the platform supports this
3030      * feature.
3031      * @return true if bluetooth SCO can be used for audio when not in call
3032      *         false otherwise
3033      * @see #startBluetoothSco()
3034     */
isBluetoothScoAvailableOffCall()3035     public boolean isBluetoothScoAvailableOffCall() {
3036         return getContext().getResources().getBoolean(
3037                com.android.internal.R.bool.config_bluetooth_sco_off_call);
3038     }
3039 
3040     /**
3041      * Start bluetooth SCO audio connection.
3042      * <p>Requires Permission:
3043      *   {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
3044      * <p>This method can be used by applications wanting to send and received audio
3045      * to/from a bluetooth SCO headset while the phone is not in call.
3046      * <p>As the SCO connection establishment can take several seconds,
3047      * applications should not rely on the connection to be available when the method
3048      * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
3049      * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
3050      * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
3051      * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
3052      * registration. If the state is already CONNECTED, no state change will be received via the
3053      * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
3054      * so that the connection stays active in case the current initiator stops the connection.
3055      * <p>Unless the connection is already active as described above, the state will always
3056      * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
3057      * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
3058      * <p>When finished with the SCO connection or if the establishment fails, the application must
3059      * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
3060      * <p>Even if a SCO connection is established, the following restrictions apply on audio
3061      * output streams so that they can be routed to SCO headset:
3062      * <ul>
3063      *   <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
3064      *   <li> the format must be mono </li>
3065      *   <li> the sampling must be 16kHz or 8kHz </li>
3066      * </ul>
3067      * <p>The following restrictions apply on input streams:
3068      * <ul>
3069      *   <li> the format must be mono </li>
3070      *   <li> the sampling must be 8kHz </li>
3071      * </ul>
3072      * <p>Note that the phone application always has the priority on the usage of the SCO
3073      * connection for telephony. If this method is called while the phone is in call
3074      * it will be ignored. Similarly, if a call is received or sent while an application
3075      * is using the SCO connection, the connection will be lost for the application and NOT
3076      * returned automatically when the call ends.
3077      * <p>NOTE: up to and including API version
3078      * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
3079      * voice call to the bluetooth headset.
3080      * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
3081      * connection is established.
3082      * @see #stopBluetoothSco()
3083      * @see #ACTION_SCO_AUDIO_STATE_UPDATED
3084      * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead.
3085      */
startBluetoothSco()3086     @Deprecated public void startBluetoothSco() {
3087         final IAudioService service = getService();
3088         try {
3089             service.startBluetoothSco(mICallBack,
3090                     getContext().getApplicationInfo().targetSdkVersion);
3091         } catch (RemoteException e) {
3092             throw e.rethrowFromSystemServer();
3093         }
3094     }
3095 
3096     /**
3097      * @hide
3098      * Start bluetooth SCO audio connection in virtual call mode.
3099      * <p>Requires Permission:
3100      *   {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
3101      * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
3102      * Telephony and communication applications (VoIP, Video Chat) should preferably select
3103      * virtual call mode.
3104      * Applications using voice input for search or commands should first try raw audio connection
3105      * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
3106      * failure.
3107      * @see #startBluetoothSco()
3108      * @see #stopBluetoothSco()
3109      * @see #ACTION_SCO_AUDIO_STATE_UPDATED
3110      */
3111     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
startBluetoothScoVirtualCall()3112     public void startBluetoothScoVirtualCall() {
3113         final IAudioService service = getService();
3114         try {
3115             service.startBluetoothScoVirtualCall(mICallBack);
3116         } catch (RemoteException e) {
3117             throw e.rethrowFromSystemServer();
3118         }
3119     }
3120 
3121     /**
3122      * Stop bluetooth SCO audio connection.
3123      * <p>Requires Permission:
3124      *   {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}.
3125      * <p>This method must be called by applications having requested the use of
3126      * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
3127      * connection or if connection fails.
3128      * @see #startBluetoothSco()
3129      * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead.
3130      */
3131     // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
stopBluetoothSco()3132     @Deprecated public void stopBluetoothSco() {
3133         final IAudioService service = getService();
3134         try {
3135             service.stopBluetoothSco(mICallBack);
3136         } catch (RemoteException e) {
3137             throw e.rethrowFromSystemServer();
3138         }
3139     }
3140 
3141     /**
3142      * Request use of Bluetooth SCO headset for communications.
3143      * <p>
3144      * This method should only be used by applications that replace the platform-wide
3145      * management of audio settings or the main telephony application.
3146      *
3147      * @param on set <var>true</var> to use bluetooth SCO for communications;
3148      *               <var>false</var> to not use bluetooth SCO for communications
3149      */
setBluetoothScoOn(boolean on)3150     public void setBluetoothScoOn(boolean on){
3151         final IAudioService service = getService();
3152         try {
3153             service.setBluetoothScoOn(on);
3154         } catch (RemoteException e) {
3155             throw e.rethrowFromSystemServer();
3156         }
3157     }
3158 
3159     /**
3160      * Checks whether communications use Bluetooth SCO.
3161      *
3162      * @return true if SCO is used for communications;
3163      *         false if otherwise
3164      * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead.
3165      */
isBluetoothScoOn()3166     @Deprecated public boolean isBluetoothScoOn() {
3167         final IAudioService service = getService();
3168         try {
3169             return service.isBluetoothScoOn();
3170         } catch (RemoteException e) {
3171             throw e.rethrowFromSystemServer();
3172         }
3173     }
3174 
3175     /**
3176      * @deprecated Use {@link MediaRouter#selectRoute} instead.
3177      */
setBluetoothA2dpOn(boolean on)3178     @Deprecated public void setBluetoothA2dpOn(boolean on){
3179     }
3180 
3181     /**
3182      * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
3183      *
3184      * @return true if a Bluetooth A2DP peripheral is connected
3185      *         false if otherwise
3186      * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
3187      */
isBluetoothA2dpOn()3188     public boolean isBluetoothA2dpOn() {
3189         if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
3190                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3191             return true;
3192         } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
3193                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3194             return true;
3195         } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
3196                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
3197             return true;
3198         }
3199         return false;
3200     }
3201 
3202     /**
3203      * Sets audio routing to the wired headset on or off.
3204      *
3205      * @param on set <var>true</var> to route audio to/from wired
3206      *           headset; <var>false</var> disable wired headset audio
3207      * @deprecated Do not use.
3208      */
setWiredHeadsetOn(boolean on)3209     @Deprecated public void setWiredHeadsetOn(boolean on){
3210     }
3211 
3212     /**
3213      * Checks whether a wired headset is connected or not.
3214      * <p>This is not a valid indication that audio playback is
3215      * actually over the wired headset as audio routing depends on other conditions.
3216      *
3217      * @return true if a wired headset is connected.
3218      *         false if otherwise
3219      * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
3220      */
isWiredHeadsetOn()3221     public boolean isWiredHeadsetOn() {
3222         if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
3223                 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
3224             AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
3225                 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
3226             AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
3227               == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
3228             return false;
3229         } else {
3230             return true;
3231         }
3232     }
3233 
3234     /**
3235      * Sets the microphone mute on or off.
3236      * <p>
3237      * This method should only be used by applications that replace the platform-wide
3238      * management of audio settings or the main telephony application.
3239      *
3240      * @param on set <var>true</var> to mute the microphone;
3241      *           <var>false</var> to turn mute off
3242      */
setMicrophoneMute(boolean on)3243     public void setMicrophoneMute(boolean on) {
3244         final IAudioService service = getService();
3245         try {
3246             service.setMicrophoneMute(on, getContext().getOpPackageName(),
3247                     UserHandle.getCallingUserId(), getContext().getAttributionTag());
3248         } catch (RemoteException e) {
3249             throw e.rethrowFromSystemServer();
3250         }
3251     }
3252 
3253     /**
3254      * @hide
3255      * Sets the microphone from switch mute on or off.
3256      * <p>
3257      * This method should only be used by InputManager to notify
3258      * Audio Subsystem about Microphone Mute switch state.
3259      *
3260      * @param on set <var>true</var> to mute the microphone;
3261      *           <var>false</var> to turn mute off
3262      */
3263     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setMicrophoneMuteFromSwitch(boolean on)3264     public void setMicrophoneMuteFromSwitch(boolean on) {
3265         final IAudioService service = getService();
3266         try {
3267             service.setMicrophoneMuteFromSwitch(on);
3268         } catch (RemoteException e) {
3269             throw e.rethrowFromSystemServer();
3270         }
3271     }
3272 
3273     /**
3274      * Checks whether the microphone mute is on or off.
3275      *
3276      * @return true if microphone is muted, false if it's not
3277      */
isMicrophoneMute()3278     public boolean isMicrophoneMute() {
3279         final IAudioService service = getService();
3280         try {
3281             return service.isMicrophoneMuted();
3282         } catch (RemoteException e) {
3283             throw e.rethrowFromSystemServer();
3284         }
3285     }
3286 
3287     /**
3288      * Broadcast Action: microphone muting state changed.
3289      *
3290      * You <em>cannot</em> receive this through components declared
3291      * in manifests, only by explicitly registering for it with
3292      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3293      * Context.registerReceiver()}.
3294      *
3295      * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
3296      * microphone is muted.
3297      */
3298     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3299     public static final String ACTION_MICROPHONE_MUTE_CHANGED =
3300             "android.media.action.MICROPHONE_MUTE_CHANGED";
3301 
3302     /**
3303      * Broadcast Action: speakerphone state changed.
3304      *
3305      * You <em>cannot</em> receive this through components declared
3306      * in manifests, only by explicitly registering for it with
3307      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
3308      * Context.registerReceiver()}.
3309      *
3310      * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
3311      * speakerphone functionality is enabled or not.
3312      */
3313     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
3314     public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
3315             "android.media.action.SPEAKERPHONE_STATE_CHANGED";
3316 
3317     /**
3318      * Sets the audio mode.
3319      * <p>
3320      * The audio mode encompasses audio routing AND the behavior of
3321      * the telephony layer. Therefore this method should only be used by applications that
3322      * replace the platform-wide management of audio settings or the main telephony application.
3323      * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
3324      * application when it places a phone call, as it will cause signals from the radio layer
3325      * to feed the platform mixer.
3326      *
3327      * @param mode  the requested audio mode.
3328      *              Informs the HAL about the current audio state so that
3329      *              it can route the audio appropriately.
3330      */
setMode(@udioMode int mode)3331     public void setMode(@AudioMode int mode) {
3332         final IAudioService service = getService();
3333         try {
3334             service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
3335         } catch (RemoteException e) {
3336             throw e.rethrowFromSystemServer();
3337         }
3338     }
3339 
3340     /**
3341      * This change id controls use of audio modes for call audio redirection.
3342      * @hide
3343      */
3344     @ChangeId
3345     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
3346     public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id
3347 
3348     /**
3349      * Returns the current audio mode.
3350      *
3351      * @return      the current audio mode.
3352      */
3353     @AudioMode
getMode()3354     public int getMode() {
3355         final IAudioService service = getService();
3356         try {
3357             int mode = service.getMode();
3358             int sdk;
3359             try {
3360                 sdk = getContext().getApplicationInfo().targetSdkVersion;
3361             } catch (NullPointerException e) {
3362                 // some tests don't have a Context
3363                 sdk = Build.VERSION.SDK_INT;
3364             }
3365             if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
3366                 mode = MODE_IN_CALL;
3367             } else if (mode == MODE_CALL_REDIRECT
3368                     && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3369                 mode = MODE_IN_CALL;
3370             } else if (mode == MODE_COMMUNICATION_REDIRECT
3371                     && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) {
3372                 mode = MODE_IN_COMMUNICATION;
3373             }
3374             return mode;
3375         } catch (RemoteException e) {
3376             throw e.rethrowFromSystemServer();
3377         }
3378     }
3379 
3380     /**
3381      * Interface definition of a callback that is notified when the audio mode changes
3382      */
3383     public interface OnModeChangedListener {
3384         /**
3385          * Called on the listener to indicate that the audio mode has changed
3386          *
3387          * @param mode The current audio mode
3388          */
onModeChanged(@udioMode int mode)3389         void onModeChanged(@AudioMode int mode);
3390     }
3391 
3392     /**
3393      * manages the OnModeChangedListener listeners and the ModeDispatcherStub
3394      */
3395     private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
3396             new CallbackUtil.LazyListenerManager();
3397 
3398 
3399     final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
3400             implements CallbackUtil.DispatcherStub {
3401 
3402         @Override
register(boolean register)3403         public void register(boolean register) {
3404             try {
3405                 if (register) {
3406                     getService().registerModeDispatcher(this);
3407                 } else {
3408                     getService().unregisterModeDispatcher(this);
3409                 }
3410             } catch (RemoteException e) {
3411                 e.rethrowFromSystemServer();
3412             }
3413         }
3414 
3415         @Override
dispatchAudioModeChanged(int mode)3416         public void dispatchAudioModeChanged(int mode) {
3417             mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
3418         }
3419     }
3420 
3421     /**
3422      * Adds a listener to be notified of changes to the audio mode.
3423      * See {@link #getMode()}
3424      * @param executor
3425      * @param listener
3426      */
addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)3427     public void addOnModeChangedListener(
3428             @NonNull @CallbackExecutor Executor executor,
3429             @NonNull OnModeChangedListener listener) {
3430         mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
3431                 () -> new ModeDispatcherStub());
3432     }
3433 
3434     /**
3435      * Removes a previously added listener for changes to audio mode.
3436      * See {@link #getMode()}
3437      * @param listener
3438      */
removeOnModeChangedListener(@onNull OnModeChangedListener listener)3439     public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
3440         mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
3441     }
3442 
3443     /**
3444     * Indicates if the platform supports a special call screening and call monitoring mode.
3445     * <p>
3446     * When this mode is supported, it is possible to perform call screening and monitoring
3447     * functions while other use cases like music or movie playback are active.
3448     * <p>
3449     * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3450     * call screening mode.
3451     * <p>
3452     * If call screening mode is not supported, setting mode to
3453     * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3454     *  {@link #getMode()}.
3455     * @return true if call screening mode is supported, false otherwise.
3456     */
isCallScreeningModeSupported()3457     public boolean isCallScreeningModeSupported() {
3458         final IAudioService service = getService();
3459         try {
3460             return service.isCallScreeningModeSupported();
3461         } catch (RemoteException e) {
3462             throw e.rethrowFromSystemServer();
3463         }
3464     }
3465 
3466     /* modes for setMode/getMode/setRoute/getRoute */
3467     /**
3468      * Audio hardware modes.
3469      */
3470     /**
3471      * Invalid audio mode.
3472      */
3473     public static final int MODE_INVALID            = AudioSystem.MODE_INVALID;
3474     /**
3475      * Current audio mode. Used to apply audio routing to current mode.
3476      */
3477     public static final int MODE_CURRENT            = AudioSystem.MODE_CURRENT;
3478     /**
3479      * Normal audio mode: not ringing and no call established.
3480      */
3481     public static final int MODE_NORMAL             = AudioSystem.MODE_NORMAL;
3482     /**
3483      * Ringing audio mode. An incoming is being signaled.
3484      */
3485     public static final int MODE_RINGTONE           = AudioSystem.MODE_RINGTONE;
3486     /**
3487      * In call audio mode. A telephony call is established.
3488      */
3489     public static final int MODE_IN_CALL            = AudioSystem.MODE_IN_CALL;
3490     /**
3491      * In communication audio mode. An audio/video chat or VoIP call is established.
3492      */
3493     public static final int MODE_IN_COMMUNICATION   = AudioSystem.MODE_IN_COMMUNICATION;
3494     /**
3495      * Call screening in progress. Call is connected and audio is accessible to call
3496      * screening applications but other audio use cases are still possible.
3497      */
3498     public static final int MODE_CALL_SCREENING     = AudioSystem.MODE_CALL_SCREENING;
3499 
3500     /**
3501      * A telephony call is established and its audio is being redirected to another device.
3502      */
3503     public static final int MODE_CALL_REDIRECT   = AudioSystem.MODE_CALL_REDIRECT;
3504 
3505     /**
3506      * An audio/video chat or VoIP call is established and its audio is being redirected to another
3507      * device.
3508      */
3509     public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT;
3510 
3511     /** @hide */
3512     @IntDef(flag = false, prefix = "MODE_", value = {
3513             MODE_NORMAL,
3514             MODE_RINGTONE,
3515             MODE_IN_CALL,
3516             MODE_IN_COMMUNICATION,
3517             MODE_CALL_SCREENING,
3518             MODE_CALL_REDIRECT,
3519             MODE_COMMUNICATION_REDIRECT}
3520     )
3521     @Retention(RetentionPolicy.SOURCE)
3522     public @interface AudioMode {}
3523 
3524     /* Routing bits for setRouting/getRouting API */
3525     /**
3526      * Routing audio output to earpiece
3527      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3528      * setBluetoothScoOn() methods instead.
3529      */
3530     @Deprecated public static final int ROUTE_EARPIECE          = AudioSystem.ROUTE_EARPIECE;
3531     /**
3532      * Routing audio output to speaker
3533      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3534      * setBluetoothScoOn() methods instead.
3535      */
3536     @Deprecated public static final int ROUTE_SPEAKER           = AudioSystem.ROUTE_SPEAKER;
3537     /**
3538      * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
3539      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3540      * setBluetoothScoOn() methods instead.
3541      */
3542     @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3543     /**
3544      * Routing audio output to bluetooth SCO
3545      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3546      * setBluetoothScoOn() methods instead.
3547      */
3548     @Deprecated public static final int ROUTE_BLUETOOTH_SCO     = AudioSystem.ROUTE_BLUETOOTH_SCO;
3549     /**
3550      * Routing audio output to headset
3551      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3552      * setBluetoothScoOn() methods instead.
3553      */
3554     @Deprecated public static final int ROUTE_HEADSET           = AudioSystem.ROUTE_HEADSET;
3555     /**
3556      * Routing audio output to bluetooth A2DP
3557      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3558      * setBluetoothScoOn() methods instead.
3559      */
3560     @Deprecated public static final int ROUTE_BLUETOOTH_A2DP    = AudioSystem.ROUTE_BLUETOOTH_A2DP;
3561     /**
3562      * Used for mask parameter of {@link #setRouting(int,int,int)}.
3563      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3564      * setBluetoothScoOn() methods instead.
3565      */
3566     @Deprecated public static final int ROUTE_ALL               = AudioSystem.ROUTE_ALL;
3567 
3568     /**
3569      * Sets the audio routing for a specified mode
3570      *
3571      * @param mode   audio mode to change route. E.g., MODE_RINGTONE.
3572      * @param routes bit vector of routes requested, created from one or
3573      *               more of ROUTE_xxx types. Set bits indicate that route should be on
3574      * @param mask   bit vector of routes to change, created from one or more of
3575      * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
3576      *
3577      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3578      * setBluetoothScoOn() methods instead.
3579      */
3580     @Deprecated
setRouting(int mode, int routes, int mask)3581     public void setRouting(int mode, int routes, int mask) {
3582     }
3583 
3584     /**
3585      * Returns the current audio routing bit vector for a specified mode.
3586      *
3587      * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3588      * @return an audio route bit vector that can be compared with ROUTE_xxx
3589      * bits
3590      * @deprecated   Do not query audio routing directly, use isSpeakerphoneOn(),
3591      * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
3592      */
3593     @Deprecated
getRouting(int mode)3594     public int getRouting(int mode) {
3595         return -1;
3596     }
3597 
3598     /**
3599      * Checks whether any music is active.
3600      *
3601      * @return true if any music tracks are active.
3602      */
isMusicActive()3603     public boolean isMusicActive() {
3604         final IAudioService service = getService();
3605         try {
3606             return service.isMusicActive(false /*remotely*/);
3607         } catch (RemoteException e) {
3608             throw e.rethrowFromSystemServer();
3609         }
3610     }
3611 
3612     /**
3613      * @hide
3614      * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3615      *   display). Note that BT audio sinks are not considered remote devices.
3616      * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3617      */
3618     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isMusicActiveRemotely()3619     public boolean isMusicActiveRemotely() {
3620         final IAudioService service = getService();
3621         try {
3622             return service.isMusicActive(true /*remotely*/);
3623         } catch (RemoteException e) {
3624             throw e.rethrowFromSystemServer();
3625         }
3626     }
3627 
3628     /**
3629      * @hide
3630      * Checks whether the current audio focus is exclusive.
3631      * @return true if the top of the audio focus stack requested focus
3632      *     with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3633      */
isAudioFocusExclusive()3634     public boolean isAudioFocusExclusive() {
3635         final IAudioService service = getService();
3636         try {
3637             return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3638         } catch (RemoteException e) {
3639             throw e.rethrowFromSystemServer();
3640         }
3641     }
3642 
3643     /**
3644      * Return a new audio session identifier not associated with any player or effect.
3645      * An audio session identifier is a system wide unique identifier for a set of audio streams
3646      * (one or more mixed together).
3647      * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3648      * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3649      * session ID will be applied to the mixed audio content of the players that share the same
3650      * audio session.
3651      * <p>This method can for instance be used when creating one of the
3652      * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3653      * or to specify a session for a speech synthesis utterance
3654      * in {@link android.speech.tts.TextToSpeech.Engine}.
3655      * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
3656      *   system failed to generate a new session, a condition in which audio playback or recording
3657      *   will subsequently fail as well.
3658      */
generateAudioSessionId()3659     public int generateAudioSessionId() {
3660         int session = AudioSystem.newAudioSessionId();
3661         if (session > 0) {
3662             return session;
3663         } else {
3664             Log.e(TAG, "Failure to generate a new audio session ID");
3665             return ERROR;
3666         }
3667     }
3668 
3669     /**
3670      * A special audio session ID to indicate that the audio session ID isn't known and the
3671      * framework should generate a new value. This can be used when building a new
3672      * {@link AudioTrack} instance with
3673      * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3674      */
3675     public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3676 
3677 
3678     /*
3679      * Sets a generic audio configuration parameter. The use of these parameters
3680      * are platform dependant, see libaudio
3681      *
3682      * ** Temporary interface - DO NOT USE
3683      *
3684      * TODO: Replace with a more generic key:value get/set mechanism
3685      *
3686      * param key   name of parameter to set. Must not be null.
3687      * param value value of parameter. Must not be null.
3688      */
3689     /**
3690      * @hide
3691      * @deprecated Use {@link #setParameters(String)} instead
3692      */
setParameter(String key, String value)3693     @Deprecated public void setParameter(String key, String value) {
3694         setParameters(key+"="+value);
3695     }
3696 
3697     /**
3698      * Sets a variable number of parameter values to audio hardware.
3699      *
3700      * @param keyValuePairs list of parameters key value pairs in the form:
3701      *    key1=value1;key2=value2;...
3702      *
3703      */
setParameters(String keyValuePairs)3704     public void setParameters(String keyValuePairs) {
3705         AudioSystem.setParameters(keyValuePairs);
3706     }
3707 
3708     /**
3709      * @hide
3710      */
3711     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3712     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setHfpEnabled(boolean enable)3713     public void setHfpEnabled(boolean enable) {
3714         AudioSystem.setParameters("hfp_enable=" + enable);
3715     }
3716 
3717     /**
3718      * @hide
3719      */
3720     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3721     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setHfpVolume(int volume)3722     public void setHfpVolume(int volume) {
3723         AudioSystem.setParameters("hfp_volume=" + volume);
3724     }
3725 
3726     /**
3727      * @hide
3728      */
3729     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3730     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setHfpSamplingRate(int rate)3731     public void setHfpSamplingRate(int rate) {
3732         AudioSystem.setParameters("hfp_set_sampling_rate=" + rate);
3733     }
3734 
3735     /**
3736      * @hide
3737      */
3738     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3739     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setBluetoothHeadsetProperties(@onNull String name, boolean hasNrecEnabled, boolean hasWbsEnabled)3740     public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled,
3741             boolean hasWbsEnabled) {
3742         AudioSystem.setParameters("bt_headset_name=" + name
3743                 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off")
3744                 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off"));
3745     }
3746 
3747     /**
3748      * @hide
3749      */
3750     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3751     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setA2dpSuspended(boolean enable)3752     public void setA2dpSuspended(boolean enable) {
3753         final IAudioService service = getService();
3754         try {
3755             service.setA2dpSuspended(enable);
3756         } catch (RemoteException e) {
3757             throw e.rethrowFromSystemServer();
3758         }
3759     }
3760 
3761     /**
3762      * Suspends the use of LE Audio.
3763      *
3764      * @param enable {@code true} to suspend le audio, {@code false} to unsuspend
3765      *
3766      * @hide
3767      */
3768     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
3769     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
setLeAudioSuspended(boolean enable)3770     public void setLeAudioSuspended(boolean enable) {
3771         final IAudioService service = getService();
3772         try {
3773             service.setLeAudioSuspended(enable);
3774         } catch (RemoteException e) {
3775             throw e.rethrowFromSystemServer();
3776         }
3777     }
3778 
3779     /**
3780      * Gets a variable number of parameter values from audio hardware.
3781      *
3782      * @param keys list of parameters
3783      * @return list of parameters key value pairs in the form:
3784      *    key1=value1;key2=value2;...
3785      */
getParameters(String keys)3786     public String getParameters(String keys) {
3787         return AudioSystem.getParameters(keys);
3788     }
3789 
3790     /* Sound effect identifiers */
3791     /**
3792      * Keyboard and direction pad click sound
3793      * @see #playSoundEffect(int)
3794      */
3795     public static final int FX_KEY_CLICK = 0;
3796     /**
3797      * Focus has moved up
3798      * @see #playSoundEffect(int)
3799      */
3800     public static final int FX_FOCUS_NAVIGATION_UP = 1;
3801     /**
3802      * Focus has moved down
3803      * @see #playSoundEffect(int)
3804      */
3805     public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3806     /**
3807      * Focus has moved left
3808      * @see #playSoundEffect(int)
3809      */
3810     public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3811     /**
3812      * Focus has moved right
3813      * @see #playSoundEffect(int)
3814      */
3815     public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3816     /**
3817      * IME standard keypress sound
3818      * @see #playSoundEffect(int)
3819      */
3820     public static final int FX_KEYPRESS_STANDARD = 5;
3821     /**
3822      * IME spacebar keypress sound
3823      * @see #playSoundEffect(int)
3824      */
3825     public static final int FX_KEYPRESS_SPACEBAR = 6;
3826     /**
3827      * IME delete keypress sound
3828      * @see #playSoundEffect(int)
3829      */
3830     public static final int FX_KEYPRESS_DELETE = 7;
3831     /**
3832      * IME return_keypress sound
3833      * @see #playSoundEffect(int)
3834      */
3835     public static final int FX_KEYPRESS_RETURN = 8;
3836 
3837     /**
3838      * Invalid keypress sound
3839      * @see #playSoundEffect(int)
3840      */
3841     public static final int FX_KEYPRESS_INVALID = 9;
3842 
3843     /**
3844      * Back sound
3845      * @see #playSoundEffect(int)
3846      */
3847     public static final int FX_BACK = 10;
3848 
3849     /**
3850      * @hide Home sound
3851      * <p>
3852      * To be played by the framework when the home app becomes active if config_enableHomeSound is
3853      * set to true. This is currently only used on TV devices.
3854      * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3855      * @see #playSoundEffect(int)
3856      */
3857     public static final int FX_HOME = 11;
3858 
3859     /**
3860      * @hide Navigation repeat sound 1
3861      * <p>
3862      * To be played by the framework when a focus navigation is repeatedly triggered
3863      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3864      * This is currently only used on TV devices.
3865      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3866      * @see #playSoundEffect(int)
3867      */
3868     public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
3869 
3870     /**
3871      * @hide Navigation repeat sound 2
3872      * <p>
3873      * To be played by the framework when a focus navigation is repeatedly triggered
3874      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3875      * This is currently only used on TV devices.
3876      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3877      * @see #playSoundEffect(int)
3878      */
3879     public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
3880 
3881     /**
3882      * @hide Navigation repeat sound 3
3883      * <p>
3884      * To be played by the framework when a focus navigation is repeatedly triggered
3885      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3886      * This is currently only used on TV devices.
3887      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3888      * @see #playSoundEffect(int)
3889      */
3890     public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
3891 
3892     /**
3893      * @hide Navigation repeat sound 4
3894      * <p>
3895      * To be played by the framework when a focus navigation is repeatedly triggered
3896      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3897      * This is currently only used on TV devices.
3898      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3899      * @see #playSoundEffect(int)
3900      */
3901     public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
3902 
3903     /**
3904      * @hide Number of sound effects
3905      */
3906     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3907     public static final int NUM_SOUND_EFFECTS = 16;
3908 
3909     /** @hide */
3910     @IntDef(prefix = { "FX_" }, value = {
3911             FX_KEY_CLICK,
3912             FX_FOCUS_NAVIGATION_UP,
3913             FX_FOCUS_NAVIGATION_DOWN,
3914             FX_FOCUS_NAVIGATION_LEFT,
3915             FX_FOCUS_NAVIGATION_RIGHT,
3916             FX_KEYPRESS_STANDARD,
3917             FX_KEYPRESS_SPACEBAR,
3918             FX_KEYPRESS_DELETE,
3919             FX_KEYPRESS_RETURN,
3920             FX_KEYPRESS_INVALID,
3921             FX_BACK
3922     })
3923     @Retention(RetentionPolicy.SOURCE)
3924     public @interface SystemSoundEffect {}
3925 
3926     /**
3927      * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
3928      */
3929     public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
3930 
3931     /**
3932      * @hide
3933      * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3934      * @return The id of a navigation repeat sound effect or -1 if out of bounds
3935      */
getNthNavigationRepeatSoundEffect(int n)3936     public static int getNthNavigationRepeatSoundEffect(int n) {
3937         switch (n) {
3938             case 0:
3939                 return FX_FOCUS_NAVIGATION_REPEAT_1;
3940             case 1:
3941                 return FX_FOCUS_NAVIGATION_REPEAT_2;
3942             case 2:
3943                 return FX_FOCUS_NAVIGATION_REPEAT_3;
3944             case 3:
3945                 return FX_FOCUS_NAVIGATION_REPEAT_4;
3946             default:
3947                 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
3948                 return -1;
3949         }
3950     }
3951 
3952     /**
3953      * @hide
3954      */
setNavigationRepeatSoundEffectsEnabled(boolean enabled)3955     public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
3956         try {
3957             getService().setNavigationRepeatSoundEffectsEnabled(enabled);
3958         } catch (RemoteException e) {
3959 
3960         }
3961     }
3962 
3963     /**
3964      * @hide
3965      * @return true if the navigation repeat sound effects are enabled
3966      */
areNavigationRepeatSoundEffectsEnabled()3967     public boolean areNavigationRepeatSoundEffectsEnabled() {
3968         try {
3969             return getService().areNavigationRepeatSoundEffectsEnabled();
3970         } catch (RemoteException e) {
3971             throw e.rethrowFromSystemServer();
3972         }
3973     }
3974 
3975     /**
3976      * @hide
3977      * @param enabled
3978      */
setHomeSoundEffectEnabled(boolean enabled)3979     public void setHomeSoundEffectEnabled(boolean enabled) {
3980         try {
3981             getService().setHomeSoundEffectEnabled(enabled);
3982         } catch (RemoteException e) {
3983 
3984         }
3985     }
3986 
3987     /**
3988      * @hide
3989      * @return true if the home sound effect is enabled
3990      */
isHomeSoundEffectEnabled()3991     public boolean isHomeSoundEffectEnabled() {
3992         try {
3993             return getService().isHomeSoundEffectEnabled();
3994         } catch (RemoteException e) {
3995             throw e.rethrowFromSystemServer();
3996         }
3997     }
3998 
3999     /**
4000      * Plays a sound effect (Key clicks, lid open/close...)
4001      * @param effectType The type of sound effect.
4002      * NOTE: This version uses the UI settings to determine
4003      * whether sounds are heard or not.
4004      */
playSoundEffect(@ystemSoundEffect int effectType)4005     public void playSoundEffect(@SystemSoundEffect int effectType) {
4006         playSoundEffect(effectType, UserHandle.USER_CURRENT);
4007     }
4008 
4009     /**
4010      * Plays a sound effect (Key clicks, lid open/close...)
4011      * @param effectType The type of sound effect.
4012      * @param userId The current user to pull sound settings from
4013      * NOTE: This version uses the UI settings to determine
4014      * whether sounds are heard or not.
4015      * @hide
4016      */
playSoundEffect(@ystemSoundEffect int effectType, int userId)4017     public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
4018         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
4019             return;
4020         }
4021 
4022         if (delegateSoundEffectToVdm(effectType)) {
4023             return;
4024         }
4025 
4026         final IAudioService service = getService();
4027         try {
4028             service.playSoundEffect(effectType, userId);
4029         } catch (RemoteException e) {
4030             throw e.rethrowFromSystemServer();
4031         }
4032     }
4033 
4034     /**
4035      * Plays a sound effect (Key clicks, lid open/close...)
4036      * @param effectType The type of sound effect.
4037      * @param volume Sound effect volume.
4038      * The volume value is a raw scalar so UI controls should be scaled logarithmically.
4039      * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
4040      * NOTE: This version is for applications that have their own
4041      * settings panel for enabling and controlling volume.
4042      */
playSoundEffect(@ystemSoundEffect int effectType, float volume)4043     public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
4044         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
4045             return;
4046         }
4047 
4048         if (delegateSoundEffectToVdm(effectType)) {
4049             return;
4050         }
4051 
4052         final IAudioService service = getService();
4053         try {
4054             service.playSoundEffectVolume(effectType, volume);
4055         } catch (RemoteException e) {
4056             throw e.rethrowFromSystemServer();
4057         }
4058     }
4059 
4060     /**
4061      * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
4062      * configured with custom device policy for audio. If there is such device, request to play
4063      * sound effect is forwarded to {@link VirtualDeviceManager}.
4064      *
4065      * @param effectType - The type of sound effect.
4066      * @return true if the request was forwarded to {@link VirtualDeviceManager} instance,
4067      * false otherwise.
4068      */
delegateSoundEffectToVdm(@ystemSoundEffect int effectType)4069     private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
4070         if (hasCustomPolicyVirtualDeviceContext()) {
4071             VirtualDeviceManager vdm = getVirtualDeviceManager();
4072             vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
4073             return true;
4074         }
4075         return false;
4076     }
4077 
hasCustomPolicyVirtualDeviceContext()4078     private boolean hasCustomPolicyVirtualDeviceContext() {
4079         if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
4080             return false;
4081         }
4082 
4083         VirtualDeviceManager vdm = getVirtualDeviceManager();
4084         return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
4085                 != DEVICE_POLICY_DEFAULT;
4086     }
4087 
4088     /**
4089      *  Load Sound effects.
4090      *  This method must be called when sound effects are enabled.
4091      */
loadSoundEffects()4092     public void loadSoundEffects() {
4093         final IAudioService service = getService();
4094         try {
4095             service.loadSoundEffects();
4096         } catch (RemoteException e) {
4097             throw e.rethrowFromSystemServer();
4098         }
4099     }
4100 
4101     /**
4102      *  Unload Sound effects.
4103      *  This method can be called to free some memory when
4104      *  sound effects are disabled.
4105      */
unloadSoundEffects()4106     public void unloadSoundEffects() {
4107         final IAudioService service = getService();
4108         try {
4109             service.unloadSoundEffects();
4110         } catch (RemoteException e) {
4111             throw e.rethrowFromSystemServer();
4112         }
4113     }
4114 
4115     /**
4116      * @hide
4117      */
audioFocusToString(int focus)4118     public static String audioFocusToString(int focus) {
4119         switch (focus) {
4120             case AUDIOFOCUS_NONE:
4121                 return "AUDIOFOCUS_NONE";
4122             case AUDIOFOCUS_GAIN:
4123                 return "AUDIOFOCUS_GAIN";
4124             case AUDIOFOCUS_GAIN_TRANSIENT:
4125                 return "AUDIOFOCUS_GAIN_TRANSIENT";
4126             case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
4127                 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
4128             case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
4129                 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
4130             case AUDIOFOCUS_LOSS:
4131                 return "AUDIOFOCUS_LOSS";
4132             case AUDIOFOCUS_LOSS_TRANSIENT:
4133                 return "AUDIOFOCUS_LOSS_TRANSIENT";
4134             case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
4135                 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
4136             default:
4137                 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
4138         }
4139     }
4140 
4141     /**
4142      * Used to indicate no audio focus has been gained or lost, or requested.
4143      */
4144     public static final int AUDIOFOCUS_NONE = 0;
4145 
4146     /**
4147      * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
4148      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4149      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4150      */
4151     public static final int AUDIOFOCUS_GAIN = 1;
4152     /**
4153      * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
4154      * amount of time. Examples of temporary changes are the playback of driving directions, or an
4155      * event notification.
4156      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4157      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4158      */
4159     public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
4160     /**
4161      * Used to indicate a temporary request of audio focus, anticipated to last a short
4162      * amount of time, and where it is acceptable for other audio applications to keep playing
4163      * after having lowered their output level (also referred to as "ducking").
4164      * Examples of temporary changes are the playback of driving directions where playback of music
4165      * in the background is acceptable.
4166      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4167      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4168      */
4169     public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
4170     /**
4171      * Used to indicate a temporary request of audio focus, anticipated to last a short
4172      * amount of time, during which no other applications, or system components, should play
4173      * anything. Examples of exclusive and transient audio focus requests are voice
4174      * memo recording and speech recognition, during which the system shouldn't play any
4175      * notifications, and media playback should have paused.
4176      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
4177      */
4178     public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
4179     /**
4180      * Used to indicate a loss of audio focus of unknown duration.
4181      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4182      */
4183     public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
4184     /**
4185      * Used to indicate a transient loss of audio focus.
4186      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4187      */
4188     public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
4189     /**
4190      * Used to indicate a transient loss of audio focus where the loser of the audio focus can
4191      * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
4192      * the new focus owner doesn't require others to be silent.
4193      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
4194      */
4195     public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
4196             -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
4197 
4198     /**
4199      * Interface definition for a callback to be invoked when the audio focus of the system is
4200      * updated.
4201      */
4202     public interface OnAudioFocusChangeListener {
4203         /**
4204          * Called on the listener to notify it the audio focus for this listener has been changed.
4205          * The focusChange value indicates whether the focus was gained,
4206          * whether the focus was lost, and whether that loss is transient, or whether the new focus
4207          * holder will hold it for an unknown amount of time.
4208          * When losing focus, listeners can use the focus change information to decide what
4209          * behavior to adopt when losing focus. A music player could for instance elect to lower
4210          * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
4211          * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
4212          *   {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
4213          *   and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
4214          */
onAudioFocusChange(int focusChange)4215         public void onAudioFocusChange(int focusChange);
4216     }
4217 
4218     /**
4219      * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
4220      */
4221     private static class FocusRequestInfo {
4222         @NonNull  final AudioFocusRequest mRequest;
4223         @Nullable final Handler mHandler;
FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)4224         FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
4225             mRequest = afr;
4226             mHandler = handler;
4227         }
4228     }
4229 
4230     /**
4231      * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
4232      * to actual listener objects.
4233      */
4234     @UnsupportedAppUsage
4235     private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
4236             new ConcurrentHashMap<String, FocusRequestInfo>();
4237 
findFocusRequestInfo(String id)4238     private FocusRequestInfo findFocusRequestInfo(String id) {
4239         return mAudioFocusIdListenerMap.get(id);
4240     }
4241 
4242     /**
4243      * Handler for events (audio focus change, recording config change) coming from the
4244      * audio service.
4245      */
4246     private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
4247             new ServiceEventHandlerDelegate(null);
4248 
4249     /**
4250      * Event types
4251      */
4252     private final static int MSSG_FOCUS_CHANGE = 0;
4253     private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
4254     private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
4255 
4256     /**
4257      * Helper class to handle the forwarding of audio service events to the appropriate listener
4258      */
4259     private class ServiceEventHandlerDelegate {
4260         private final Handler mHandler;
4261 
ServiceEventHandlerDelegate(Handler handler)4262         ServiceEventHandlerDelegate(Handler handler) {
4263             Looper looper;
4264             if (handler == null) {
4265                 if ((looper = Looper.myLooper()) == null) {
4266                     looper = Looper.getMainLooper();
4267                 }
4268             } else {
4269                 looper = handler.getLooper();
4270             }
4271 
4272             if (looper != null) {
4273                 // implement the event handler delegate to receive events from audio service
4274                 mHandler = new Handler(looper) {
4275                     @Override
4276                     public void handleMessage(Message msg) {
4277                         switch (msg.what) {
4278                             case MSSG_FOCUS_CHANGE: {
4279                                 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
4280                                 if (fri != null)  {
4281                                     final OnAudioFocusChangeListener listener =
4282                                             fri.mRequest.getOnAudioFocusChangeListener();
4283                                     if (listener != null) {
4284                                         Log.d(TAG, "dispatching onAudioFocusChange("
4285                                                 + msg.arg1 + ") to " + msg.obj);
4286                                         listener.onAudioFocusChange(msg.arg1);
4287                                     }
4288                                 }
4289                             } break;
4290                             case MSSG_RECORDING_CONFIG_CHANGE: {
4291                                 final RecordConfigChangeCallbackData cbData =
4292                                         (RecordConfigChangeCallbackData) msg.obj;
4293                                 if (cbData.mCb != null) {
4294                                     cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
4295                                 }
4296                             } break;
4297                             case MSSG_PLAYBACK_CONFIG_CHANGE: {
4298                                 final PlaybackConfigChangeCallbackData cbData =
4299                                         (PlaybackConfigChangeCallbackData) msg.obj;
4300                                 if (cbData.mCb != null) {
4301                                     if (DEBUG) {
4302                                         Log.d(TAG, "dispatching onPlaybackConfigChanged()");
4303                                     }
4304                                     cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
4305                                 }
4306                             } break;
4307                             default:
4308                                 Log.e(TAG, "Unknown event " + msg.what);
4309                         }
4310                     }
4311                 };
4312             } else {
4313                 mHandler = null;
4314             }
4315         }
4316 
getHandler()4317         Handler getHandler() {
4318             return mHandler;
4319         }
4320     }
4321 
4322     private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
4323         @Override
4324         public void dispatchAudioFocusChange(int focusChange, String id) {
4325             final FocusRequestInfo fri = findFocusRequestInfo(id);
4326             if (fri != null)  {
4327                 final OnAudioFocusChangeListener listener =
4328                         fri.mRequest.getOnAudioFocusChangeListener();
4329                 if (listener != null) {
4330                     final Handler h = (fri.mHandler == null) ?
4331                             mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
4332                     final Message m = h.obtainMessage(
4333                             MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
4334                             id/*obj*/);
4335                     h.sendMessage(m);
4336                 }
4337             }
4338         }
4339 
4340         @Override
4341         public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
4342             synchronized (mFocusRequestsLock) {
4343                 // TODO use generation counter as the key instead
4344                 final BlockingFocusResultReceiver focusReceiver =
4345                         mFocusRequestsAwaitingResult.remove(clientId);
4346                 if (focusReceiver != null) {
4347                     focusReceiver.notifyResult(requestResult);
4348                 } else {
4349                     Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
4350                 }
4351             }
4352         }
4353     };
4354 
getIdForAudioFocusListener(OnAudioFocusChangeListener l)4355     private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
4356         if (l == null) {
4357             return new String(this.toString());
4358         } else {
4359             return new String(this.toString() + l.toString());
4360         }
4361     }
4362 
4363     /**
4364      * @hide
4365      * Registers a listener to be called when audio focus changes and keeps track of the associated
4366      * focus request (including Handler to use for the listener).
4367      * @param afr the full request parameters
4368      */
registerAudioFocusRequest(@onNull AudioFocusRequest afr)4369     public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
4370         final Handler h = afr.getOnAudioFocusChangeListenerHandler();
4371         final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
4372             new ServiceEventHandlerDelegate(h).getHandler());
4373         final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4374         mAudioFocusIdListenerMap.put(key, fri);
4375     }
4376 
4377     /**
4378      * @hide
4379      * Causes the specified listener to not be called anymore when focus is gained or lost.
4380      * @param l the listener to unregister.
4381      */
unregisterAudioFocusRequest(OnAudioFocusChangeListener l)4382     public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
4383         // remove locally
4384         mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
4385     }
4386 
4387 
4388     /**
4389      * A failed focus change request.
4390      */
4391     public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
4392     /**
4393      * A successful focus change request.
4394      */
4395     public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
4396      /**
4397       * A focus change request whose granting is delayed: the request was successful, but the
4398       * requester will only be granted audio focus once the condition that prevented immediate
4399       * granting has ended.
4400       * See {@link #requestAudioFocus(AudioFocusRequest)} and
4401       * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
4402       */
4403     public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
4404 
4405     /** @hide */
4406     @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
4407             AUDIOFOCUS_REQUEST_FAILED,
4408             AUDIOFOCUS_REQUEST_GRANTED,
4409             AUDIOFOCUS_REQUEST_DELAYED }
4410     )
4411     @Retention(RetentionPolicy.SOURCE)
4412     public @interface FocusRequestResult {}
4413 
4414     /**
4415      * @hide
4416      * code returned when a synchronous focus request on the client-side is to be blocked
4417      * until the external audio focus policy decides on the response for the client
4418      */
4419     public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
4420 
4421     /**
4422      * Timeout duration in ms when waiting on an external focus policy for the result for a
4423      * focus request
4424      */
4425     private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250;
4426 
4427     private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
4428 
4429     private final Object mFocusRequestsLock = new Object();
4430     /**
4431      * Map of all receivers of focus request results, one per unresolved focus request.
4432      * Receivers are added before sending the request to the external focus policy,
4433      * and are removed either after receiving the result, or after the timeout.
4434      * This variable is lazily initialized.
4435      */
4436     @GuardedBy("mFocusRequestsLock")
4437     private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
4438 
4439 
4440     /**
4441      *  Request audio focus.
4442      *  Send a request to obtain the audio focus
4443      *  @param l the listener to be notified of audio focus changes
4444      *  @param streamType the main audio stream type affected by the focus request
4445      *  @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4446      *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
4447      *      for the playback of driving directions, or notifications sounds.
4448      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4449      *      the previous focus owner to keep playing if it ducks its audio output.
4450      *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4451      *      that benefits from the system not playing disruptive sounds like notifications, for
4452      *      usecases such as voice memo recording, or speech recognition.
4453      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4454      *      as the playback of a song or a video.
4455      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4456      *  @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
4457      */
requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)4458     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
4459         PlayerBase.deprecateStreamTypeForPlayback(streamType,
4460                 "AudioManager", "requestAudioFocus()");
4461         int status = AUDIOFOCUS_REQUEST_FAILED;
4462 
4463         try {
4464             // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
4465             // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
4466             // AUDIOFOCUS_FLAG_DELAY_OK flag
4467             status = requestAudioFocus(l,
4468                     new AudioAttributes.Builder()
4469                             .setInternalLegacyStreamType(streamType).build(),
4470                     durationHint,
4471                     0 /* flags, legacy behavior */);
4472         } catch (IllegalArgumentException e) {
4473             Log.e(TAG, "Audio focus request denied due to ", e);
4474         }
4475 
4476         return status;
4477     }
4478 
4479     // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
4480     /**
4481      * @hide
4482      * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
4483      * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
4484      * the system is in a state where focus cannot change, but be granted focus later when
4485      * this condition ends.
4486      */
4487     @SystemApi
4488     public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
4489     /**
4490      * @hide
4491      * Use this flag when requesting audio focus to indicate that the requester
4492      * will pause its media playback (if applicable) when losing audio focus with
4493      * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
4494      * <br>On some platforms, the ducking may be handled without the application being aware of it
4495      * (i.e. it will not transiently lose focus). For applications that for instance play spoken
4496      * content, such as audio book or podcast players, ducking may never be acceptable, and will
4497      * thus always pause. This flag enables them to be declared as such whenever they request focus.
4498      */
4499     @SystemApi
4500     public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
4501     /**
4502      * @hide
4503      * Use this flag to lock audio focus so granting is temporarily disabled.
4504      * <br>This flag can only be used by owners of a registered
4505      * {@link android.media.audiopolicy.AudioPolicy} in
4506      * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
4507      */
4508     @SystemApi
4509     public static final int AUDIOFOCUS_FLAG_LOCK     = 0x1 << 2;
4510 
4511     /**
4512      * @hide
4513      * flag set on test API calls,
4514      * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
4515      */
4516     public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
4517     /** @hide */
4518     public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4519             | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
4520     /** @hide */
4521     public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
4522             | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
4523 
4524     /**
4525      * Request audio focus.
4526      * See the {@link AudioFocusRequest} for information about the options available to configure
4527      * your request, and notification of focus gain and loss.
4528      * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4529      *   requested.
4530      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4531      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4532      *     <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4533      *     is requested without building the {@link AudioFocusRequest} with
4534      *     {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4535      *     {@code true}.
4536      * @throws NullPointerException if passed a null argument
4537      */
requestAudioFocus(@onNull AudioFocusRequest focusRequest)4538     public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
4539         return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
4540     }
4541 
4542     /**
4543      *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4544      *  @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4545      *      with {@link #requestAudioFocus(AudioFocusRequest)}.
4546      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4547      *  @throws IllegalArgumentException if passed a null argument
4548      */
abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4549     public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4550         if (focusRequest == null) {
4551             throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4552         }
4553         return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4554                 focusRequest.getAudioAttributes());
4555     }
4556 
4557     /**
4558      * @hide
4559      * Request audio focus.
4560      * Send a request to obtain the audio focus. This method differs from
4561      * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4562      * that the requester accepts delayed grants of audio focus.
4563      * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4564      *     when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4565      * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4566      *     requesting audio focus.
4567      * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4568      *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
4569      *      for the playback of driving directions, or notifications sounds.
4570      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4571      *      the previous focus owner to keep playing if it ducks its audio output.
4572      *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4573      *      that benefits from the system not playing disruptive sounds like notifications, for
4574      *      usecases such as voice memo recording, or speech recognition.
4575      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4576      *      as the playback of a song or a video.
4577      * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4578      *     {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
4579      *     <br>Use 0 when not using any flags for the request, which behaves like
4580      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4581      *     focus is granted immediately, or the grant request fails because the system is in a
4582      *     state where focus cannot change (e.g. a phone call).
4583      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4584      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4585      *     The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4586      *     without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4587      * @throws IllegalArgumentException
4588      */
4589     @SystemApi
4590     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)4591     public int requestAudioFocus(OnAudioFocusChangeListener l,
4592             @NonNull AudioAttributes requestAttributes,
4593             int durationHint,
4594             int flags) throws IllegalArgumentException {
4595         if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4596             throw new IllegalArgumentException("Invalid flags 0x"
4597                     + Integer.toHexString(flags).toUpperCase());
4598         }
4599         return requestAudioFocus(l, requestAttributes, durationHint,
4600                 flags & AUDIOFOCUS_FLAGS_APPS,
4601                 null /* no AudioPolicy*/);
4602     }
4603 
4604     /**
4605      * @hide
4606      * Request or lock audio focus.
4607      * This method is to be used by system components that have registered an
4608      * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4609      * so focus granting is temporarily disabled.
4610      * @param l see the description of the same parameter in
4611      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4612      * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4613      *     requesting audio focus.
4614      * @param durationHint see the description of the same parameter in
4615      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4616      * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4617      *     {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
4618      *     <br>Use 0 when not using any flags for the request, which behaves like
4619      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4620      *     focus is granted immediately, or the grant request fails because the system is in a
4621      *     state where focus cannot change (e.g. a phone call).
4622      * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4623      *     focus, or null.
4624      * @return see the description of the same return value in
4625      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4626      * @throws IllegalArgumentException
4627      * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
4628      */
4629     @SystemApi
4630     @RequiresPermission(anyOf= {
4631             Manifest.permission.MODIFY_PHONE_STATE,
4632             Manifest.permission.MODIFY_AUDIO_ROUTING
4633     })
requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)4634     public int requestAudioFocus(OnAudioFocusChangeListener l,
4635             @NonNull AudioAttributes requestAttributes,
4636             int durationHint,
4637             int flags,
4638             AudioPolicy ap) throws IllegalArgumentException {
4639         // parameter checking
4640         if (requestAttributes == null) {
4641             throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4642         }
4643         if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
4644             throw new IllegalArgumentException("Invalid duration hint");
4645         }
4646         if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
4647             throw new IllegalArgumentException("Illegal flags 0x"
4648                 + Integer.toHexString(flags).toUpperCase());
4649         }
4650         if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4651             throw new IllegalArgumentException(
4652                     "Illegal null focus listener when flagged as accepting delayed focus grant");
4653         }
4654         if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4655                 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4656             throw new IllegalArgumentException(
4657                     "Illegal null focus listener when flagged as pausing instead of ducking");
4658         }
4659         if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4660             throw new IllegalArgumentException(
4661                     "Illegal null audio policy when locking audio focus");
4662         }
4663 
4664         final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
4665                 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
4666                 .setAudioAttributes(requestAttributes)
4667                 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4668                         == AUDIOFOCUS_FLAG_DELAY_OK)
4669                 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4670                         == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4671                 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4672                 .build();
4673         return requestAudioFocus(afr, ap);
4674     }
4675 
4676     /**
4677      * @hide
4678      * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4679      * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4680      * @param afr the parameters of the request
4681      * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4682      * @param clientFakeUid the UID of the client, here an arbitrary int,
4683      *                      doesn't have to be a real UID
4684      * @param clientTargetSdk the target SDK used by the client
4685      * @return return code indicating status of the request
4686      */
4687     @TestApi
4688     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4689     public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4690             @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4691         Objects.requireNonNull(afr);
4692         Objects.requireNonNull(clientFakeId);
4693         int status;
4694         BlockingFocusResultReceiver focusReceiver;
4695         synchronized (mFocusRequestsLock) {
4696             try {
4697                 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4698                         afr.getFocusGain(),
4699                         mICallBack,
4700                         mAudioFocusDispatcher,
4701                         clientFakeId, "com.android.test.fakeclient",
4702                         afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST,
4703                         clientFakeUid, clientTargetSdk);
4704             } catch (RemoteException e) {
4705                 throw e.rethrowFromSystemServer();
4706             }
4707             if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4708                 // default path with no external focus policy
4709                 return status;
4710             }
4711 
4712             focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId);
4713         }
4714 
4715         return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver);
4716     }
4717 
4718     /**
4719      * @hide
4720      * Test API to abandon audio focus for an arbitrary client.
4721      * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4722      * @param afr the parameters used for the request
4723      * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4724      *      would be requesting
4725      * @return return code indicating status of the request
4726      */
4727     @TestApi
4728     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4729     public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4730             @NonNull String clientFakeId) {
4731         Objects.requireNonNull(afr);
4732         Objects.requireNonNull(clientFakeId);
4733         try {
4734             return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4735                     clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4736         } catch (RemoteException e) {
4737             throw e.rethrowFromSystemServer();
4738         }
4739     }
4740 
4741     /**
4742      * @hide
4743      * Return the duration of the fade out applied when a player of the given AudioAttributes
4744      * is losing audio focus
4745      * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4746      * @return a duration in ms, 0 indicates no fade out is applied
4747      */
4748     @TestApi
4749     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4750     public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4751     {
4752         Objects.requireNonNull(aa);
4753         try {
4754             return getService().getFadeOutDurationOnFocusLossMillis(aa);
4755         } catch (RemoteException e) {
4756             throw e.rethrowFromSystemServer();
4757         }
4758     }
4759 
4760     /**
4761      * @hide
4762      * Test method to return the list of UIDs currently marked as ducked because of their
4763      * audio focus status
4764      * @return the list of UIDs, can be empty when no app is being ducked.
4765      */
4766     @TestApi
4767     @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
4768     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getFocusDuckedUidsForTest()4769     public @NonNull List<Integer> getFocusDuckedUidsForTest() {
4770         try {
4771             return getService().getFocusDuckedUidsForTest();
4772         } catch (RemoteException e) {
4773             throw e.rethrowFromSystemServer();
4774         }
4775     }
4776 
4777     /**
4778      * @hide
4779      * Test method to return the duration of the fade out applied on the players of a focus loser
4780      * @return the fade out duration in ms
4781      */
4782     @TestApi
4783     @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
4784     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getFocusFadeOutDurationForTest()4785     public long getFocusFadeOutDurationForTest() {
4786         try {
4787             return getService().getFocusFadeOutDurationForTest();
4788         } catch (RemoteException e) {
4789             throw e.rethrowFromSystemServer();
4790         }
4791     }
4792 
4793     /**
4794      * @hide
4795      * Test method to return the length of time after a fade-out before the focus loser is unmuted
4796      * (and is faded back in).
4797      * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms.
4798      */
4799     @TestApi
4800     @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
4801     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getFocusUnmuteDelayAfterFadeOutForTest()4802     public long getFocusUnmuteDelayAfterFadeOutForTest() {
4803         try {
4804             return getService().getFocusUnmuteDelayAfterFadeOutForTest();
4805         } catch (RemoteException e) {
4806             throw e.rethrowFromSystemServer();
4807         }
4808     }
4809 
4810     /**
4811      * @hide
4812      * Test method to start preventing applications from requesting audio focus during a test,
4813      * which could interfere with the functionality/behavior under test.
4814      * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest}
4815      * when the testing is done. If this is not the case (e.g. in case of a test crash),
4816      * a death observer mechanism will ensure the system is not left in a bad state, but this should
4817      * not be relied on when implementing tests.
4818      * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance
4819      *     be those of the test runner and other players used in the test, or the "fake" UIDs used
4820      *     for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}.
4821      * @return true if the focus freeze mode is successfully entered, false if there was an issue,
4822      *     such as another freeze in place at the time of invocation.
4823      *     A false result should result in a test failure as this would indicate the system is not
4824      *     in a proper state with a predictable behavior for audio focus management.
4825      */
4826     @TestApi
4827     @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
4828     @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
enterAudioFocusFreezeForTest(@onNull List<Integer> exemptedUids)4829     public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) {
4830         Objects.requireNonNull(exemptedUids);
4831         try {
4832             final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray();
4833             return getService().enterAudioFocusFreezeForTest(mICallBack, uids);
4834         } catch (RemoteException e) {
4835             throw e.rethrowFromSystemServer();
4836         }
4837     }
4838 
4839     /**
4840      * @hide
4841      * Test method to end preventing applications from requesting audio focus during a test.
4842      * @return true if the focus freeze mode is successfully exited, false if there was an issue,
4843      *     such as the freeze already having ended, or not started.
4844      */
4845     @TestApi
4846     @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API)
4847     @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED")
exitAudioFocusFreezeForTest()4848     public boolean exitAudioFocusFreezeForTest() {
4849         try {
4850             return getService().exitAudioFocusFreezeForTest(mICallBack);
4851         } catch (RemoteException e) {
4852             throw e.rethrowFromSystemServer();
4853         }
4854     }
4855 
4856     /**
4857      * @hide
4858      * Request or lock audio focus.
4859      * This method is to be used by system components that have registered an
4860      * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4861      * so focus granting is temporarily disabled.
4862      * @param afr see the description of the same parameter in
4863      *     {@link #requestAudioFocus(AudioFocusRequest)}
4864      * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4865      *     focus, or null.
4866      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4867      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4868      * @throws NullPointerException if the AudioFocusRequest is null
4869      * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4870      */
4871     @SystemApi
4872     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)4873     public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4874         if (afr == null) {
4875             throw new NullPointerException("Illegal null AudioFocusRequest");
4876         }
4877         // this can only be checked now, not during the creation of the AudioFocusRequest instance
4878         if (afr.locksFocus() && ap == null) {
4879             throw new IllegalArgumentException(
4880                     "Illegal null audio policy when locking audio focus");
4881         }
4882 
4883         if (hasCustomPolicyVirtualDeviceContext()) {
4884             // If the focus request was made within context associated with VirtualDevice
4885             // configured with custom device policy for audio, bypass audio service focus handling.
4886             // The custom device policy for audio means that audio associated with this device
4887             // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
4888             // shouldn't affect non-virtual audio tracks (and vice versa).
4889             return AUDIOFOCUS_REQUEST_GRANTED;
4890         }
4891 
4892         registerAudioFocusRequest(afr);
4893         final IAudioService service = getService();
4894         final int status;
4895         int sdk;
4896         try {
4897             sdk = getContext().getApplicationInfo().targetSdkVersion;
4898         } catch (NullPointerException e) {
4899             // some tests don't have a Context
4900             sdk = Build.VERSION.SDK_INT;
4901         }
4902 
4903         final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4904         BlockingFocusResultReceiver focusReceiver;
4905         synchronized (mFocusRequestsLock) {
4906 
4907             try {
4908                 // TODO status contains result and generation counter for ext policy
4909                 status = service.requestAudioFocus(afr.getAudioAttributes(),
4910                         afr.getFocusGain(), mICallBack,
4911                         mAudioFocusDispatcher,
4912                         clientId,
4913                         getContext().getOpPackageName() /* package name */,
4914                         getContext().getAttributionTag(),
4915                         afr.getFlags(),
4916                         ap != null ? ap.cb() : null,
4917                         sdk);
4918             } catch (RemoteException e) {
4919                 throw e.rethrowFromSystemServer();
4920             }
4921             if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4922                 // default path with no external focus policy
4923                 return status;
4924             }
4925             focusReceiver = addClientIdToFocusReceiverLocked(clientId);
4926         }
4927 
4928         return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver);
4929     }
4930 
4931     @GuardedBy("mFocusRequestsLock")
addClientIdToFocusReceiverLocked(String clientId)4932     private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) {
4933         BlockingFocusResultReceiver focusReceiver;
4934         if (mFocusRequestsAwaitingResult == null) {
4935             mFocusRequestsAwaitingResult =
4936                     new HashMap<String, BlockingFocusResultReceiver>(1);
4937         }
4938         focusReceiver = new BlockingFocusResultReceiver(clientId);
4939         mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4940         return focusReceiver;
4941     }
4942 
handleExternalAudioPolicyWaitIfNeeded(String clientId, BlockingFocusResultReceiver focusReceiver)4943     private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId,
4944             BlockingFocusResultReceiver focusReceiver) {
4945         focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4946         if (DEBUG && !focusReceiver.receivedResult()) {
4947             Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded"
4948                     + " response from ext policy timed out, denying request");
4949         }
4950 
4951         synchronized (mFocusRequestsLock) {
4952             mFocusRequestsAwaitingResult.remove(clientId);
4953         }
4954         return focusReceiver.requestResult();
4955     }
4956 
4957     // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4958     private static final class SafeWaitObject {
4959         private boolean mQuit = false;
4960 
safeNotify()4961         public void safeNotify() {
4962             synchronized (this) {
4963                 mQuit = true;
4964                 this.notify();
4965             }
4966         }
4967 
safeWait(long millis)4968         public void safeWait(long millis) throws InterruptedException {
4969             final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4970             synchronized (this) {
4971                 while (!mQuit) {
4972                     final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4973                     if (timeToWait <= 0) {
4974                         break;
4975                     }
4976                     this.wait(timeToWait);
4977                 }
4978             }
4979         }
4980     }
4981 
4982     private static final class BlockingFocusResultReceiver {
4983         private final SafeWaitObject mLock = new SafeWaitObject();
4984         @GuardedBy("mLock")
4985         private boolean mResultReceived = false;
4986         // request denied by default (e.g. timeout)
4987         private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4988         private final String mFocusClientId;
4989 
BlockingFocusResultReceiver(String clientId)4990         BlockingFocusResultReceiver(String clientId) {
4991             mFocusClientId = clientId;
4992         }
4993 
receivedResult()4994         boolean receivedResult() { return mResultReceived; }
requestResult()4995         int requestResult() { return mFocusRequestResult; }
4996 
notifyResult(int requestResult)4997         void notifyResult(int requestResult) {
4998             synchronized (mLock) {
4999                 mResultReceived = true;
5000                 mFocusRequestResult = requestResult;
5001                 mLock.safeNotify();
5002             }
5003         }
5004 
waitForResult(long timeOutMs)5005         public void waitForResult(long timeOutMs) {
5006             synchronized (mLock) {
5007                 if (mResultReceived) {
5008                     // the result was received before waiting
5009                     return;
5010                 }
5011                 try {
5012                     mLock.safeWait(timeOutMs);
5013                 } catch (InterruptedException e) { }
5014             }
5015         }
5016     }
5017 
5018     /**
5019      * @hide
5020      * Used internally by telephony package to request audio focus. Will cause the focus request
5021      * to be associated with the "voice communication" identifier only used in AudioService
5022      * to identify this use case.
5023      * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
5024      *    the establishment of the call
5025      * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
5026      *    media applications resume after a call
5027      */
5028     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
requestAudioFocusForCall(int streamType, int durationHint)5029     public void requestAudioFocusForCall(int streamType, int durationHint) {
5030         final IAudioService service = getService();
5031         try {
5032             service.requestAudioFocus(new AudioAttributes.Builder()
5033                         .setInternalLegacyStreamType(streamType).build(),
5034                     durationHint, mICallBack, null,
5035                     AudioSystem.IN_VOICE_COMM_FOCUS_ID,
5036                     getContext().getOpPackageName(),
5037                     getContext().getAttributionTag(),
5038                     AUDIOFOCUS_FLAG_LOCK,
5039                     null /* policy token */, 0 /* sdk n/a here*/);
5040         } catch (RemoteException e) {
5041             throw e.rethrowFromSystemServer();
5042         }
5043     }
5044 
5045     /**
5046      * @hide
5047      * Return the volume ramping time for a sound to be played after the given focus request,
5048      *   and to play a sound of the given attributes
5049      * @param focusGain
5050      * @param attr
5051      * @return
5052      */
getFocusRampTimeMs(int focusGain, AudioAttributes attr)5053     public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
5054         final IAudioService service = getService();
5055         try {
5056             return service.getFocusRampTimeMs(focusGain, attr);
5057         } catch (RemoteException e) {
5058             throw e.rethrowFromSystemServer();
5059         }
5060     }
5061 
5062     /**
5063      * @hide
5064      * Set the result to the audio focus request received through
5065      * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
5066      * @param afi the information about the focus requester
5067      * @param requestResult the result to the focus request to be passed to the requester
5068      * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5069      */
5070     @SystemApi
5071     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)5072     public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
5073             @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
5074         if (afi == null) {
5075             throw new IllegalArgumentException("Illegal null AudioFocusInfo");
5076         }
5077         if (ap == null) {
5078             throw new IllegalArgumentException("Illegal null AudioPolicy");
5079         }
5080         final IAudioService service = getService();
5081         try {
5082             service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
5083         } catch (RemoteException e) {
5084             throw e.rethrowFromSystemServer();
5085         }
5086     }
5087 
5088     /**
5089      * @hide
5090      * Notifies an application with a focus listener of gain or loss of audio focus.
5091      * This method can only be used by owners of an {@link AudioPolicy} configured with
5092      * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
5093      * @param afi the recipient of the focus change, that has previously requested audio focus, and
5094      *     that was received by the {@code AudioPolicy} through
5095      *     {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
5096      * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
5097      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
5098      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
5099      *     or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
5100      *     {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
5101      *     or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
5102      *     <br>For the focus gain, the change type should be the same as the app requested.
5103      * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5104      * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
5105      *     {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
5106      *     if there was an error sending the request.
5107      * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
5108      */
5109     @SystemApi
5110     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)5111     public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
5112             @NonNull AudioPolicy ap) {
5113         if (afi == null) {
5114             throw new NullPointerException("Illegal null AudioFocusInfo");
5115         }
5116         if (ap == null) {
5117             throw new NullPointerException("Illegal null AudioPolicy");
5118         }
5119         final IAudioService service = getService();
5120         try {
5121             return service.dispatchFocusChange(afi, focusChange, ap.cb());
5122         } catch (RemoteException e) {
5123             throw e.rethrowFromSystemServer();
5124         }
5125     }
5126 
5127     /**
5128      * Notifies an application with a focus listener of gain or loss of audio focus
5129      *
5130      * <p>This is similar to {@link #dispatchAudioFocusChange(AudioFocusInfo, int, AudioPolicy)} but
5131      * with additional functionality  of fade. The players of the application with  audio focus
5132      * change, provided they meet the active {@link FadeManagerConfiguration} requirements, are
5133      * faded before dispatching the callback to the application. For example, players of the
5134      * application losing audio focus will be faded out, whereas players of the application gaining
5135      * audio focus will be faded in, if needed.
5136      *
5137      * <p>The applicability of fade is decided against the supplied active {@link AudioFocusInfo}.
5138      * This list cannot be {@code null}. The list can be empty if no other active
5139      * {@link AudioFocusInfo} available at the time of the dispatch.
5140      *
5141      * <p>The {@link FadeManagerConfiguration} supplied here is prioritized over existing fade
5142      * configurations. If none supplied, either the {@link FadeManagerConfiguration} set through
5143      * {@link AudioPolicy} or the default will be used to determine the fade properties.
5144      *
5145      * <p>This method can only be used by owners of an {@link AudioPolicy} configured with
5146      * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
5147      *
5148      * @param afi the recipient of the focus change, that has previously requested audio focus, and
5149      *     that was received by the {@code AudioPolicy} through
5150      *     {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}
5151      * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
5152      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
5153      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
5154      *     or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
5155      *     {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
5156      *     or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
5157      *     <br>For the focus gain, the change type should be the same as the app requested
5158      * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
5159      * @param otherActiveAfis active {@link AudioFocusInfo} that are granted audio focus at the time
5160      *     of dispatch
5161      * @param transientFadeMgrConfig {@link FadeManagerConfiguration} that will be used for fading
5162      *     players resulting from this dispatch. This is a transient configuration that is only
5163      *     valid for this focus change and shall be discarded after processing this request.
5164      * @return {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener or if
5165      *     there was an error sending the request, or {@link #AUDIOFOCUS_REQUEST_GRANTED} if the
5166      *     dispatch was successfully sent, or {@link #AUDIOFOCUS_REQUEST_DELAYED} if
5167      *     the request was successful but the dispatch of focus change was delayed due to a fade
5168      *     operation.
5169      * @hide
5170      */
5171     @FlaggedApi(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION)
5172     @SystemApi
5173     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
5174     @FocusRequestResult
dispatchAudioFocusChangeWithFade(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis, @Nullable FadeManagerConfiguration transientFadeMgrConfig)5175     public int dispatchAudioFocusChangeWithFade(@NonNull AudioFocusInfo afi, int focusChange,
5176             @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis,
5177             @Nullable FadeManagerConfiguration transientFadeMgrConfig) {
5178         Objects.requireNonNull(afi, "AudioFocusInfo cannot be null");
5179         Objects.requireNonNull(ap, "AudioPolicy cannot be null");
5180         Objects.requireNonNull(otherActiveAfis, "Other active AudioFocusInfo list cannot be null");
5181 
5182         IAudioService service = getService();
5183         try {
5184             return service.dispatchFocusChangeWithFade(afi, focusChange, ap.cb(), otherActiveAfis,
5185                     transientFadeMgrConfig);
5186         } catch (RemoteException e) {
5187             throw e.rethrowFromSystemServer();
5188         }
5189     }
5190 
5191     /**
5192      * @hide
5193      * Used internally by telephony package to abandon audio focus, typically after a call or
5194      * when ringing ends and the call is rejected or not answered.
5195      * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
5196      */
5197     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
abandonAudioFocusForCall()5198     public void abandonAudioFocusForCall() {
5199         final IAudioService service = getService();
5200         try {
5201             service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
5202                     null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
5203         } catch (RemoteException e) {
5204             throw e.rethrowFromSystemServer();
5205         }
5206     }
5207 
5208     /**
5209      *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
5210      *  @param l the listener with which focus was requested.
5211      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
5212      *  @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
5213      */
abandonAudioFocus(OnAudioFocusChangeListener l)5214     public int abandonAudioFocus(OnAudioFocusChangeListener l) {
5215         return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
5216     }
5217 
5218     /**
5219      * @hide
5220      * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
5221      *  @param l the listener with which focus was requested.
5222      * @param aa the {@link AudioAttributes} with which audio focus was requested
5223      * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
5224      * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
5225      */
5226     @SystemApi
5227     @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
5228     // have been done by a matching requestAudioFocus
abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)5229     public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
5230         if (hasCustomPolicyVirtualDeviceContext()) {
5231             // If this AudioManager instance is running within VirtualDevice context configured
5232             // with custom device policy for audio, the audio focus handling is bypassed.
5233             return AUDIOFOCUS_REQUEST_GRANTED;
5234         }
5235         unregisterAudioFocusRequest(l);
5236         final IAudioService service = getService();
5237         try {
5238             return service.abandonAudioFocus(mAudioFocusDispatcher,
5239                     getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
5240         } catch (RemoteException e) {
5241             throw e.rethrowFromSystemServer();
5242         }
5243     }
5244 
5245     //====================================================================
5246     // Remote Control
5247     /**
5248      * Register a component to be the sole receiver of MEDIA_BUTTON intents.
5249      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5250      *      that will receive the media button intent. This broadcast receiver must be declared
5251      *      in the application manifest. The package of the component must match that of
5252      *      the context you're registering from.
5253      * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
5254      */
5255     @Deprecated
registerMediaButtonEventReceiver(ComponentName eventReceiver)5256     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
5257         if (eventReceiver == null) {
5258             return;
5259         }
5260         if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
5261             Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
5262                     "receiver and context package names don't match");
5263             return;
5264         }
5265         // construct a PendingIntent for the media button and register it
5266         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5267         //     the associated intent will be handled by the component being registered
5268         mediaButtonIntent.setComponent(eventReceiver);
5269         PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5270                 0/*requestCode, ignored*/, mediaButtonIntent,
5271                 PendingIntent.FLAG_IMMUTABLE);
5272         registerMediaButtonIntent(pi, eventReceiver);
5273     }
5274 
5275     /**
5276      * Register a component to be the sole receiver of MEDIA_BUTTON intents.  This is like
5277      * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
5278      * the buttons to go to any PendingIntent.  Note that you should only use this form if
5279      * you know you will continue running for the full time until unregistering the
5280      * PendingIntent.
5281      * @param eventReceiver target that will receive media button intents.  The PendingIntent
5282      * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
5283      * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
5284      * media button that was pressed.
5285      * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
5286      */
5287     @Deprecated
registerMediaButtonEventReceiver(PendingIntent eventReceiver)5288     public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
5289         if (eventReceiver == null) {
5290             return;
5291         }
5292         registerMediaButtonIntent(eventReceiver, null);
5293     }
5294 
5295     /**
5296      * @hide
5297      * no-op if (pi == null) or (eventReceiver == null)
5298      */
registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)5299     public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
5300         if (pi == null) {
5301             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
5302             return;
5303         }
5304         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
5305         helper.addMediaButtonListener(pi, eventReceiver, getContext());
5306     }
5307 
5308     /**
5309      * Unregister the receiver of MEDIA_BUTTON intents.
5310      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
5311      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
5312      * @deprecated Use {@link MediaSession} instead.
5313      */
5314     @Deprecated
unregisterMediaButtonEventReceiver(ComponentName eventReceiver)5315     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
5316         if (eventReceiver == null) {
5317             return;
5318         }
5319         // construct a PendingIntent for the media button and unregister it
5320         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
5321         //     the associated intent will be handled by the component being registered
5322         mediaButtonIntent.setComponent(eventReceiver);
5323         PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5324                 0/*requestCode, ignored*/, mediaButtonIntent,
5325                 PendingIntent.FLAG_IMMUTABLE);
5326         unregisterMediaButtonIntent(pi);
5327     }
5328 
5329     /**
5330      * Unregister the receiver of MEDIA_BUTTON intents.
5331      * @param eventReceiver same PendingIntent that was registed with
5332      *      {@link #registerMediaButtonEventReceiver(PendingIntent)}.
5333      * @deprecated Use {@link MediaSession} instead.
5334      */
5335     @Deprecated
unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)5336     public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
5337         if (eventReceiver == null) {
5338             return;
5339         }
5340         unregisterMediaButtonIntent(eventReceiver);
5341     }
5342 
5343     /**
5344      * @hide
5345      */
unregisterMediaButtonIntent(PendingIntent pi)5346     public void unregisterMediaButtonIntent(PendingIntent pi) {
5347         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
5348         helper.removeMediaButtonListener(pi);
5349     }
5350 
5351     /**
5352      * Registers the remote control client for providing information to display on the remote
5353      * controls.
5354      * @param rcClient The remote control client from which remote controls will receive
5355      *      information to display.
5356      * @see RemoteControlClient
5357      * @deprecated Use {@link MediaSession} instead.
5358      */
5359     @Deprecated
registerRemoteControlClient(RemoteControlClient rcClient)5360     public void registerRemoteControlClient(RemoteControlClient rcClient) {
5361         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
5362             return;
5363         }
5364         rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
5365     }
5366 
5367     /**
5368      * Unregisters the remote control client that was providing information to display on the
5369      * remote controls.
5370      * @param rcClient The remote control client to unregister.
5371      * @see #registerRemoteControlClient(RemoteControlClient)
5372      * @deprecated Use {@link MediaSession} instead.
5373      */
5374     @Deprecated
unregisterRemoteControlClient(RemoteControlClient rcClient)5375     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
5376         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
5377             return;
5378         }
5379         rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
5380     }
5381 
5382     /**
5383      * Registers a {@link RemoteController} instance for it to receive media
5384      * metadata updates and playback state information from applications using
5385      * {@link RemoteControlClient}, and control their playback.
5386      * <p>
5387      * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
5388      * one of the enabled notification listeners (see
5389      * {@link android.service.notification.NotificationListenerService}).
5390      *
5391      * @param rctlr the object to register.
5392      * @return true if the {@link RemoteController} was successfully registered,
5393      *         false if an error occurred, due to an internal system error, or
5394      *         insufficient permissions.
5395      * @deprecated Use
5396      *             {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
5397      *             and {@link MediaController} instead.
5398      */
5399     @Deprecated
registerRemoteController(RemoteController rctlr)5400     public boolean registerRemoteController(RemoteController rctlr) {
5401         if (rctlr == null) {
5402             return false;
5403         }
5404         rctlr.startListeningToSessions();
5405         return true;
5406     }
5407 
5408     /**
5409      * Unregisters a {@link RemoteController}, causing it to no longer receive
5410      * media metadata and playback state information, and no longer be capable
5411      * of controlling playback.
5412      *
5413      * @param rctlr the object to unregister.
5414      * @deprecated Use
5415      *             {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
5416      *             instead.
5417      */
5418     @Deprecated
unregisterRemoteController(RemoteController rctlr)5419     public void unregisterRemoteController(RemoteController rctlr) {
5420         if (rctlr == null) {
5421             return;
5422         }
5423         rctlr.stopListeningToSessions();
5424     }
5425 
5426 
5427     //====================================================================
5428     // Audio policy
5429     /**
5430      * @hide
5431      * Register the given {@link AudioPolicy}.
5432      * This call is synchronous and blocks until the registration process successfully completed
5433      * or failed to complete.
5434      * @param policy the non-null {@link AudioPolicy} to register.
5435      * @return {@link #ERROR} if there was an error communicating with the registration service
5436      *    or if the user doesn't have the required
5437      *    {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
5438      *    {@link #SUCCESS} otherwise.
5439      */
5440     @SystemApi
5441     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
registerAudioPolicy(@onNull AudioPolicy policy)5442     public int registerAudioPolicy(@NonNull AudioPolicy policy) {
5443         return registerAudioPolicyStatic(policy);
5444     }
5445 
registerAudioPolicyStatic(@onNull AudioPolicy policy)5446     static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
5447         if (policy == null) {
5448             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5449         }
5450         final IAudioService service = getService();
5451         try {
5452             MediaProjection projection = policy.getMediaProjection();
5453             String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
5454                     policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
5455                     policy.isVolumeController(),
5456                     projection == null ? null : projection.getProjection(),
5457                     policy.getAttributionSource());
5458             if (regId == null) {
5459                 return ERROR;
5460             } else {
5461                 policy.setRegistration(regId);
5462             }
5463             // successful registration
5464         } catch (RemoteException e) {
5465             throw e.rethrowFromSystemServer();
5466         }
5467         return SUCCESS;
5468     }
5469 
5470     /**
5471      * @hide
5472      * Unregisters an {@link AudioPolicy} asynchronously.
5473      * @param policy the non-null {@link AudioPolicy} to unregister.
5474      */
5475     @SystemApi
5476     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
unregisterAudioPolicyAsync(@onNull AudioPolicy policy)5477     public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
5478         unregisterAudioPolicyAsyncStatic(policy);
5479     }
5480 
unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)5481     static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
5482         if (policy == null) {
5483             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
5484         }
5485         final IAudioService service = getService();
5486         try {
5487             service.unregisterAudioPolicyAsync(policy.cb());
5488             policy.reset();
5489         } catch (RemoteException e) {
5490             throw e.rethrowFromSystemServer();
5491         }
5492     }
5493 
5494     /**
5495      * @hide
5496      * Unregisters an {@link AudioPolicy} synchronously.
5497      * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
5498      * associated with mixes of this policy.
5499      * @param policy the non-null {@link AudioPolicy} to unregister.
5500      */
5501     @SystemApi
5502     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
unregisterAudioPolicy(@onNull AudioPolicy policy)5503     public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
5504         Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
5505         final IAudioService service = getService();
5506         try {
5507             policy.invalidateCaptorsAndInjectors();
5508             service.unregisterAudioPolicy(policy.cb());
5509             policy.reset();
5510         } catch (RemoteException e) {
5511             throw e.rethrowFromSystemServer();
5512         }
5513     }
5514 
5515     /**
5516      * @hide
5517      * @return All currently registered audio policy mixes.
5518      */
5519     @TestApi
5520     @FlaggedApi(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API)
5521     @NonNull
getRegisteredPolicyMixes()5522     public List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes() {
5523         if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
5524             return Collections.emptyList();
5525         }
5526 
5527         final IAudioService service = getService();
5528         try {
5529             return service.getRegisteredPolicyMixes();
5530         } catch (RemoteException e) {
5531             throw e.rethrowFromSystemServer();
5532         }
5533     }
5534 
5535     /**
5536      * @hide
5537      * @return true if an AudioPolicy was previously registered
5538      */
5539     @TestApi
hasRegisteredDynamicPolicy()5540     public boolean hasRegisteredDynamicPolicy() {
5541         final IAudioService service = getService();
5542         try {
5543             return service.hasRegisteredDynamicPolicy();
5544         } catch (RemoteException e) {
5545             throw e.rethrowFromSystemServer();
5546         }
5547     }
5548 
5549     //====================================================================
5550     // Notification of playback activity & playback configuration
5551     /**
5552      * Interface for receiving update notifications about the playback activity on the system.
5553      * Extend this abstract class and register it with
5554      * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
5555      * to be notified.
5556      * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
5557      * configuration.
5558      * @see AudioPlaybackConfiguration
5559      */
5560     public static abstract class AudioPlaybackCallback {
5561         /**
5562          * Called whenever the playback activity and configuration has changed.
5563          * @param configs list containing the results of
5564          *      {@link AudioManager#getActivePlaybackConfigurations()}.
5565          */
onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)5566         public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
5567     }
5568 
5569     private static class AudioPlaybackCallbackInfo {
5570         final AudioPlaybackCallback mCb;
5571         final Handler mHandler;
AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)5572         AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
5573             mCb = cb;
5574             mHandler = handler;
5575         }
5576     }
5577 
5578     private final static class PlaybackConfigChangeCallbackData {
5579         final AudioPlaybackCallback mCb;
5580         final List<AudioPlaybackConfiguration> mConfigs;
5581 
PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)5582         PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
5583                 List<AudioPlaybackConfiguration> configs) {
5584             mCb = cb;
5585             mConfigs = configs;
5586         }
5587     }
5588 
5589     /**
5590      * Register a callback to be notified of audio playback changes through
5591      * {@link AudioPlaybackCallback}
5592      * @param cb non-null callback to register
5593      * @param handler the {@link Handler} object for the thread on which to execute
5594      * the callback. If <code>null</code>, the {@link Handler} associated with the main
5595      * {@link Looper} will be used.
5596      */
registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)5597     public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
5598                                               @Nullable Handler handler)
5599     {
5600         if (cb == null) {
5601             throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5602         }
5603 
5604         synchronized(mPlaybackCallbackLock) {
5605             // lazy initialization of the list of playback callbacks
5606             if (mPlaybackCallbackList == null) {
5607                 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
5608             }
5609             final int oldCbCount = mPlaybackCallbackList.size();
5610             if (!hasPlaybackCallback_sync(cb)) {
5611                 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
5612                         new ServiceEventHandlerDelegate(handler).getHandler()));
5613                 final int newCbCount = mPlaybackCallbackList.size();
5614                 if ((oldCbCount == 0) && (newCbCount > 0)) {
5615                     // register binder for callbacks
5616                     try {
5617                         getService().registerPlaybackCallback(mPlayCb);
5618                     } catch (RemoteException e) {
5619                         throw e.rethrowFromSystemServer();
5620                     }
5621                 }
5622             } else {
5623                 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
5624                         + "registered callback");
5625             }
5626         }
5627     }
5628 
5629     /**
5630      * Unregister an audio playback callback previously registered with
5631      * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5632      * @param cb non-null callback to unregister
5633      */
unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)5634     public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
5635         if (cb == null) {
5636             throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
5637         }
5638         synchronized(mPlaybackCallbackLock) {
5639             if (mPlaybackCallbackList == null) {
5640                 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5641                         + " that was never registered");
5642                 return;
5643             }
5644             final int oldCbCount = mPlaybackCallbackList.size();
5645             if (removePlaybackCallback_sync(cb)) {
5646                 final int newCbCount = mPlaybackCallbackList.size();
5647                 if ((oldCbCount > 0) && (newCbCount == 0)) {
5648                     // unregister binder for callbacks
5649                     try {
5650                         getService().unregisterPlaybackCallback(mPlayCb);
5651                     } catch (RemoteException e) {
5652                         throw e.rethrowFromSystemServer();
5653                     }
5654                 }
5655             } else {
5656                 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
5657                         + " already unregistered or never registered");
5658             }
5659         }
5660     }
5661 
5662     /**
5663      * Returns the current active audio playback configurations of the device
5664      * @return a non-null list of playback configurations. An empty list indicates there is no
5665      *     playback active when queried.
5666      * @see AudioPlaybackConfiguration
5667      */
getActivePlaybackConfigurations()5668     public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
5669         final IAudioService service = getService();
5670         try {
5671             return service.getActivePlaybackConfigurations();
5672         } catch (RemoteException e) {
5673             throw e.rethrowFromSystemServer();
5674         }
5675     }
5676 
5677     /**
5678      * All operations on this list are sync'd on mPlaybackCallbackLock.
5679      * List is lazy-initialized in
5680      * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
5681      * List can be null.
5682      */
5683     private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
5684     private final Object mPlaybackCallbackLock = new Object();
5685 
5686     /**
5687      * Must be called synchronized on mPlaybackCallbackLock
5688      */
hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5689     private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5690         if (mPlaybackCallbackList != null) {
5691             for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5692                 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5693                     return true;
5694                 }
5695             }
5696         }
5697         return false;
5698     }
5699 
5700     /**
5701      * Must be called synchronized on mPlaybackCallbackLock
5702      */
removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5703     private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
5704         if (mPlaybackCallbackList != null) {
5705             for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5706                 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
5707                     mPlaybackCallbackList.remove(i);
5708                     return true;
5709                 }
5710             }
5711         }
5712         return false;
5713     }
5714 
5715     private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
5716         @Override
5717         public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
5718                 boolean flush) {
5719             if (flush) {
5720                 Binder.flushPendingCommands();
5721             }
5722             synchronized(mPlaybackCallbackLock) {
5723                 if (mPlaybackCallbackList != null) {
5724                     for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
5725                         final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
5726                         if (arci.mHandler != null) {
5727                             final Message m = arci.mHandler.obtainMessage(
5728                                     MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
5729                                     new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5730                             arci.mHandler.sendMessage(m);
5731                         }
5732                     }
5733                 }
5734             }
5735         }
5736 
5737     };
5738 
5739     //====================================================================
5740     // Notification of recording activity & recording configuration
5741     /**
5742      * Interface for receiving update notifications about the recording configuration. Extend
5743      * this abstract class and register it with
5744      * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5745      * to be notified.
5746      * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5747      * configuration.
5748      * @see AudioRecordingConfiguration
5749      */
5750     public static abstract class AudioRecordingCallback {
5751         /**
5752          * Called whenever the device recording configuration has changed.
5753          * @param configs list containing the results of
5754          *      {@link AudioManager#getActiveRecordingConfigurations()}.
5755          */
onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)5756         public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
5757     }
5758 
5759     private static class AudioRecordingCallbackInfo {
5760         final AudioRecordingCallback mCb;
5761         final Handler mHandler;
AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5762         AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5763             mCb = cb;
5764             mHandler = handler;
5765         }
5766     }
5767 
5768     private final static class RecordConfigChangeCallbackData {
5769         final AudioRecordingCallback mCb;
5770         final List<AudioRecordingConfiguration> mConfigs;
5771 
RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5772         RecordConfigChangeCallbackData(AudioRecordingCallback cb,
5773                 List<AudioRecordingConfiguration> configs) {
5774             mCb = cb;
5775             mConfigs = configs;
5776         }
5777     }
5778 
5779     /**
5780      * Register a callback to be notified of audio recording changes through
5781      * {@link AudioRecordingCallback}
5782      * @param cb non-null callback to register
5783      * @param handler the {@link Handler} object for the thread on which to execute
5784      * the callback. If <code>null</code>, the {@link Handler} associated with the main
5785      * {@link Looper} will be used.
5786      */
registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5787     public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5788                                                @Nullable Handler handler)
5789     {
5790         if (cb == null) {
5791             throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5792         }
5793 
5794         synchronized(mRecordCallbackLock) {
5795             // lazy initialization of the list of recording callbacks
5796             if (mRecordCallbackList == null) {
5797                 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
5798             }
5799             final int oldCbCount = mRecordCallbackList.size();
5800             if (!hasRecordCallback_sync(cb)) {
5801                 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5802                         new ServiceEventHandlerDelegate(handler).getHandler()));
5803                 final int newCbCount = mRecordCallbackList.size();
5804                 if ((oldCbCount == 0) && (newCbCount > 0)) {
5805                     // register binder for callbacks
5806                     final IAudioService service = getService();
5807                     try {
5808                         service.registerRecordingCallback(mRecCb);
5809                     } catch (RemoteException e) {
5810                         throw e.rethrowFromSystemServer();
5811                     }
5812                 }
5813             } else {
5814                 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5815                         + "registered callback");
5816             }
5817         }
5818     }
5819 
5820     /**
5821      * Unregister an audio recording callback previously registered with
5822      * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5823      * @param cb non-null callback to unregister
5824      */
unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5825     public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5826         if (cb == null) {
5827             throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5828         }
5829         synchronized(mRecordCallbackLock) {
5830             if (mRecordCallbackList == null) {
5831                 return;
5832             }
5833             final int oldCbCount = mRecordCallbackList.size();
5834             if (removeRecordCallback_sync(cb)) {
5835                 final int newCbCount = mRecordCallbackList.size();
5836                 if ((oldCbCount > 0) && (newCbCount == 0)) {
5837                     // unregister binder for callbacks
5838                     final IAudioService service = getService();
5839                     try {
5840                         service.unregisterRecordingCallback(mRecCb);
5841                     } catch (RemoteException e) {
5842                         throw e.rethrowFromSystemServer();
5843                     }
5844                 }
5845             } else {
5846                 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5847                         + " already unregistered or never registered");
5848             }
5849         }
5850     }
5851 
5852     /**
5853      * Returns the current active audio recording configurations of the device.
5854      * @return a non-null list of recording configurations. An empty list indicates there is
5855      *     no recording active when queried.
5856      * @see AudioRecordingConfiguration
5857      */
getActiveRecordingConfigurations()5858     public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
5859         final IAudioService service = getService();
5860         try {
5861             return service.getActiveRecordingConfigurations();
5862         } catch (RemoteException e) {
5863             throw e.rethrowFromSystemServer();
5864         }
5865     }
5866 
5867     /**
5868      * constants for the recording events, to keep in sync
5869      * with frameworks/av/include/media/AudioPolicy.h
5870      */
5871     /** @hide */
5872     public static final int RECORD_CONFIG_EVENT_NONE = -1;
5873     /** @hide */
5874     public static final int RECORD_CONFIG_EVENT_START = 0;
5875     /** @hide */
5876     public static final int RECORD_CONFIG_EVENT_STOP = 1;
5877     /** @hide */
5878     public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5879     /** @hide */
5880     public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
5881     /**
5882      * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5883      */
5884     /** @hide */
5885     public static final int RECORD_RIID_INVALID = -1;
5886     /** @hide */
5887     public static final int RECORDER_STATE_STARTED = 0;
5888     /** @hide */
5889     public static final int RECORDER_STATE_STOPPED = 1;
5890 
5891     /**
5892      * All operations on this list are sync'd on mRecordCallbackLock.
5893      * List is lazy-initialized in
5894      * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5895      * List can be null.
5896      */
5897     private List<AudioRecordingCallbackInfo> mRecordCallbackList;
5898     private final Object mRecordCallbackLock = new Object();
5899 
5900     /**
5901      * Must be called synchronized on mRecordCallbackLock
5902      */
hasRecordCallback_sync(@onNull AudioRecordingCallback cb)5903     private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5904         if (mRecordCallbackList != null) {
5905             for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5906                 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5907                     return true;
5908                 }
5909             }
5910         }
5911         return false;
5912     }
5913 
5914     /**
5915      * Must be called synchronized on mRecordCallbackLock
5916      */
removeRecordCallback_sync(@onNull AudioRecordingCallback cb)5917     private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5918         if (mRecordCallbackList != null) {
5919             for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5920                 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5921                     mRecordCallbackList.remove(i);
5922                     return true;
5923                 }
5924             }
5925         }
5926         return false;
5927     }
5928 
5929     private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
5930         @Override
5931         public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
5932             synchronized(mRecordCallbackLock) {
5933                 if (mRecordCallbackList != null) {
5934                     for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5935                         final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5936                         if (arci.mHandler != null) {
5937                             final Message m = arci.mHandler.obtainMessage(
5938                                     MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5939                                     new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5940                             arci.mHandler.sendMessage(m);
5941                         }
5942                     }
5943                 }
5944             }
5945         }
5946 
5947     };
5948 
5949     //=====================================================================
5950 
5951     /**
5952      *  @hide
5953      *  Reload audio settings. This method is called by Settings backup
5954      *  agent when audio settings are restored and causes the AudioService
5955      *  to read and apply restored settings.
5956      */
5957     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
reloadAudioSettings()5958     public void reloadAudioSettings() {
5959         final IAudioService service = getService();
5960         try {
5961             service.reloadAudioSettings();
5962         } catch (RemoteException e) {
5963             throw e.rethrowFromSystemServer();
5964         }
5965     }
5966 
5967      /**
5968       * {@hide}
5969       */
5970      private final IBinder mICallBack = new Binder();
5971 
5972     /**
5973      * Checks whether the phone is in silent mode, with or without vibrate.
5974      *
5975      * @return true if phone is in silent mode, with or without vibrate.
5976      *
5977      * @see #getRingerMode()
5978      *
5979      * @hide pending API Council approval
5980      */
5981     @UnsupportedAppUsage
isSilentMode()5982     public boolean isSilentMode() {
5983         int ringerMode = getRingerMode();
5984         boolean silentMode =
5985             (ringerMode == RINGER_MODE_SILENT) ||
5986             (ringerMode == RINGER_MODE_VIBRATE);
5987         return silentMode;
5988     }
5989 
5990     // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5991     // class is not used by other parts of the framework, which instead use definitions and methods
5992     // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5993 
5994     /** @hide
5995      * The audio device code for representing "no device." */
5996     public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5997     /** @hide
5998      *  The audio output device code for the small speaker at the front of the device used
5999      *  when placing calls.  Does not refer to an in-ear headphone without attached microphone,
6000      *  such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
6001      *  {@link #DEVICE_OUT_WIRED_HEADPHONE}.
6002      */
6003     @UnsupportedAppUsage
6004     public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
6005     /** @hide
6006      *  The audio output device code for the built-in speaker */
6007     @UnsupportedAppUsage
6008     public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
6009     /** @hide
6010      * The audio output device code for a wired headset with attached microphone */
6011     @UnsupportedAppUsage
6012     public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
6013     /** @hide
6014      * The audio output device code for a wired headphone without attached microphone */
6015     @UnsupportedAppUsage
6016     public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
6017     /** @hide
6018      * The audio output device code for a USB headphone with attached microphone */
6019     public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
6020     /** @hide
6021      * The audio output device code for generic Bluetooth SCO, for voice */
6022     public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
6023     /** @hide
6024      * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
6025      * Hands-Free Profile (HFP), for voice
6026      */
6027     @UnsupportedAppUsage
6028     public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
6029             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
6030     /** @hide
6031      * The audio output device code for Bluetooth SCO car audio, for voice */
6032     public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
6033             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
6034     /** @hide
6035      * The audio output device code for generic Bluetooth A2DP, for music */
6036     @UnsupportedAppUsage
6037     public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
6038     /** @hide
6039      * The audio output device code for Bluetooth A2DP headphones, for music */
6040     @UnsupportedAppUsage
6041     public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
6042             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
6043     /** @hide
6044      * The audio output device code for Bluetooth A2DP external speaker, for music */
6045     @UnsupportedAppUsage
6046     public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
6047             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
6048     /** @hide
6049      * The audio output device code for S/PDIF (legacy) or HDMI
6050      * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
6051     public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
6052     /** @hide
6053      * The audio output device code for HDMI */
6054     @UnsupportedAppUsage
6055     public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
6056     /** @hide
6057      * The audio output device code for an analog wired headset attached via a
6058      *  docking station
6059      */
6060     @UnsupportedAppUsage
6061     public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
6062     /** @hide
6063      * The audio output device code for a digital wired headset attached via a
6064      *  docking station
6065      */
6066     @UnsupportedAppUsage
6067     public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
6068     /** @hide
6069      * The audio output device code for a USB audio accessory. The accessory is in USB host
6070      * mode and the Android device in USB device mode
6071      */
6072     public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
6073     /** @hide
6074      * The audio output device code for a USB audio device. The device is in USB device
6075      * mode and the Android device in USB host mode
6076      */
6077     public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
6078     /** @hide
6079      * The audio output device code for projection output.
6080      */
6081     public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
6082     /** @hide
6083      * The audio output device code the telephony voice TX path.
6084      */
6085     public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
6086     /** @hide
6087      * The audio output device code for an analog jack with line impedance detected.
6088      */
6089     public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
6090     /** @hide
6091      * The audio output device code for HDMI Audio Return Channel.
6092      */
6093     public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
6094     /** @hide
6095      * The audio output device code for HDMI enhanced Audio Return Channel.
6096      */
6097     public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
6098     /** @hide
6099      * The audio output device code for S/PDIF digital connection.
6100      */
6101     public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
6102     /** @hide
6103      * The audio output device code for built-in FM transmitter.
6104      */
6105     public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
6106     /** @hide
6107      * The audio output device code for echo reference injection point.
6108      */
6109     public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
6110     /** @hide
6111      * The audio output device code for a BLE audio headset.
6112      */
6113     public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
6114     /** @hide
6115      * The audio output device code for a BLE audio speaker.
6116      */
6117     public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
6118     /** @hide
6119      * The audio output device code for a BLE audio brodcast group.
6120      */
6121     public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST;
6122     /** @hide
6123      * This is not used as a returned value from {@link #getDevicesForStream}, but could be
6124      *  used in the future in a set method to select whatever default device is chosen by the
6125      *  platform-specific implementation.
6126      */
6127     public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
6128 
6129     /** @hide
6130      * The audio input device code for default built-in microphone
6131      */
6132     public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
6133     /** @hide
6134      * The audio input device code for a Bluetooth SCO headset
6135      */
6136     public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
6137                                     AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
6138     /** @hide
6139      * The audio input device code for wired headset microphone
6140      */
6141     public static final int DEVICE_IN_WIRED_HEADSET =
6142                                     AudioSystem.DEVICE_IN_WIRED_HEADSET;
6143     /** @hide
6144      * The audio input device code for HDMI
6145      */
6146     public static final int DEVICE_IN_HDMI =
6147                                     AudioSystem.DEVICE_IN_HDMI;
6148     /** @hide
6149      * The audio input device code for HDMI ARC
6150      */
6151     public static final int DEVICE_IN_HDMI_ARC =
6152                                     AudioSystem.DEVICE_IN_HDMI_ARC;
6153 
6154     /** @hide
6155      * The audio input device code for HDMI EARC
6156      */
6157     public static final int DEVICE_IN_HDMI_EARC =
6158                                     AudioSystem.DEVICE_IN_HDMI_EARC;
6159 
6160     /** @hide
6161      * The audio input device code for telephony voice RX path
6162      */
6163     public static final int DEVICE_IN_TELEPHONY_RX =
6164                                     AudioSystem.DEVICE_IN_TELEPHONY_RX;
6165     /** @hide
6166      * The audio input device code for built-in microphone pointing to the back
6167      */
6168     public static final int DEVICE_IN_BACK_MIC =
6169                                     AudioSystem.DEVICE_IN_BACK_MIC;
6170     /** @hide
6171      * The audio input device code for analog from a docking station
6172      */
6173     public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
6174                                     AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
6175     /** @hide
6176      * The audio input device code for digital from a docking station
6177      */
6178     public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
6179                                     AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
6180     /** @hide
6181      * The audio input device code for a USB audio accessory. The accessory is in USB host
6182      * mode and the Android device in USB device mode
6183      */
6184     public static final int DEVICE_IN_USB_ACCESSORY =
6185                                     AudioSystem.DEVICE_IN_USB_ACCESSORY;
6186     /** @hide
6187      * The audio input device code for a USB audio device. The device is in USB device
6188      * mode and the Android device in USB host mode
6189      */
6190     public static final int DEVICE_IN_USB_DEVICE =
6191                                     AudioSystem.DEVICE_IN_USB_DEVICE;
6192     /** @hide
6193      * The audio input device code for a FM radio tuner
6194      */
6195     public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
6196     /** @hide
6197      * The audio input device code for a TV tuner
6198      */
6199     public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
6200     /** @hide
6201      * The audio input device code for an analog jack with line impedance detected
6202      */
6203     public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
6204     /** @hide
6205      * The audio input device code for a S/PDIF digital connection
6206      */
6207     public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
6208     /** @hide
6209      * The audio input device code for audio loopback
6210      */
6211     public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
6212     /** @hide
6213      * The audio input device code for an echo reference capture point.
6214      */
6215     public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
6216     /** @hide
6217      * The audio input device code for a BLE audio headset.
6218      */
6219     public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
6220 
6221     /**
6222      * Return true if the device code corresponds to an output device.
6223      * @hide
6224      */
isOutputDevice(int device)6225     public static boolean isOutputDevice(int device)
6226     {
6227         return !AudioSystem.isInputDevice(device);
6228     }
6229 
6230     /**
6231      * Return true if the device code corresponds to an input device.
6232      * @hide
6233      */
isInputDevice(int device)6234     public static boolean isInputDevice(int device)
6235     {
6236         return AudioSystem.isInputDevice(device);
6237     }
6238 
6239 
6240     /**
6241      * Return the enabled devices for the specified output stream type.
6242      *
6243      * @param streamType The stream type to query. One of
6244      *            {@link #STREAM_VOICE_CALL},
6245      *            {@link #STREAM_SYSTEM},
6246      *            {@link #STREAM_RING},
6247      *            {@link #STREAM_MUSIC},
6248      *            {@link #STREAM_ALARM},
6249      *            {@link #STREAM_NOTIFICATION},
6250      *            {@link #STREAM_DTMF},
6251      *            {@link #STREAM_ACCESSIBILITY}.
6252      *
6253      * @return The bit-mask "or" of audio output device codes for all enabled devices on this
6254      *         stream. Zero or more of
6255      *            {@link #DEVICE_OUT_EARPIECE},
6256      *            {@link #DEVICE_OUT_SPEAKER},
6257      *            {@link #DEVICE_OUT_WIRED_HEADSET},
6258      *            {@link #DEVICE_OUT_WIRED_HEADPHONE},
6259      *            {@link #DEVICE_OUT_BLUETOOTH_SCO},
6260      *            {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
6261      *            {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
6262      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP},
6263      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
6264      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
6265      *            {@link #DEVICE_OUT_HDMI},
6266      *            {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
6267      *            {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
6268      *            {@link #DEVICE_OUT_USB_ACCESSORY}.
6269      *            {@link #DEVICE_OUT_USB_DEVICE}.
6270      *            {@link #DEVICE_OUT_REMOTE_SUBMIX}.
6271      *            {@link #DEVICE_OUT_TELEPHONY_TX}.
6272      *            {@link #DEVICE_OUT_LINE}.
6273      *            {@link #DEVICE_OUT_HDMI_ARC}.
6274      *            {@link #DEVICE_OUT_HDMI_EARC}.
6275      *            {@link #DEVICE_OUT_SPDIF}.
6276      *            {@link #DEVICE_OUT_FM}.
6277      *            {@link #DEVICE_OUT_DEFAULT} is not used here.
6278      *
6279      * The implementation may support additional device codes beyond those listed, so
6280      * the application should ignore any bits which it does not recognize.
6281      * Note that the information may be imprecise when the implementation
6282      * cannot distinguish whether a particular device is enabled.
6283      *
6284      * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices
6285      *             will have multi-bit device types.
6286      *             Prefer to use {@link #getDevicesForAttributes()} instead,
6287      *             noting that getDevicesForStream() has a few small discrepancies
6288      *             for better volume handling.
6289      * @hide
6290      */
6291     @UnsupportedAppUsage
6292     @Deprecated
getDevicesForStream(int streamType)6293     public int getDevicesForStream(int streamType) {
6294         switch (streamType) {
6295             case STREAM_VOICE_CALL:
6296             case STREAM_SYSTEM:
6297             case STREAM_RING:
6298             case STREAM_MUSIC:
6299             case STREAM_ALARM:
6300             case STREAM_NOTIFICATION:
6301             case STREAM_DTMF:
6302             case STREAM_ACCESSIBILITY:
6303                 final IAudioService service = getService();
6304                 try {
6305                     return service.getDeviceMaskForStream(streamType);
6306                 } catch (RemoteException e) {
6307                     throw e.rethrowFromSystemServer();
6308                 }
6309             default:
6310                 return 0;
6311         }
6312     }
6313 
6314     /**
6315      * @hide
6316      * Get the audio devices that would be used for the routing of the given audio attributes.
6317      * @param attributes the {@link AudioAttributes} for which the routing is being queried
6318      * @return an empty list if there was an issue with the request, a list of audio devices
6319      *   otherwise (typically one device, except for duplicated paths).
6320      */
6321     @SystemApi
6322     @RequiresPermission(anyOf = {
6323             Manifest.permission.MODIFY_AUDIO_ROUTING,
6324             Manifest.permission.QUERY_AUDIO_STATE
6325     })
getDevicesForAttributes( @onNull AudioAttributes attributes)6326     public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
6327             @NonNull AudioAttributes attributes) {
6328         Objects.requireNonNull(attributes);
6329         final IAudioService service = getService();
6330         try {
6331             return service.getDevicesForAttributes(attributes);
6332         } catch (RemoteException e) {
6333             throw e.rethrowFromSystemServer();
6334         }
6335     }
6336 
6337     // Each listener corresponds to a unique callback stub because each listener can subscribe to
6338     // different AudioAttributes.
6339     private final ConcurrentHashMap<OnDevicesForAttributesChangedListener,
6340             IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub =
6341                     new ConcurrentHashMap<>();
6342 
6343     private static final class IDevicesForAttributesCallbackStub
6344             extends IDevicesForAttributesCallback.Stub {
6345         ListenerInfo<OnDevicesForAttributesChangedListener> mInfo;
6346 
IDevicesForAttributesCallbackStub(@onNull OnDevicesForAttributesChangedListener listener, @NonNull Executor executor)6347         IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener,
6348                 @NonNull Executor executor) {
6349             mInfo = new ListenerInfo<>(listener, executor);
6350         }
6351 
register(boolean register, AudioAttributes attributes)6352         public void register(boolean register, AudioAttributes attributes) {
6353             try {
6354                 if (register) {
6355                     getService().addOnDevicesForAttributesChangedListener(attributes, this);
6356                 } else {
6357                     getService().removeOnDevicesForAttributesChangedListener(this);
6358                 }
6359             } catch (RemoteException e) {
6360                 throw e.rethrowFromSystemServer();
6361             }
6362         }
6363 
6364         @Override
onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume, List<AudioDeviceAttributes> devices)6365         public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume,
6366                 List<AudioDeviceAttributes> devices) {
6367             // forVolume is ignored. The case where it is `true` is not handled.
6368             mInfo.mExecutor.execute(() ->
6369                     mInfo.mListener.onDevicesForAttributesChanged(
6370                             attributes, devices));
6371         }
6372     }
6373 
6374     /**
6375      * @hide
6376      * Interface to be notified of when routing changes for the registered audio attributes.
6377      */
6378     @SystemApi
6379     public interface OnDevicesForAttributesChangedListener {
6380         /**
6381          * Called on the listener to indicate that the audio devices for the given audio
6382          * attributes have changed.
6383          * @param attributes the {@link AudioAttributes} whose routing changed
6384          * @param devices a list of newly routed audio devices
6385          */
onDevicesForAttributesChanged(@onNull AudioAttributes attributes, @NonNull List<AudioDeviceAttributes> devices)6386         void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes,
6387                 @NonNull List<AudioDeviceAttributes> devices);
6388     }
6389 
6390     /**
6391      * @hide
6392      * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}.
6393      * @param attributes the {@link AudioAttributes} to listen for routing changes
6394      * @param executor
6395      * @param listener
6396      */
6397     @SystemApi
6398     @RequiresPermission(anyOf = {
6399             Manifest.permission.MODIFY_AUDIO_ROUTING,
6400             Manifest.permission.QUERY_AUDIO_STATE
6401     })
addOnDevicesForAttributesChangedListener(@onNull AudioAttributes attributes, @NonNull @CallbackExecutor Executor executor, @NonNull OnDevicesForAttributesChangedListener listener)6402     public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes,
6403             @NonNull @CallbackExecutor Executor executor,
6404             @NonNull OnDevicesForAttributesChangedListener listener) {
6405         Objects.requireNonNull(attributes);
6406         Objects.requireNonNull(executor);
6407         Objects.requireNonNull(listener);
6408 
6409         synchronized (mDevicesForAttributesListenerToStub) {
6410             IDevicesForAttributesCallbackStub callbackStub =
6411                     mDevicesForAttributesListenerToStub.get(listener);
6412 
6413             if (callbackStub == null) {
6414                 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor);
6415                 mDevicesForAttributesListenerToStub.put(listener, callbackStub);
6416             }
6417 
6418             callbackStub.register(true, attributes);
6419         }
6420     }
6421 
6422     /**
6423      * @hide
6424      * Removes a previously registered listener for being notified of routing changes for the given
6425      * {@link AudioAttributes}.
6426      * @param listener
6427      */
6428     @SystemApi
6429     @RequiresPermission(anyOf = {
6430             Manifest.permission.MODIFY_AUDIO_ROUTING,
6431             Manifest.permission.QUERY_AUDIO_STATE
6432     })
removeOnDevicesForAttributesChangedListener( @onNull OnDevicesForAttributesChangedListener listener)6433     public void removeOnDevicesForAttributesChangedListener(
6434             @NonNull OnDevicesForAttributesChangedListener listener) {
6435         Objects.requireNonNull(listener);
6436 
6437         synchronized (mDevicesForAttributesListenerToStub) {
6438             IDevicesForAttributesCallbackStub callbackStub =
6439                     mDevicesForAttributesListenerToStub.get(listener);
6440             if (callbackStub != null) {
6441                 callbackStub.register(false, null /* attributes */);
6442             }
6443 
6444             mDevicesForAttributesListenerToStub.remove(listener);
6445         }
6446     }
6447 
6448     /**
6449      * Get the audio devices that would be used for the routing of the given audio attributes.
6450      * These are the devices anticipated to play sound from an {@link AudioTrack} created with
6451      * the specified {@link AudioAttributes}.
6452      * The audio routing can change if audio devices are physically connected or disconnected or
6453      * concurrently through {@link AudioRouting} or {@link MediaRouter}.
6454      * @param attributes the {@link AudioAttributes} for which the routing is being queried
6455      * @return an empty list if there was an issue with the request, a list of
6456      * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths).
6457      */
getAudioDevicesForAttributes( @onNull AudioAttributes attributes)6458     public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes(
6459             @NonNull AudioAttributes attributes) {
6460         final List<AudioDeviceAttributes> devicesForAttributes;
6461         try {
6462             Objects.requireNonNull(attributes);
6463             final IAudioService service = getService();
6464             devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes);
6465         } catch (Exception e) {
6466             Log.i(TAG, "No audio devices available for specified attributes.");
6467             return Collections.emptyList();
6468         }
6469 
6470         // Map from AudioDeviceAttributes to AudioDeviceInfo
6471         AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS);
6472         List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>();
6473         for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) {
6474             for (AudioDeviceInfo deviceInfo : outputDeviceInfos) {
6475                 if (deviceForAttributes.getType() == deviceInfo.getType()
6476                         && TextUtils.equals(deviceForAttributes.getAddress(),
6477                                 deviceInfo.getAddress())) {
6478                     deviceInfosForAttributes.add(deviceInfo);
6479                 }
6480             }
6481         }
6482         return Collections.unmodifiableList(deviceInfosForAttributes);
6483     }
6484 
6485     /**
6486      * @hide
6487      * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
6488      * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
6489      * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
6490      */
6491     public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
6492     /**
6493      * @hide
6494      * Volume behavior for an audio device where a software attenuation is applied
6495      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
6496      */
6497     @SystemApi
6498     public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
6499     /**
6500      * @hide
6501      * Volume behavior for an audio device where the volume is always set to provide no attenuation
6502      *     nor gain (e.g. unit gain).
6503      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
6504      */
6505     @SystemApi
6506     public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
6507     /**
6508      * @hide
6509      * Volume behavior for an audio device where the volume is either set to muted, or to provide
6510      *     no attenuation nor gain (e.g. unit gain).
6511      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
6512      */
6513     @SystemApi
6514     public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
6515     /**
6516      * @hide
6517      * Volume behavior for an audio device where no software attenuation is applied, and
6518      *     the volume is kept synchronized between the host and the device itself through a
6519      *     device-specific protocol such as BT AVRCP.
6520      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
6521      */
6522     @SystemApi
6523     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
6524     /**
6525      * @hide
6526      * Volume behavior for an audio device where no software attenuation is applied, and
6527      *     the volume is kept synchronized between the host and the device itself through a
6528      *     device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
6529      *     normal vs in phone call).
6530      * @see #setMode(int)
6531      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
6532      */
6533     @SystemApi
6534     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
6535 
6536     /**
6537      * @hide
6538      * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
6539      * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
6540      * no effect, or an unreliable effect.
6541      */
6542     @SystemApi
6543     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
6544 
6545     /** @hide */
6546     @IntDef({
6547             DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6548             DEVICE_VOLUME_BEHAVIOR_FULL,
6549             DEVICE_VOLUME_BEHAVIOR_FIXED,
6550             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6551             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
6552             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6553     })
6554     @Retention(RetentionPolicy.SOURCE)
6555     public @interface DeviceVolumeBehavior {}
6556 
6557     /** @hide */
6558     @IntDef({
6559             DEVICE_VOLUME_BEHAVIOR_UNSET,
6560             DEVICE_VOLUME_BEHAVIOR_VARIABLE,
6561             DEVICE_VOLUME_BEHAVIOR_FULL,
6562             DEVICE_VOLUME_BEHAVIOR_FIXED,
6563             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6564             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
6565             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6566     })
6567     @Retention(RetentionPolicy.SOURCE)
6568     public @interface DeviceVolumeBehaviorState {}
6569 
6570     /**
6571      * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
6572      * @hide
6573      */
6574     @IntDef({
6575             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
6576             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
6577     })
6578     @Retention(RetentionPolicy.SOURCE)
6579     public @interface AbsoluteDeviceVolumeBehavior {}
6580 
6581     /**
6582      * @hide
6583      * Throws IAE on an invalid volume behavior value
6584      * @param volumeBehavior behavior value to check
6585      */
enforceValidVolumeBehavior(int volumeBehavior)6586     public static void enforceValidVolumeBehavior(int volumeBehavior) {
6587         switch (volumeBehavior) {
6588             case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
6589             case DEVICE_VOLUME_BEHAVIOR_FULL:
6590             case DEVICE_VOLUME_BEHAVIOR_FIXED:
6591             case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
6592             case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
6593             case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
6594                 return;
6595             default:
6596                 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
6597         }
6598     }
6599 
6600     /**
6601      * @hide
6602      * Sets the volume behavior for an audio output device.
6603      * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
6604      * @see #DEVICE_VOLUME_BEHAVIOR_FULL
6605      * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
6606      * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
6607      * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
6608      * @param device the device to be affected
6609      * @param deviceVolumeBehavior one of the device behaviors
6610      */
6611     @SystemApi
6612     @RequiresPermission(anyOf = {
6613             Manifest.permission.MODIFY_AUDIO_ROUTING,
6614             Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
6615     })
setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)6616     public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
6617             @DeviceVolumeBehavior int deviceVolumeBehavior) {
6618         // verify arguments (validity of device type is enforced in server)
6619         Objects.requireNonNull(device);
6620         enforceValidVolumeBehavior(deviceVolumeBehavior);
6621         // communicate with service
6622         final IAudioService service = getService();
6623         try {
6624             service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
6625                     mApplicationContext.getOpPackageName());
6626         } catch (RemoteException e) {
6627             throw e.rethrowFromSystemServer();
6628         }
6629     }
6630 
6631     /**
6632      * @hide
6633      * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by
6634      * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned
6635      * in its place.
6636      */
6637     @ChangeId
6638     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
6639     @Overridable
6640     public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L;
6641 
6642     /**
6643      * @hide
6644      * Returns the volume device behavior for the given audio device
6645      * @param device the audio device
6646      * @return the volume behavior for the device
6647      */
6648     @SystemApi
6649     @RequiresPermission(anyOf = {
6650             Manifest.permission.MODIFY_AUDIO_ROUTING,
6651             Manifest.permission.QUERY_AUDIO_STATE,
6652             Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
6653     })
6654     public @DeviceVolumeBehavior
getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)6655     int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
6656         // verify arguments (validity of device type is enforced in server)
6657         Objects.requireNonNull(device);
6658         // communicate with service
6659         final IAudioService service = getService();
6660         try {
6661             int behavior = service.getDeviceVolumeBehavior(device);
6662             if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
6663                     && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
6664                 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
6665             }
6666             return behavior;
6667         } catch (RemoteException e) {
6668             throw e.rethrowFromSystemServer();
6669         }
6670     }
6671 
6672     /**
6673      * @hide
6674      * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
6675      */
6676     @TestApi
6677     @RequiresPermission(anyOf = {
6678             Manifest.permission.MODIFY_AUDIO_ROUTING,
6679             Manifest.permission.QUERY_AUDIO_STATE,
6680             Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED
6681     })
isFullVolumeDevice()6682     public boolean isFullVolumeDevice() {
6683         final AudioAttributes attributes = new AudioAttributes.Builder()
6684                 .setUsage(AudioAttributes.USAGE_MEDIA)
6685                 .build();
6686         final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
6687         for (AudioDeviceAttributes device : devices) {
6688             if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
6689                 return true;
6690             }
6691         }
6692         return false;
6693     }
6694 
6695     /**
6696      * Indicate wired accessory connection state change.
6697      * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
6698      * @param state  new connection state: 1 connected, 0 disconnected
6699      * @param name   device name
6700      * {@hide}
6701      */
6702     @UnsupportedAppUsage
6703     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setWiredDeviceConnectionState(int device, int state, String address, String name)6704     public void setWiredDeviceConnectionState(int device, int state, String address, String name) {
6705         AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name);
6706         setWiredDeviceConnectionState(attributes, state);
6707     }
6708 
6709     /**
6710      * Indicate wired accessory connection state change and attributes.
6711      * @param state      new connection state: 1 connected, 0 disconnected
6712      * @param attributes attributes of the connected device
6713      * {@hide}
6714      */
6715     @UnsupportedAppUsage
6716     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state)6717     public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
6718         final IAudioService service = getService();
6719         try {
6720             service.setWiredDeviceConnectionState(attributes, state,
6721                     mApplicationContext.getOpPackageName());
6722         } catch (RemoteException e) {
6723             throw e.rethrowFromSystemServer();
6724         }
6725     }
6726 
6727     /**
6728      * Indicate wired accessory connection state change.
6729      * @param device {@link AudioDeviceAttributes} of the device to "fake-connect"
6730      * @param connected true for connected, false for disconnected
6731      * {@hide}
6732      */
6733     @TestApi
6734     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setTestDeviceConnectionState(@onNull AudioDeviceAttributes device, boolean connected)6735     public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
6736             boolean connected) {
6737         try {
6738             getService().setTestDeviceConnectionState(device, connected);
6739         } catch (RemoteException e) {
6740             throw e.rethrowFromSystemServer();
6741         }
6742     }
6743 
6744     /**
6745      * Indicate Bluetooth profile connection state change.
6746      * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and
6747      * <code>previousDevice</code>
6748      * This operation is asynchronous.
6749      *
6750      * @param newDevice Bluetooth device connected or null if there is no new devices
6751      * @param previousDevice Bluetooth device disconnected or null if there is no disconnected
6752      * devices
6753      * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
6754      * {@hide}
6755      */
6756     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
6757     @RequiresPermission(Manifest.permission.BLUETOOTH_STACK)
handleBluetoothActiveDeviceChanged(@ullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info)6758     public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
6759             @Nullable BluetoothDevice previousDevice,
6760             @NonNull BluetoothProfileConnectionInfo info) {
6761         final IAudioService service = getService();
6762         try {
6763             service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
6764         } catch (RemoteException e) {
6765             throw e.rethrowFromSystemServer();
6766         }
6767     }
6768 
6769     /** {@hide} */
getRingtonePlayer()6770     public IRingtonePlayer getRingtonePlayer() {
6771         try {
6772             return getService().getRingtonePlayer();
6773         } catch (RemoteException e) {
6774             throw e.rethrowFromSystemServer();
6775         }
6776     }
6777 
6778     /**
6779      * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
6780      * for this device's low latency output stream, in decimal Hz.  Latency-sensitive apps
6781      * should use this value as a default, and offer the user the option to override it.
6782      * The low latency output stream is typically either the device's primary output stream,
6783      * or another output stream with smaller buffers.
6784      */
6785     // FIXME Deprecate
6786     public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
6787             "android.media.property.OUTPUT_SAMPLE_RATE";
6788 
6789     /**
6790      * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
6791      * for this device's low latency output stream, in decimal PCM frames.  Latency-sensitive apps
6792      * should use this value as a minimum, and offer the user the option to override it.
6793      * The low latency output stream is typically either the device's primary output stream,
6794      * or another output stream with smaller buffers.
6795      */
6796     // FIXME Deprecate
6797     public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
6798             "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
6799 
6800     /**
6801      * Used as a key for {@link #getProperty} to determine if the default microphone audio source
6802      * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6803      */
6804     public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
6805             "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
6806 
6807     /**
6808      * Used as a key for {@link #getProperty} to determine if the default speaker audio path
6809      * supports near-ultrasound frequencies (range of 18 - 21 kHz).
6810      */
6811     public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
6812             "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
6813 
6814     /**
6815      * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
6816      * available and supported with the expected frequency range and level response.
6817      */
6818     public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
6819             "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
6820     /**
6821      * Returns the value of the property with the specified key.
6822      * @param key One of the strings corresponding to a property key: either
6823      *            {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
6824      *            {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
6825      *            {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
6826      *            {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
6827      *            {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
6828      * @return A string representing the associated value for that property key,
6829      *         or null if there is no value for that key.
6830      */
getProperty(String key)6831     public String getProperty(String key) {
6832         if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
6833             int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
6834             return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
6835         } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
6836             int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
6837             return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
6838         } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
6839             // Will throw a RuntimeException Resources.NotFoundException if this config value is
6840             // not found.
6841             return String.valueOf(getContext().getResources().getBoolean(
6842                     com.android.internal.R.bool.config_supportMicNearUltrasound));
6843         } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
6844             return String.valueOf(getContext().getResources().getBoolean(
6845                     com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
6846         } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
6847             return String.valueOf(getContext().getResources().getBoolean(
6848                     com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
6849         } else {
6850             // null or unknown key
6851             return null;
6852         }
6853     }
6854 
6855     /**
6856      * @hide
6857      * Sets an additional audio output device delay in milliseconds.
6858      *
6859      * The additional output delay is a request to the output device to
6860      * delay audio presentation (generally with respect to video presentation for better
6861      * synchronization).
6862      * It may not be supported by all output devices,
6863      * and typically increases the audio latency by the amount of additional
6864      * audio delay requested.
6865      *
6866      * If additional audio delay is supported by an audio output device,
6867      * it is expected to be supported for all output streams (and configurations)
6868      * opened on that device.
6869      *
6870      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6871      * @param delayMillis delay in milliseconds desired.  This should be in range of {@code 0}
6872      *     to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
6873      * @return true if successful, false if the device does not support output device delay
6874      *     or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
6875      */
6876     @SystemApi
6877     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)6878     public boolean setAdditionalOutputDeviceDelay(
6879             @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
6880         Objects.requireNonNull(device);
6881         try {
6882             return getService().setAdditionalOutputDeviceDelay(
6883                 new AudioDeviceAttributes(device), delayMillis);
6884         } catch (RemoteException e) {
6885             throw e.rethrowFromSystemServer();
6886         }
6887     }
6888 
6889     /**
6890      * @hide
6891      * Returns the current additional audio output device delay in milliseconds.
6892      *
6893      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6894      * @return the additional output device delay. This is a non-negative number.
6895      *     {@code 0} is returned if unsupported.
6896      */
6897     @SystemApi
6898     @IntRange(from = 0)
getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)6899     public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
6900         Objects.requireNonNull(device);
6901         try {
6902             return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
6903         } catch (RemoteException e) {
6904             throw e.rethrowFromSystemServer();
6905         }
6906     }
6907 
6908     /**
6909      * @hide
6910      * Returns the maximum additional audio output device delay in milliseconds.
6911      *
6912      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6913      * @return the maximum output device delay in milliseconds that can be set.
6914      *     This is a non-negative number
6915      *     representing the additional audio delay supported for the device.
6916      *     {@code 0} is returned if unsupported.
6917      */
6918     @SystemApi
6919     @IntRange(from = 0)
getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)6920     public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
6921         Objects.requireNonNull(device);
6922         try {
6923             return getService().getMaxAdditionalOutputDeviceDelay(
6924                     new AudioDeviceAttributes(device));
6925         } catch (RemoteException e) {
6926             throw e.rethrowFromSystemServer();
6927         }
6928     }
6929 
6930     /**
6931      * Returns the estimated latency for the given stream type in milliseconds.
6932      *
6933      * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6934      * a better solution.
6935      * @hide
6936      */
6937     @UnsupportedAppUsage
getOutputLatency(int streamType)6938     public int getOutputLatency(int streamType) {
6939         return AudioSystem.getOutputLatency(streamType);
6940     }
6941 
6942     /**
6943      * Registers a global volume controller interface.  Currently limited to SystemUI.
6944      *
6945      * @hide
6946      */
setVolumeController(IVolumeController controller)6947     public void setVolumeController(IVolumeController controller) {
6948         try {
6949             getService().setVolumeController(controller);
6950         } catch (RemoteException e) {
6951             throw e.rethrowFromSystemServer();
6952         }
6953     }
6954 
6955     /**
6956      * Returns the registered volume controller interface.
6957      *
6958      * @hide
6959      */
6960     @Nullable
getVolumeController()6961     public IVolumeController getVolumeController() {
6962         try {
6963             return getService().getVolumeController();
6964         } catch (RemoteException e) {
6965             throw e.rethrowFromSystemServer();
6966         }
6967     }
6968 
6969     /**
6970      * Notify audio manager about volume controller visibility changes.
6971      * Currently limited to SystemUI.
6972      *
6973      * @hide
6974      */
notifyVolumeControllerVisible(IVolumeController controller, boolean visible)6975     public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6976         try {
6977             getService().notifyVolumeControllerVisible(controller, visible);
6978         } catch (RemoteException e) {
6979             throw e.rethrowFromSystemServer();
6980         }
6981     }
6982 
6983     /**
6984      * Only useful for volume controllers.
6985      * @hide
6986      */
isStreamAffectedByRingerMode(int streamType)6987     public boolean isStreamAffectedByRingerMode(int streamType) {
6988         try {
6989             return getService().isStreamAffectedByRingerMode(streamType);
6990         } catch (RemoteException e) {
6991             throw e.rethrowFromSystemServer();
6992         }
6993     }
6994 
6995     /**
6996      * Only useful for volume controllers.
6997      * @hide
6998      */
isStreamAffectedByMute(int streamType)6999     public boolean isStreamAffectedByMute(int streamType) {
7000         try {
7001             return getService().isStreamAffectedByMute(streamType);
7002         } catch (RemoteException e) {
7003             throw e.rethrowFromSystemServer();
7004         }
7005     }
7006 
7007     /**
7008      * Check whether a user can mute this stream type from a given UI element.
7009      *
7010      * <p>Only useful for volume controllers.
7011      *
7012      * @param streamType type of stream to check if it's mutable from UI
7013      *
7014      * @hide
7015      */
isStreamMutableByUi(int streamType)7016     public boolean isStreamMutableByUi(int streamType) {
7017         try {
7018             return getService().isStreamMutableByUi(streamType);
7019         } catch (RemoteException e) {
7020             throw e.rethrowFromSystemServer();
7021         }
7022     }
7023 
7024     /**
7025      * Only useful for volume controllers.
7026      * @hide
7027      */
disableSafeMediaVolume()7028     public void disableSafeMediaVolume() {
7029         try {
7030             getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
7031         } catch (RemoteException e) {
7032             throw e.rethrowFromSystemServer();
7033         }
7034     }
7035 
7036     /**
7037      * @hide
7038      * Lower media volume to RS1 interval
7039      */
lowerVolumeToRs1()7040     public void lowerVolumeToRs1() {
7041         try {
7042             getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName());
7043         } catch (RemoteException e) {
7044             throw e.rethrowFromSystemServer();
7045         }
7046     }
7047 
7048     /**
7049      * @hide
7050      * @return the RS2 upper bound used for momentary exposure warnings
7051      */
7052     @TestApi
7053     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
getRs2Value()7054     public float getRs2Value() {
7055         try {
7056             return getService().getOutputRs2UpperBound();
7057         } catch (RemoteException e) {
7058             throw e.rethrowFromSystemServer();
7059         }
7060     }
7061 
7062     /**
7063      * @hide
7064      * Sets the RS2 upper bound used for momentary exposure warnings
7065      */
7066     @TestApi
7067     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setRs2Value(float rs2Value)7068     public void setRs2Value(float rs2Value) {
7069         try {
7070             getService().setOutputRs2UpperBound(rs2Value);
7071         } catch (RemoteException e) {
7072             throw e.rethrowFromSystemServer();
7073         }
7074     }
7075 
7076     /**
7077      * @hide
7078      * @return the current computed sound dose value
7079      */
7080     @TestApi
7081     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
getCsd()7082     public float getCsd() {
7083         try {
7084             return getService().getCsd();
7085         } catch (RemoteException e) {
7086             throw e.rethrowFromSystemServer();
7087         }
7088     }
7089 
7090     /**
7091      * @hide
7092      * Sets the computed sound dose value to {@code csd}. A negative value will
7093      * reset all the CSD related timeouts: after a momentary exposure warning and
7094      * before the momentary exposure reaches RS2 (see IEC62368-1 10.6.5)
7095      */
7096     @TestApi
7097     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setCsd(float csd)7098     public void setCsd(float csd) {
7099         try {
7100             getService().setCsd(csd);
7101         } catch (RemoteException e) {
7102             throw e.rethrowFromSystemServer();
7103         }
7104     }
7105 
7106     /**
7107      * @hide
7108      * Forces the computation of MEL values (used for CSD) on framework level. This will have the
7109      * result of ignoring the MEL values computed on HAL level. Should only be used in testing
7110      * since this can affect the certification of a device with EN50332-3 regulation.
7111      */
7112     @TestApi
7113     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
forceUseFrameworkMel(boolean useFrameworkMel)7114     public void forceUseFrameworkMel(boolean useFrameworkMel) {
7115         try {
7116             getService().forceUseFrameworkMel(useFrameworkMel);
7117         } catch (RemoteException e) {
7118             throw e.rethrowFromSystemServer();
7119         }
7120     }
7121 
7122     /**
7123      * @hide
7124      * Forces the computation of CSD on all output devices.
7125      */
7126     @TestApi
7127     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices)7128     public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) {
7129         try {
7130             getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices);
7131         } catch (RemoteException e) {
7132             throw e.rethrowFromSystemServer();
7133         }
7134     }
7135 
7136     /**
7137      * @hide
7138      * Returns whether CSD is enabled and supported by the current active audio module HAL.
7139      * This method will return {@code false) for setups in which CSD as a feature is available
7140      * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see
7141      * {@link AudioManager#isCsdAsAFeatureEnabled()}).
7142      */
7143     @TestApi
7144     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
isCsdEnabled()7145     public boolean isCsdEnabled() {
7146         try {
7147             return getService().isCsdEnabled();
7148         } catch (RemoteException e) {
7149             throw e.rethrowFromSystemServer();
7150         }
7151     }
7152 
7153     /**
7154      * @hide
7155      * Returns whether CSD as a feature can be manipulated by a client. This method
7156      * returns {@code true} in countries where there isn't a safe hearing regulation
7157      * enforced.
7158      */
7159     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
isCsdAsAFeatureAvailable()7160     public boolean isCsdAsAFeatureAvailable() {
7161         try {
7162             return getService().isCsdAsAFeatureAvailable();
7163         } catch (RemoteException e) {
7164             throw e.rethrowFromSystemServer();
7165         }
7166     }
7167 
7168     /**
7169      * @hide
7170      * Returns {@code true} if the client has enabled CSD. This function should only
7171      * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
7172      */
7173     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
isCsdAsAFeatureEnabled()7174     public boolean isCsdAsAFeatureEnabled() {
7175         try {
7176             return getService().isCsdAsAFeatureEnabled();
7177         } catch (RemoteException e) {
7178             throw e.rethrowFromSystemServer();
7179         }
7180     }
7181 
7182     /**
7183      * @hide
7184      * Enables/disables the CSD feature. This function should only be called if
7185      * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}.
7186      */
7187     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setCsdAsAFeatureEnabled(boolean csdToggleValue)7188     public void setCsdAsAFeatureEnabled(boolean csdToggleValue) {
7189         try {
7190             getService().setCsdAsAFeatureEnabled(csdToggleValue);
7191         } catch (RemoteException e) {
7192             throw e.rethrowFromSystemServer();
7193         }
7194     }
7195 
7196     /**
7197      * @hide
7198      * Describes an audio device that has not been categorized with a specific
7199      * audio type.
7200      */
7201     public static final int AUDIO_DEVICE_CATEGORY_UNKNOWN = 0;
7202 
7203     /**
7204      * @hide
7205      * Describes an audio device which is categorized as something different.
7206      */
7207     public static final int AUDIO_DEVICE_CATEGORY_OTHER = 1;
7208 
7209     /**
7210      * @hide
7211      * Describes an audio device which was categorized as speakers.
7212      */
7213     public static final int AUDIO_DEVICE_CATEGORY_SPEAKER = 2;
7214 
7215     /**
7216      * @hide
7217      * Describes an audio device which was categorized as headphones.
7218      */
7219     public static final int AUDIO_DEVICE_CATEGORY_HEADPHONES = 3;
7220 
7221     /**
7222      * @hide
7223      * Describes an audio device which was categorized as car-kit.
7224      */
7225     public static final int AUDIO_DEVICE_CATEGORY_CARKIT = 4;
7226 
7227     /**
7228      * @hide
7229      * Describes an audio device which was categorized as watch.
7230      */
7231     public static final int AUDIO_DEVICE_CATEGORY_WATCH = 5;
7232 
7233     /**
7234      * @hide
7235      * Describes an audio device which was categorized as hearing aid.
7236      */
7237     public static final int AUDIO_DEVICE_CATEGORY_HEARING_AID = 6;
7238 
7239     /**
7240      * @hide
7241      * Describes an audio device which was categorized as receiver.
7242      */
7243     public static final int AUDIO_DEVICE_CATEGORY_RECEIVER = 7;
7244 
7245     /** @hide */
7246     @IntDef(flag = false, prefix = "AUDIO_DEVICE_CATEGORY", value = {
7247             AUDIO_DEVICE_CATEGORY_UNKNOWN,
7248             AUDIO_DEVICE_CATEGORY_OTHER,
7249             AUDIO_DEVICE_CATEGORY_SPEAKER,
7250             AUDIO_DEVICE_CATEGORY_HEADPHONES,
7251             AUDIO_DEVICE_CATEGORY_CARKIT,
7252             AUDIO_DEVICE_CATEGORY_WATCH,
7253             AUDIO_DEVICE_CATEGORY_HEARING_AID,
7254             AUDIO_DEVICE_CATEGORY_RECEIVER }
7255     )
7256     @Retention(RetentionPolicy.SOURCE)
7257     public @interface AudioDeviceCategory {}
7258 
7259     /** @hide */
audioDeviceCategoryToString(int audioDeviceCategory)7260     public static String audioDeviceCategoryToString(int audioDeviceCategory) {
7261         switch (audioDeviceCategory) {
7262             case AUDIO_DEVICE_CATEGORY_UNKNOWN: return "AUDIO_DEVICE_CATEGORY_UNKNOWN";
7263             case AUDIO_DEVICE_CATEGORY_OTHER: return "AUDIO_DEVICE_CATEGORY_OTHER";
7264             case AUDIO_DEVICE_CATEGORY_SPEAKER: return "AUDIO_DEVICE_CATEGORY_SPEAKER";
7265             case AUDIO_DEVICE_CATEGORY_HEADPHONES: return "AUDIO_DEVICE_CATEGORY_HEADPHONES";
7266             case AUDIO_DEVICE_CATEGORY_CARKIT: return "AUDIO_DEVICE_CATEGORY_CARKIT";
7267             case AUDIO_DEVICE_CATEGORY_WATCH: return "AUDIO_DEVICE_CATEGORY_WATCH";
7268             case AUDIO_DEVICE_CATEGORY_HEARING_AID: return "AUDIO_DEVICE_CATEGORY_HEARING_AID";
7269             case AUDIO_DEVICE_CATEGORY_RECEIVER: return "AUDIO_DEVICE_CATEGORY_RECEIVER";
7270             default:
7271                 return new StringBuilder("unknown AudioDeviceCategory ").append(
7272                         audioDeviceCategory).toString();
7273         }
7274     }
7275 
7276     /**
7277      * @hide
7278      * Sets the audio device type of a Bluetooth device given its MAC address
7279      */
7280     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setBluetoothAudioDeviceCategory_legacy(@onNull String address, boolean isBle, @AudioDeviceCategory int btAudioDeviceType)7281     public void setBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle,
7282             @AudioDeviceCategory int btAudioDeviceType) {
7283         if (automaticBtDeviceType()) {
7284             // do nothing
7285             return;
7286         }
7287         try {
7288             getService().setBluetoothAudioDeviceCategory_legacy(address, isBle, btAudioDeviceType);
7289         } catch (RemoteException e) {
7290             throw e.rethrowFromSystemServer();
7291         }
7292     }
7293 
7294     /**
7295      * @hide
7296      * Gets the audio device type of a Bluetooth device given its MAC address
7297      */
7298     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7299     @AudioDeviceCategory
getBluetoothAudioDeviceCategory_legacy(@onNull String address, boolean isBle)7300     public int getBluetoothAudioDeviceCategory_legacy(@NonNull String address, boolean isBle) {
7301         if (automaticBtDeviceType()) {
7302             return AUDIO_DEVICE_CATEGORY_UNKNOWN;
7303         }
7304         try {
7305             return getService().getBluetoothAudioDeviceCategory_legacy(address, isBle);
7306         } catch (RemoteException e) {
7307             throw e.rethrowFromSystemServer();
7308         }
7309     }
7310 
7311     /**
7312      * @hide
7313      * Sets the audio device type of a Bluetooth device given its MAC address
7314      *
7315      * @return {@code true} if the device type was set successfully. If the
7316      *         audio device type was automatically identified this method will
7317      *         return {@code false}.
7318      */
7319     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setBluetoothAudioDeviceCategory(@onNull String address, @AudioDeviceCategory int btAudioDeviceCategory)7320     public boolean setBluetoothAudioDeviceCategory(@NonNull String address,
7321             @AudioDeviceCategory int btAudioDeviceCategory) {
7322         if (!automaticBtDeviceType()) {
7323             return false;
7324         }
7325         try {
7326             return getService().setBluetoothAudioDeviceCategory(address, btAudioDeviceCategory);
7327         } catch (RemoteException e) {
7328             throw e.rethrowFromSystemServer();
7329         }
7330     }
7331 
7332     /**
7333      * @hide
7334      * Gets the audio device type of a Bluetooth device given its MAC address
7335      */
7336     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
7337     @AudioDeviceCategory
getBluetoothAudioDeviceCategory(@onNull String address)7338     public int getBluetoothAudioDeviceCategory(@NonNull String address) {
7339         if (!automaticBtDeviceType()) {
7340             return AUDIO_DEVICE_CATEGORY_UNKNOWN;
7341         }
7342         try {
7343             return getService().getBluetoothAudioDeviceCategory(address);
7344         } catch (RemoteException e) {
7345             throw e.rethrowFromSystemServer();
7346         }
7347     }
7348 
7349     /**
7350      * @hide
7351      * Returns {@code true} if the audio device type of a Bluetooth device can
7352      * be automatically identified
7353      */
7354     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
isBluetoothAudioDeviceCategoryFixed(@onNull String address)7355     public boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) {
7356         if (!automaticBtDeviceType()) {
7357             return false;
7358         }
7359         try {
7360             return getService().isBluetoothAudioDeviceCategoryFixed(address);
7361         } catch (RemoteException e) {
7362             throw e.rethrowFromSystemServer();
7363         }
7364     }
7365 
7366     /**
7367      * @hide
7368      * Sound dose warning at every 100% of dose during integration window
7369      */
7370     public static final int CSD_WARNING_DOSE_REACHED_1X = 1;
7371     /**
7372      * @hide
7373      * Sound dose warning when 500% of dose is reached during integration window
7374      */
7375     public static final int CSD_WARNING_DOSE_REPEATED_5X = 2;
7376     /**
7377      * @hide
7378      * Sound dose warning after a momentary exposure event
7379      */
7380     public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3;
7381     /**
7382      * @hide
7383      * Sound dose warning at every 100% of dose during integration window
7384      */
7385     public static final int CSD_WARNING_ACCUMULATION_START = 4;
7386 
7387     /** @hide */
7388     @IntDef(flag = false, value = {
7389             CSD_WARNING_DOSE_REACHED_1X,
7390             CSD_WARNING_DOSE_REPEATED_5X,
7391             CSD_WARNING_MOMENTARY_EXPOSURE,
7392             CSD_WARNING_ACCUMULATION_START }
7393     )
7394     @Retention(RetentionPolicy.SOURCE)
7395     public @interface CsdWarning {}
7396 
7397     /**
7398      * Only useful for volume controllers.
7399      * @hide
7400      */
7401     @UnsupportedAppUsage
setRingerModeInternal(int ringerMode)7402     public void setRingerModeInternal(int ringerMode) {
7403         try {
7404             getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
7405         } catch (RemoteException e) {
7406             throw e.rethrowFromSystemServer();
7407         }
7408     }
7409 
7410     /**
7411      * Only useful for volume controllers.
7412      * @hide
7413      */
7414     @UnsupportedAppUsage
getRingerModeInternal()7415     public int getRingerModeInternal() {
7416         try {
7417             return getService().getRingerModeInternal();
7418         } catch (RemoteException e) {
7419             throw e.rethrowFromSystemServer();
7420         }
7421     }
7422 
7423     /**
7424      * Only useful for volume controllers.
7425      * @hide
7426      */
setVolumePolicy(VolumePolicy policy)7427     public void setVolumePolicy(VolumePolicy policy) {
7428         try {
7429             getService().setVolumePolicy(policy);
7430         } catch (RemoteException e) {
7431             throw e.rethrowFromSystemServer();
7432         }
7433     }
7434 
7435     /**
7436      * Set Hdmi Cec system audio mode.
7437      *
7438      * @param on whether to be on system audio mode
7439      * @return output device type. 0 (DEVICE_NONE) if failed to set device.
7440      * @hide
7441      */
setHdmiSystemAudioSupported(boolean on)7442     public int setHdmiSystemAudioSupported(boolean on) {
7443         try {
7444             return getService().setHdmiSystemAudioSupported(on);
7445         } catch (RemoteException e) {
7446             throw e.rethrowFromSystemServer();
7447         }
7448     }
7449 
7450     /**
7451      * Returns true if Hdmi Cec system audio mode is supported.
7452      *
7453      * @hide
7454      */
7455     @SystemApi
7456     @SuppressLint("RequiresPermission") // FIXME is this still used?
isHdmiSystemAudioSupported()7457     public boolean isHdmiSystemAudioSupported() {
7458         try {
7459             return getService().isHdmiSystemAudioSupported();
7460         } catch (RemoteException e) {
7461             throw e.rethrowFromSystemServer();
7462         }
7463     }
7464 
7465     /**
7466      * Return codes for listAudioPorts(), createAudioPatch() ...
7467      */
7468 
7469     /** @hide */
7470     @SystemApi
7471     public static final int SUCCESS = AudioSystem.SUCCESS;
7472     /**
7473      * A default error code.
7474      */
7475     public static final int ERROR = AudioSystem.ERROR;
7476     /** @hide
7477      * CANDIDATE FOR PUBLIC API
7478      */
7479     public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
7480     /** @hide
7481      */
7482     public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
7483     /** @hide
7484      */
7485     public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
7486     /** @hide
7487      */
7488     public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
7489     /**
7490      * An error code indicating that the object reporting it is no longer valid and needs to
7491      * be recreated.
7492      */
7493     public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
7494 
7495     /**
7496      * Returns a list of descriptors for all audio ports managed by the audio framework.
7497      * Audio ports are nodes in the audio framework or audio hardware that can be configured
7498      * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
7499      * See AudioPort for a list of attributes of each audio port.
7500      * @param ports An AudioPort ArrayList where the list will be returned.
7501      * @hide
7502      */
7503     @UnsupportedAppUsage
listAudioPorts(ArrayList<AudioPort> ports)7504     public static int listAudioPorts(ArrayList<AudioPort> ports) {
7505         return updateAudioPortCache(ports, null, null);
7506     }
7507 
7508     /**
7509      * Returns a list of descriptors for all audio ports managed by the audio framework as
7510      * it was before the last update calback.
7511      * @param ports An AudioPort ArrayList where the list will be returned.
7512      * @hide
7513      */
listPreviousAudioPorts(ArrayList<AudioPort> ports)7514     public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
7515         return updateAudioPortCache(null, null, ports);
7516     }
7517 
7518     /**
7519      * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
7520      * @see listAudioPorts(ArrayList<AudioPort>)
7521      * @hide
7522      */
listAudioDevicePorts(ArrayList<AudioDevicePort> devices)7523     public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
7524         if (devices == null) {
7525             return ERROR_BAD_VALUE;
7526         }
7527         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
7528         int status = updateAudioPortCache(ports, null, null);
7529         if (status == SUCCESS) {
7530             filterDevicePorts(ports, devices);
7531         }
7532         return status;
7533     }
7534 
7535     /**
7536      * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
7537      * @see listPreviousAudioPorts(ArrayList<AudioPort>)
7538      * @hide
7539      */
listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)7540     public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
7541         if (devices == null) {
7542             return ERROR_BAD_VALUE;
7543         }
7544         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
7545         int status = updateAudioPortCache(null, null, ports);
7546         if (status == SUCCESS) {
7547             filterDevicePorts(ports, devices);
7548         }
7549         return status;
7550     }
7551 
filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)7552     private static void filterDevicePorts(ArrayList<AudioPort> ports,
7553                                           ArrayList<AudioDevicePort> devices) {
7554         devices.clear();
7555         for (int i = 0; i < ports.size(); i++) {
7556             if (ports.get(i) instanceof AudioDevicePort) {
7557                 devices.add((AudioDevicePort)ports.get(i));
7558             }
7559         }
7560     }
7561 
7562     /**
7563      * Create a connection between two or more devices. The framework will reject the request if
7564      * device types are not compatible or the implementation does not support the requested
7565      * configuration.
7566      * NOTE: current implementation is limited to one source and one sink per patch.
7567      * @param patch AudioPatch array where the newly created patch will be returned.
7568      *              As input, if patch[0] is not null, the specified patch will be replaced by the
7569      *              new patch created. This avoids calling releaseAudioPatch() when modifying a
7570      *              patch and allows the implementation to optimize transitions.
7571      * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
7572      * @param sinks   List of sink audio ports. All must be AudioPort.ROLE_SINK.
7573      *
7574      * @return - {@link #SUCCESS} if connection is successful.
7575      *         - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
7576      *         - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
7577      *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
7578      *         a patch.
7579      *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7580      *         - {@link #ERROR} if patch cannot be connected for any other reason.
7581      *
7582      *         patch[0] contains the newly created patch
7583      * @hide
7584      */
7585     @UnsupportedAppUsage
createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)7586     public static int createAudioPatch(AudioPatch[] patch,
7587                                  AudioPortConfig[] sources,
7588                                  AudioPortConfig[] sinks) {
7589         return AudioSystem.createAudioPatch(patch, sources, sinks);
7590     }
7591 
7592     /**
7593      * Releases an existing audio patch connection.
7594      * @param patch The audio patch to disconnect.
7595      * @return - {@link #SUCCESS} if disconnection is successful.
7596      *         - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
7597      *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
7598      *         a patch.
7599      *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
7600      *         - {@link #ERROR} if patch cannot be released for any other reason.
7601      * @hide
7602      */
7603     @UnsupportedAppUsage
releaseAudioPatch(AudioPatch patch)7604     public static int releaseAudioPatch(AudioPatch patch) {
7605         return AudioSystem.releaseAudioPatch(patch);
7606     }
7607 
7608     /**
7609      * List all existing connections between audio ports.
7610      * @param patches An AudioPatch array where the list will be returned.
7611      * @hide
7612      */
7613     @UnsupportedAppUsage
listAudioPatches(ArrayList<AudioPatch> patches)7614     public static int listAudioPatches(ArrayList<AudioPatch> patches) {
7615         return updateAudioPortCache(null, patches, null);
7616     }
7617 
7618     /**
7619      * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
7620      * AudioGain.buildConfig()
7621      * @hide
7622      */
setAudioPortGain(AudioPort port, AudioGainConfig gain)7623     public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
7624         if (port == null || gain == null) {
7625             return ERROR_BAD_VALUE;
7626         }
7627         AudioPortConfig activeConfig = port.activeConfig();
7628         AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
7629                                         activeConfig.channelMask(), activeConfig.format(), gain);
7630         config.mConfigMask = AudioPortConfig.GAIN;
7631         return AudioSystem.setAudioPortConfig(config);
7632     }
7633 
7634     /**
7635      * Listener registered by client to be notified upon new audio port connections,
7636      * disconnections or attributes update.
7637      * @hide
7638      */
7639     public interface OnAudioPortUpdateListener {
7640         /**
7641          * Callback method called upon audio port list update.
7642          * @param portList the updated list of audio ports
7643          */
onAudioPortListUpdate(AudioPort[] portList)7644         public void onAudioPortListUpdate(AudioPort[] portList);
7645 
7646         /**
7647          * Callback method called upon audio patch list update.
7648          * @param patchList the updated list of audio patches
7649          */
onAudioPatchListUpdate(AudioPatch[] patchList)7650         public void onAudioPatchListUpdate(AudioPatch[] patchList);
7651 
7652         /**
7653          * Callback method called when the mediaserver dies
7654          */
onServiceDied()7655         public void onServiceDied();
7656     }
7657 
7658     /**
7659      * Register an audio port list update listener.
7660      * @hide
7661      */
7662     @UnsupportedAppUsage
registerAudioPortUpdateListener(OnAudioPortUpdateListener l)7663     public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
7664         sAudioPortEventHandler.init();
7665         sAudioPortEventHandler.registerListener(l);
7666     }
7667 
7668     /**
7669      * Unregister an audio port list update listener.
7670      * @hide
7671      */
7672     @UnsupportedAppUsage
unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)7673     public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
7674         sAudioPortEventHandler.unregisterListener(l);
7675     }
7676 
7677     //
7678     // AudioPort implementation
7679     //
7680 
7681     private static final int AUDIOPORT_GENERATION_INIT = 0;
7682     private static Object sAudioPortGenerationLock = new Object();
7683     @GuardedBy("sAudioPortGenerationLock")
7684     private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
7685     private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
7686     private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
7687     private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
7688 
resetAudioPortGeneration()7689     static int resetAudioPortGeneration() {
7690         int generation;
7691         synchronized (sAudioPortGenerationLock) {
7692             generation = sAudioPortGeneration;
7693             sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
7694         }
7695         return generation;
7696     }
7697 
updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)7698     static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
7699                                     ArrayList<AudioPort> previousPorts) {
7700         sAudioPortEventHandler.init();
7701         synchronized (sAudioPortGenerationLock) {
7702 
7703             if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
7704                 int[] patchGeneration = new int[1];
7705                 int[] portGeneration = new int[1];
7706                 int status;
7707                 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
7708                 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
7709 
7710                 do {
7711                     newPorts.clear();
7712                     status = AudioSystem.listAudioPorts(newPorts, portGeneration);
7713                     if (status != SUCCESS) {
7714                         Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
7715                         return status;
7716                     }
7717                     newPatches.clear();
7718                     status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
7719                     if (status != SUCCESS) {
7720                         Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
7721                         return status;
7722                     }
7723                     // Loop until patch generation is the same as port generation unless audio ports
7724                     // and audio patches are not null.
7725                 } while (patchGeneration[0] != portGeneration[0]
7726                         && (ports == null || patches == null));
7727                 // If the patch generation doesn't equal port generation, return ERROR here in case
7728                 // of mismatch between audio ports and audio patches.
7729                 if (patchGeneration[0] != portGeneration[0]) {
7730                     return ERROR;
7731                 }
7732 
7733                 for (int i = 0; i < newPatches.size(); i++) {
7734                     for (int j = 0; j < newPatches.get(i).sources().length; j++) {
7735                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
7736                                                                    newPorts);
7737                         newPatches.get(i).sources()[j] = portCfg;
7738                     }
7739                     for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
7740                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
7741                                                                    newPorts);
7742                         newPatches.get(i).sinks()[j] = portCfg;
7743                     }
7744                 }
7745                 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
7746                     AudioPatch newPatch = i.next();
7747                     boolean hasInvalidPort = false;
7748                     for (AudioPortConfig portCfg : newPatch.sources()) {
7749                         if (portCfg == null) {
7750                             hasInvalidPort = true;
7751                             break;
7752                         }
7753                     }
7754                     for (AudioPortConfig portCfg : newPatch.sinks()) {
7755                         if (portCfg == null) {
7756                             hasInvalidPort = true;
7757                             break;
7758                         }
7759                     }
7760                     if (hasInvalidPort) {
7761                         // Temporarily remove patches with invalid ports. One who created the patch
7762                         // is responsible for dealing with the port change.
7763                         i.remove();
7764                     }
7765                 }
7766 
7767                 sPreviousAudioPortsCached = sAudioPortsCached;
7768                 sAudioPortsCached = newPorts;
7769                 sAudioPatchesCached = newPatches;
7770                 sAudioPortGeneration = portGeneration[0];
7771             }
7772             if (ports != null) {
7773                 ports.clear();
7774                 ports.addAll(sAudioPortsCached);
7775             }
7776             if (patches != null) {
7777                 patches.clear();
7778                 patches.addAll(sAudioPatchesCached);
7779             }
7780             if (previousPorts != null) {
7781                 previousPorts.clear();
7782                 previousPorts.addAll(sPreviousAudioPortsCached);
7783             }
7784         }
7785         return SUCCESS;
7786     }
7787 
updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)7788     static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
7789         AudioPort port = portCfg.port();
7790         int k;
7791         for (k = 0; k < ports.size(); k++) {
7792             // compare handles because the port returned by JNI is not of the correct
7793             // subclass
7794             if (ports.get(k).handle().equals(port.handle())) {
7795                 port = ports.get(k);
7796                 break;
7797             }
7798         }
7799         if (k == ports.size()) {
7800             // This can happen in case of stale audio patch referring to a removed device and is
7801             // handled by the caller.
7802             return null;
7803         }
7804         AudioGainConfig gainCfg = portCfg.gain();
7805         if (gainCfg != null) {
7806             AudioGain gain = port.gain(gainCfg.index());
7807             gainCfg = gain.buildConfig(gainCfg.mode(),
7808                                        gainCfg.channelMask(),
7809                                        gainCfg.values(),
7810                                        gainCfg.rampDurationMs());
7811         }
7812         return port.buildConfig(portCfg.samplingRate(),
7813                                                  portCfg.channelMask(),
7814                                                  portCfg.format(),
7815                                                  gainCfg);
7816     }
7817 
7818     private OnAmPortUpdateListener mPortListener = null;
7819 
7820     /**
7821      * The message sent to apps when the contents of the device list changes if they provide
7822      * a {@link Handler} object to {@link registerAudioDeviceCallback}.
7823      */
7824     private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
7825     private final static int MSG_DEVICES_DEVICES_ADDED = 1;
7826     private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
7827 
7828     /**
7829      * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
7830      */
7831     private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
7832             new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
7833 
7834     /**
7835      * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
7836      * the results list to only those device types they are interested in.
7837      */
7838     /**
7839      * Specifies to the {@link AudioManager#getDevices(int)} method to include
7840      * source (i.e. input) audio devices.
7841      */
7842     public static final int GET_DEVICES_INPUTS    = 0x0001;
7843 
7844     /**
7845      * Specifies to the {@link AudioManager#getDevices(int)} method to include
7846      * sink (i.e. output) audio devices.
7847      */
7848     public static final int GET_DEVICES_OUTPUTS   = 0x0002;
7849 
7850     /** @hide */
7851     @IntDef(flag = true, prefix = "GET_DEVICES", value = {
7852             GET_DEVICES_INPUTS,
7853             GET_DEVICES_OUTPUTS }
7854     )
7855     @Retention(RetentionPolicy.SOURCE)
7856     public @interface AudioDeviceRole {}
7857 
7858     /**
7859      * Specifies to the {@link AudioManager#getDevices(int)} method to include both
7860      * source and sink devices.
7861      */
7862     public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
7863 
7864     /**
7865      * Determines if a given AudioDevicePort meets the specified filter criteria.
7866      * @param port  The port to test.
7867      * @param flags A set of bitflags specifying the criteria to test.
7868      * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
7869      **/
checkFlags(AudioDevicePort port, int flags)7870     private static boolean checkFlags(AudioDevicePort port, int flags) {
7871         return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
7872                port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
7873     }
7874 
checkTypes(AudioDevicePort port)7875     private static boolean checkTypes(AudioDevicePort port) {
7876         return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
7877                     AudioDeviceInfo.TYPE_UNKNOWN;
7878     }
7879 
7880     /**
7881      * Returns a Set of unique Integers corresponding to audio device type identifiers that can
7882      * <i>potentially</i> be connected to the system and meeting the criteria specified in the
7883      * <code>direction</code> parameter.
7884      * Note that this set contains {@link AudioDeviceInfo} device type identifiers for both devices
7885      * currently available <i>and</i> those that can be available if the user connects an audio
7886      * peripheral. Examples include TYPE_WIRED_HEADSET if the Android device supports an analog
7887      * headset jack or TYPE_USB_DEVICE if the Android device supports a USB host-mode port.
7888      * These are generally a superset of device type identifiers associated with the
7889      * AudioDeviceInfo objects returned from AudioManager.getDevices().
7890      * @param direction The constant specifying whether input or output devices are queried.
7891      * @see #GET_DEVICES_OUTPUTS
7892      * @see #GET_DEVICES_INPUTS
7893      * @return A (possibly zero-length) Set of Integer objects corresponding to the audio
7894      * device types of devices supported by the implementation.
7895      * @throws IllegalArgumentException If an invalid direction constant is specified.
7896      */
7897     @FlaggedApi(FLAG_SUPPORTED_DEVICE_TYPES_API)
7898     public @NonNull Set<Integer>
getSupportedDeviceTypes(@udioDeviceRole int direction)7899             getSupportedDeviceTypes(@AudioDeviceRole int direction) {
7900         if (direction != GET_DEVICES_OUTPUTS && direction != GET_DEVICES_INPUTS) {
7901             throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes(0x"
7902                     + Integer.toHexString(direction) + ") - Invalid.");
7903         }
7904 
7905         IntArray internalDeviceTypes = new IntArray();
7906         int status = AudioSystem.getSupportedDeviceTypes(direction, internalDeviceTypes);
7907         if (status != AudioManager.SUCCESS) {
7908             Log.e(TAG, "AudioManager.getSupportedDeviceTypes(" + direction + ") failed. status:"
7909                     + status);
7910         }
7911 
7912         // convert to external (AudioDeviceInfo.getType()) device IDs
7913         HashSet<Integer> externalDeviceTypes = new HashSet<Integer>();
7914         for (int index = 0; index < internalDeviceTypes.size(); index++) {
7915             // Set will eliminate any duplicates which AudioSystem.getSupportedDeviceTypes()
7916             // returns
7917             externalDeviceTypes.add(
7918                     AudioDeviceInfo.convertInternalDeviceToDeviceType(
7919                         internalDeviceTypes.get(index)));
7920         }
7921 
7922         return externalDeviceTypes;
7923     }
7924 
7925      /**
7926      * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
7927      * currently connected to the system and meeting the criteria specified in the
7928      * <code>flags</code> parameter.
7929      * Notes that Android audio framework only support one device per device type. In that case,
7930      * if there are multiple audio device with the same device type connected to the Android device,
7931      * only the last reported device will be known by Android audio framework and returned by this
7932      * API.
7933      * @param flags A set of bitflags specifying the criteria to test.
7934      * @see #GET_DEVICES_OUTPUTS
7935      * @see #GET_DEVICES_INPUTS
7936      * @see #GET_DEVICES_ALL
7937      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
7938      */
getDevices(@udioDeviceRole int flags)7939     public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
7940         return getDevicesStatic(flags);
7941     }
7942 
7943     /**
7944      * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
7945      * objects from the current (internal) AudioDevicePort list.
7946      */
7947     private static AudioDeviceInfo[]
infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)7948         infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
7949 
7950         // figure out how many AudioDeviceInfo we need space for...
7951         int numRecs = 0;
7952         for (AudioDevicePort port : ports) {
7953             if (checkTypes(port) && checkFlags(port, flags)) {
7954                 numRecs++;
7955             }
7956         }
7957 
7958         // Now load them up...
7959         AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
7960         int slot = 0;
7961         for (AudioDevicePort port : ports) {
7962             if (checkTypes(port) && checkFlags(port, flags)) {
7963                 deviceList[slot++] = new AudioDeviceInfo(port);
7964             }
7965         }
7966 
7967         return deviceList;
7968     }
7969 
7970     /*
7971      * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
7972      * the add/remove callback mechanism to provide a list of the newly added or removed devices
7973      * rather than the whole list and make the app figure it out.
7974      * Note that calling this method with:
7975      *  ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
7976      *  ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
7977      */
calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)7978     private static AudioDeviceInfo[] calcListDeltas(
7979             ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
7980 
7981         ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
7982 
7983         AudioDevicePort cur_port = null;
7984         for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
7985             boolean cur_port_found = false;
7986             cur_port = ports_B.get(cur_index);
7987             for (int prev_index = 0;
7988                  prev_index < ports_A.size() && !cur_port_found;
7989                  prev_index++) {
7990                 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
7991             }
7992 
7993             if (!cur_port_found) {
7994                 delta_ports.add(cur_port);
7995             }
7996         }
7997 
7998         return infoListFromPortList(delta_ports, flags);
7999     }
8000 
8001     /**
8002      * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
8003      * connected to the system and meeting the criteria specified in the <code>flags</code>
8004      * parameter.
8005      * This is an internal function. The public API front is getDevices(int).
8006      * @param flags A set of bitflags specifying the criteria to test.
8007      * @see #GET_DEVICES_OUTPUTS
8008      * @see #GET_DEVICES_INPUTS
8009      * @see #GET_DEVICES_ALL
8010      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
8011      * @hide
8012      */
getDevicesStatic(int flags)8013     public static AudioDeviceInfo[] getDevicesStatic(int flags) {
8014         ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
8015         int status = AudioManager.listAudioDevicePorts(ports);
8016         if (status != AudioManager.SUCCESS) {
8017             // fail and bail!
8018             return new AudioDeviceInfo[0];  // Always return an array.
8019         }
8020 
8021         return infoListFromPortList(ports, flags);
8022     }
8023 
8024     /**
8025      * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
8026      * @param portId The audio port ID to look up for.
8027      * @param flags A set of bitflags specifying the criteria to test.
8028      * @see #GET_DEVICES_OUTPUTS
8029      * @see #GET_DEVICES_INPUTS
8030      * @see #GET_DEVICES_ALL
8031      * @return An AudioDeviceInfo or null if no device with matching port ID is found.
8032      * @hide
8033      */
getDeviceForPortId(int portId, int flags)8034     public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
8035         if (portId == 0) {
8036             return null;
8037         }
8038         AudioDeviceInfo[] devices = getDevicesStatic(flags);
8039         for (AudioDeviceInfo device : devices) {
8040             if (device.getId() == portId) {
8041                 return device;
8042             }
8043         }
8044         return null;
8045     }
8046 
8047     /**
8048      * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
8049      * to the set of connected audio devices.
8050      * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
8051      * notifications.
8052      * @param handler Specifies the {@link Handler} object for the thread on which to execute
8053      * the callback. If <code>null</code>, the {@link Handler} associated with the main
8054      * {@link Looper} will be used.
8055      */
registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)8056     public void registerAudioDeviceCallback(AudioDeviceCallback callback,
8057             @Nullable Handler handler) {
8058         synchronized (mDeviceCallbacks) {
8059             if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
8060                 if (mDeviceCallbacks.size() == 0) {
8061                     if (mPortListener == null) {
8062                         mPortListener = new OnAmPortUpdateListener();
8063                     }
8064                     registerAudioPortUpdateListener(mPortListener);
8065                 }
8066                 NativeEventHandlerDelegate delegate =
8067                         new NativeEventHandlerDelegate(callback, handler);
8068                 mDeviceCallbacks.put(callback, delegate);
8069                 broadcastDeviceListChange_sync(delegate.getHandler());
8070             }
8071         }
8072     }
8073 
8074     /**
8075      * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
8076      * to receive notifications of changes to the set of connected audio devices.
8077      * @param callback The {@link AudioDeviceCallback} object that was previously registered
8078      * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
8079      */
unregisterAudioDeviceCallback(AudioDeviceCallback callback)8080     public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
8081         synchronized (mDeviceCallbacks) {
8082             if (mDeviceCallbacks.containsKey(callback)) {
8083                 mDeviceCallbacks.remove(callback);
8084                 if (mDeviceCallbacks.size() == 0) {
8085                     unregisterAudioPortUpdateListener(mPortListener);
8086                 }
8087             }
8088         }
8089     }
8090 
8091     /**
8092      * Set port id for microphones by matching device type and address.
8093      * @hide
8094      */
setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)8095     public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
8096         AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
8097         for (int i = microphones.size() - 1; i >= 0; i--) {
8098             boolean foundPortId = false;
8099             for (AudioDeviceInfo device : devices) {
8100                 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
8101                         && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
8102                     microphones.get(i).setId(device.getId());
8103                     foundPortId = true;
8104                     break;
8105                 }
8106             }
8107             if (!foundPortId) {
8108                 Log.i(TAG, "Failed to find port id for device with type:"
8109                         + microphones.get(i).getType() + " address:"
8110                         + microphones.get(i).getAddress());
8111                 microphones.remove(i);
8112             }
8113         }
8114     }
8115 
8116     /**
8117      * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
8118      * @hide
8119      */
microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)8120     public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
8121         int deviceType = deviceInfo.getType();
8122         int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
8123                 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
8124                 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
8125                         : MicrophoneInfo.LOCATION_PERIPHERAL;
8126         MicrophoneInfo microphone = new MicrophoneInfo(
8127                 deviceInfo.getPort().name() + deviceInfo.getId(),
8128                 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
8129                 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
8130                 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
8131                 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
8132                 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
8133                 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
8134         microphone.setId(deviceInfo.getId());
8135         return microphone;
8136     }
8137 
8138     /**
8139      * Add {@link MicrophoneInfo} by device information while filtering certain types.
8140      */
addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)8141     private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
8142                     HashSet<Integer> filterTypes) {
8143         AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
8144         for (AudioDeviceInfo device : devices) {
8145             if (filterTypes.contains(device.getType())) {
8146                 continue;
8147             }
8148             MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
8149             microphones.add(microphone);
8150         }
8151     }
8152 
8153     /**
8154      * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
8155      * of all available microphones. The list is empty when no microphones are available
8156      * on the device. An error during the query will result in an IOException being thrown.
8157      *
8158      * @return a list that contains all microphones' characteristics
8159      * @throws IOException if an error occurs.
8160      */
getMicrophones()8161     public List<MicrophoneInfo> getMicrophones() throws IOException {
8162         ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
8163         int status = AudioSystem.getMicrophones(microphones);
8164         HashSet<Integer> filterTypes = new HashSet<>();
8165         filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
8166         if (status != AudioManager.SUCCESS) {
8167             // fail and populate microphones with unknown characteristics by device information.
8168             if (status != AudioManager.ERROR_INVALID_OPERATION) {
8169                 Log.e(TAG, "getMicrophones failed:" + status);
8170             }
8171             Log.i(TAG, "fallback on device info");
8172             addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
8173             return microphones;
8174         }
8175         setPortIdForMicrophones(microphones);
8176         filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
8177         addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
8178         return microphones;
8179     }
8180 
8181     /**
8182      * Returns a list of audio formats that corresponds to encoding formats
8183      * supported on offload path for A2DP playback.
8184      *
8185      * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
8186      * supported for offload A2DP playback
8187      * @hide
8188      */
8189     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
getHwOffloadFormatsSupportedForA2dp()8190     public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() {
8191         ArrayList<Integer> formatsList = new ArrayList<>();
8192         ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>();
8193 
8194         int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
8195                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList);
8196         if (status != AudioManager.SUCCESS) {
8197             Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
8198             return codecConfigList;
8199         }
8200 
8201         for (Integer format : formatsList) {
8202             int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
8203             if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
8204                 codecConfigList.add(
8205                         new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
8206             }
8207         }
8208         return codecConfigList;
8209     }
8210 
getHwOffloadFormatsSupportedForLeAudio( @udioSystem.BtOffloadDeviceType int deviceType)8211     private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio(
8212             @AudioSystem.BtOffloadDeviceType int deviceType) {
8213         ArrayList<Integer> formatsList = new ArrayList<>();
8214         ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>();
8215 
8216         int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia(
8217                 deviceType, formatsList);
8218         if (status != AudioManager.SUCCESS) {
8219             Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status);
8220             return leAudioCodecConfigList;
8221         }
8222 
8223         for (Integer format : formatsList) {
8224             int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format);
8225             if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
8226                 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder()
8227                                             .setCodecType(btLeAudioCodec)
8228                                             .build());
8229             }
8230         }
8231         return leAudioCodecConfigList;
8232     }
8233 
8234     /**
8235      * Returns a list of audio formats that corresponds to encoding formats
8236      * supported on offload path for Le audio playback.
8237      *
8238      * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
8239      * supported for offload Le Audio playback
8240      * @hide
8241      */
8242     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8243     @NonNull
getHwOffloadFormatsSupportedForLeAudio()8244     public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() {
8245         return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET);
8246     }
8247 
8248     /**
8249      * Returns a list of audio formats that corresponds to encoding formats
8250      * supported on offload path for Le Broadcast playback.
8251      *
8252      * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats
8253      * supported for offload Le Broadcast playback
8254      * @hide
8255      */
8256     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
8257     @NonNull
getHwOffloadFormatsSupportedForLeBroadcast()8258     public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() {
8259         return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST);
8260     }
8261 
8262     // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
8263     // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
8264     // of the ports that exist at the time of the last notification.
8265     private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
8266 
8267     /**
8268      * Internal method to compute and generate add/remove messages and then send to any
8269      * registered callbacks. Must be called synchronized on mDeviceCallbacks.
8270      */
broadcastDeviceListChange_sync(Handler handler)8271     private void broadcastDeviceListChange_sync(Handler handler) {
8272         int status;
8273 
8274         // Get the new current set of ports
8275         ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
8276         status = AudioManager.listAudioDevicePorts(current_ports);
8277         if (status != AudioManager.SUCCESS) {
8278             return;
8279         }
8280 
8281         if (handler != null) {
8282             // This is the callback for the registration, so send the current list
8283             AudioDeviceInfo[] deviceList =
8284                     infoListFromPortList(current_ports, GET_DEVICES_ALL);
8285             handler.sendMessage(
8286                     Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
8287         } else {
8288             AudioDeviceInfo[] added_devices =
8289                     calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
8290             AudioDeviceInfo[] removed_devices =
8291                     calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
8292             if (added_devices.length != 0 || removed_devices.length != 0) {
8293                 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
8294                     handler = mDeviceCallbacks.valueAt(i).getHandler();
8295                     if (handler != null) {
8296                         if (removed_devices.length != 0) {
8297                             handler.sendMessage(Message.obtain(handler,
8298                                     MSG_DEVICES_DEVICES_REMOVED,
8299                                     removed_devices));
8300                         }
8301                         if (added_devices.length != 0) {
8302                             handler.sendMessage(Message.obtain(handler,
8303                                     MSG_DEVICES_DEVICES_ADDED,
8304                                     added_devices));
8305                         }
8306                     }
8307                 }
8308             }
8309         }
8310 
8311         mPreviousPorts = current_ports;
8312     }
8313 
8314     /**
8315      * Handles Port list update notifications from the AudioManager
8316      */
8317     private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
8318         static final String TAG = "OnAmPortUpdateListener";
onAudioPortListUpdate(AudioPort[] portList)8319         public void onAudioPortListUpdate(AudioPort[] portList) {
8320             synchronized (mDeviceCallbacks) {
8321                 broadcastDeviceListChange_sync(null);
8322             }
8323         }
8324 
8325         /**
8326          * Callback method called upon audio patch list update.
8327          * Note: We don't do anything with Patches at this time, so ignore this notification.
8328          * @param patchList the updated list of audio patches.
8329          */
onAudioPatchListUpdate(AudioPatch[] patchList)8330         public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
8331 
8332         /**
8333          * Callback method called when the mediaserver dies
8334          */
onServiceDied()8335         public void onServiceDied() {
8336             synchronized (mDeviceCallbacks) {
8337                 broadcastDeviceListChange_sync(null);
8338             }
8339         }
8340     }
8341 
8342 
8343     /**
8344      * @hide
8345      * Abstract class to receive event notification about audioserver process state.
8346      */
8347     @SystemApi
8348     public abstract static class AudioServerStateCallback {
onAudioServerDown()8349         public void onAudioServerDown() { }
onAudioServerUp()8350         public void onAudioServerUp() { }
8351     }
8352 
8353     private Executor mAudioServerStateExec;
8354     private AudioServerStateCallback mAudioServerStateCb;
8355     private final Object mAudioServerStateCbLock = new Object();
8356 
8357     private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
8358             new IAudioServerStateDispatcher.Stub() {
8359         @Override
8360         public void dispatchAudioServerStateChange(boolean state) {
8361             Executor exec;
8362             AudioServerStateCallback cb;
8363 
8364             synchronized (mAudioServerStateCbLock) {
8365                 exec = mAudioServerStateExec;
8366                 cb = mAudioServerStateCb;
8367             }
8368 
8369             if ((exec == null) || (cb == null)) {
8370                 return;
8371             }
8372             if (state) {
8373                 exec.execute(() -> cb.onAudioServerUp());
8374             } else {
8375                 exec.execute(() -> cb.onAudioServerDown());
8376             }
8377         }
8378     };
8379 
8380     /**
8381      * @hide
8382      * Registers a callback for notification of audio server state changes.
8383      * @param executor {@link Executor} to handle the callbacks
8384      * @param stateCallback the callback to receive the audio server state changes
8385      *        To remove the callabck, pass a null reference for both executor and stateCallback.
8386      */
8387     @SystemApi
setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)8388     public void setAudioServerStateCallback(@NonNull Executor executor,
8389             @NonNull AudioServerStateCallback stateCallback) {
8390         if (stateCallback == null) {
8391             throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
8392         }
8393         if (executor == null) {
8394             throw new IllegalArgumentException(
8395                     "Illegal null Executor for the AudioServerStateCallback");
8396         }
8397 
8398         synchronized (mAudioServerStateCbLock) {
8399             if (mAudioServerStateCb != null) {
8400                 throw new IllegalStateException(
8401                     "setAudioServerStateCallback called with already registered callabck");
8402             }
8403             final IAudioService service = getService();
8404             try {
8405                 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
8406             } catch (RemoteException e) {
8407                 throw e.rethrowFromSystemServer();
8408             }
8409             mAudioServerStateExec = executor;
8410             mAudioServerStateCb = stateCallback;
8411         }
8412     }
8413 
8414     /**
8415      * @hide
8416      * Unregisters the callback for notification of audio server state changes.
8417      */
8418     @SystemApi
clearAudioServerStateCallback()8419     public void clearAudioServerStateCallback() {
8420         synchronized (mAudioServerStateCbLock) {
8421             if (mAudioServerStateCb != null) {
8422                 final IAudioService service = getService();
8423                 try {
8424                     service.unregisterAudioServerStateDispatcher(
8425                             mAudioServerStateDispatcher);
8426                 } catch (RemoteException e) {
8427                     throw e.rethrowFromSystemServer();
8428                 }
8429             }
8430             mAudioServerStateExec = null;
8431             mAudioServerStateCb = null;
8432         }
8433     }
8434 
8435     /**
8436      * @hide
8437      * Checks if native audioservice is running or not.
8438      * @return true if native audioservice runs, false otherwise.
8439      */
8440     @SystemApi
isAudioServerRunning()8441     public boolean isAudioServerRunning() {
8442         final IAudioService service = getService();
8443         try {
8444             return service.isAudioServerRunning();
8445         } catch (RemoteException e) {
8446             throw e.rethrowFromSystemServer();
8447         }
8448     }
8449 
8450     /**
8451      * Sets the surround sound mode.
8452      *
8453      * @return true if successful, otherwise false
8454      */
8455     @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)8456     public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
8457         try {
8458             return getService().setEncodedSurroundMode(mode);
8459         } catch (RemoteException e) {
8460             throw e.rethrowFromSystemServer();
8461         }
8462     }
8463 
8464     /**
8465      * Gets the surround sound mode.
8466      *
8467      * @return true if successful, otherwise false
8468      */
getEncodedSurroundMode()8469     public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
8470         try {
8471             return getService().getEncodedSurroundMode(
8472                     getContext().getApplicationInfo().targetSdkVersion);
8473         } catch (RemoteException e) {
8474             throw e.rethrowFromSystemServer();
8475         }
8476     }
8477 
8478     /**
8479      * @hide
8480      * Returns all surround formats.
8481      * @return a map where the key is a surround format and
8482      * the value indicates the surround format is enabled or not
8483      */
8484     @TestApi
8485     @NonNull
getSurroundFormats()8486     public Map<Integer, Boolean> getSurroundFormats() {
8487         try {
8488             return getService().getSurroundFormats();
8489         } catch (RemoteException e) {
8490             throw e.rethrowFromSystemServer();
8491         }
8492     }
8493 
8494     /**
8495      * Sets and persists a certain surround format as enabled or not.
8496      * <p>
8497      * This API is called by TvSettings surround sound menu when user enables or disables a
8498      * surround sound format. This setting is persisted as global user setting.
8499      * Applications should revert their changes to surround sound settings unless they intend to
8500      * modify the global user settings across all apps. The framework does not auto-revert an
8501      * application's settings after a lifecycle event. Audio focus is not required to apply these
8502      * settings.
8503      *
8504      * @param enabled the required surround format state, true for enabled, false for disabled
8505      * @return true if successful, otherwise false
8506      */
8507     @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)8508     public boolean setSurroundFormatEnabled(
8509             @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
8510         try {
8511             return getService().setSurroundFormatEnabled(audioFormat, enabled);
8512         } catch (RemoteException e) {
8513             throw e.rethrowFromSystemServer();
8514         }
8515     }
8516 
8517     /**
8518      * Gets whether a certain surround format is enabled or not.
8519      * @param audioFormat a surround format
8520      *
8521      * @return whether the required surround format is enabled
8522      */
isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)8523     public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
8524         try {
8525             return getService().isSurroundFormatEnabled(audioFormat);
8526         } catch (RemoteException e) {
8527             throw e.rethrowFromSystemServer();
8528         }
8529     }
8530 
8531     /**
8532      * @hide
8533      * Returns all surround formats that are reported by the connected HDMI device.
8534      * The return values are not affected by calling setSurroundFormatEnabled.
8535      *
8536      * @return a list of surround formats
8537      */
8538     @TestApi
8539     @NonNull
getReportedSurroundFormats()8540     public List<Integer> getReportedSurroundFormats() {
8541         try {
8542             return getService().getReportedSurroundFormats();
8543         } catch (RemoteException e) {
8544             throw e.rethrowFromSystemServer();
8545         }
8546     }
8547 
8548     /**
8549      * Return if audio haptic coupled playback is supported or not.
8550      *
8551      * @return whether audio haptic playback supported.
8552      */
isHapticPlaybackSupported()8553     public static boolean isHapticPlaybackSupported() {
8554         return AudioSystem.isHapticPlaybackSupported();
8555     }
8556 
8557     /**
8558      * @hide
8559      * Indicates whether a platform supports the Ultrasound feature which covers the playback
8560      * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the
8561      * usage will be
8562      * To start the Ultrasound playback:
8563      *     - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}.
8564      * To start the Ultrasound capture:
8565      *     - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}.
8566      *
8567      * @return whether the ultrasound feature is supported, true when platform supports both
8568      * Ultrasound playback and capture, false otherwise.
8569      */
8570     @SystemApi
8571     @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND)
isUltrasoundSupported()8572     public boolean isUltrasoundSupported() {
8573         try {
8574             return getService().isUltrasoundSupported();
8575         } catch (RemoteException e) {
8576             throw e.rethrowFromSystemServer();
8577         }
8578     }
8579 
8580     /**
8581      * @hide
8582      * Indicates whether the platform supports capturing content from the hotword recognition
8583      * pipeline. To capture content of this type, create an AudioRecord with
8584      * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}.
8585      * @param lookbackAudio Query if the hotword stream additionally supports providing buffered
8586      * audio prior to stream open.
8587      * @return True if the platform supports capturing hotword content, and if lookbackAudio
8588      * is true, if it additionally supports capturing buffered hotword content prior to stream
8589      * open. False otherwise.
8590      */
8591     @SystemApi
8592     @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
isHotwordStreamSupported(boolean lookbackAudio)8593     public boolean isHotwordStreamSupported(boolean lookbackAudio) {
8594         try {
8595             return getService().isHotwordStreamSupported(lookbackAudio);
8596         } catch (RemoteException e) {
8597             return false;
8598         }
8599     }
8600 
8601     /**
8602      * @hide
8603      * Introspection API to retrieve audio product strategies.
8604      * When implementing {Car|Oem}AudioManager, use this method  to retrieve the collection of
8605      * audio product strategies, which is indexed by a weakly typed index in order to be extended
8606      * by OEM without any needs of AOSP patches.
8607      * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
8608      * strategy refered either by its index or human readable string. It will allow clients
8609      * application to start streaming data using these {@link AudioAttributes} on the selected
8610      * device by Audio Policy Engine.
8611      * @return a (possibly zero-length) array of
8612      *         {@see android.media.audiopolicy.AudioProductStrategy} objects.
8613      */
8614     @SystemApi
8615     @NonNull
8616     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getAudioProductStrategies()8617     public static List<AudioProductStrategy> getAudioProductStrategies() {
8618         final IAudioService service = getService();
8619         try {
8620             return service.getAudioProductStrategies();
8621         } catch (RemoteException e) {
8622             throw e.rethrowFromSystemServer();
8623         }
8624     }
8625 
8626     /**
8627      * @hide
8628      * Introspection API to retrieve audio volume groups.
8629      * When implementing {Car|Oem}AudioManager, use this method  to retrieve the collection of
8630      * audio volume groups.
8631      * @return a (possibly zero-length) List of
8632      *         {@see android.media.audiopolicy.AudioVolumeGroup} objects.
8633      */
8634     @SystemApi
8635     @NonNull
8636     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
8637     // TODO also open to MODIFY_AUDIO_SETTINGS_PRIVILEGED b/341780042
getAudioVolumeGroups()8638     public static List<AudioVolumeGroup> getAudioVolumeGroups() {
8639         final IAudioService service = getService();
8640         try {
8641             return service.getAudioVolumeGroups();
8642         } catch (RemoteException e) {
8643             throw e.rethrowFromSystemServer();
8644         }
8645     }
8646 
8647     /**
8648      * @hide
8649      * Callback registered by client to be notified upon volume group change.
8650      */
8651     @SystemApi
8652     public abstract static class VolumeGroupCallback {
8653         /**
8654          * Callback method called upon audio volume group change.
8655          * @param group the group for which the volume has changed
8656          */
onAudioVolumeGroupChanged(int group, int flags)8657         public void onAudioVolumeGroupChanged(int group, int flags) {}
8658     }
8659 
8660    /**
8661     * @hide
8662     * Register an audio volume group change listener.
8663     * @param callback the {@link VolumeGroupCallback} to register
8664     */
8665     @SystemApi
registerVolumeGroupCallback( @onNull Executor executor, @NonNull VolumeGroupCallback callback)8666     public void registerVolumeGroupCallback(
8667             @NonNull Executor executor,
8668             @NonNull VolumeGroupCallback callback) {
8669         Preconditions.checkNotNull(executor, "executor must not be null");
8670         Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8671         sAudioAudioVolumeGroupChangedHandler.init();
8672         // TODO: make use of executor
8673         sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
8674     }
8675 
8676    /**
8677     * @hide
8678     * Unregister an audio volume group change listener.
8679     * @param callback the {@link VolumeGroupCallback} to unregister
8680     */
8681     @SystemApi
unregisterVolumeGroupCallback( @onNull VolumeGroupCallback callback)8682     public void unregisterVolumeGroupCallback(
8683             @NonNull VolumeGroupCallback callback) {
8684         Preconditions.checkNotNull(callback, "volume group change cb must not be null");
8685         sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
8686     }
8687 
8688     /**
8689      * Return if an asset contains haptic channels or not.
8690      *
8691      * @param context the {@link Context} to resolve the uri.
8692      * @param uri the {@link Uri} of the asset.
8693      * @return true if the assert contains haptic channels.
8694      * @hide
8695      */
hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)8696     public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
8697         MediaExtractor extractor = new MediaExtractor();
8698         try {
8699             extractor.setDataSource(context, uri, null);
8700             for (int i = 0; i < extractor.getTrackCount(); i++) {
8701                 MediaFormat format = extractor.getTrackFormat(i);
8702                 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
8703                         && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
8704                     return true;
8705                 }
8706             }
8707         } catch (IOException e) {
8708             Log.e(TAG, "hasHapticChannels failure:" + e);
8709         }
8710         return false;
8711     }
8712 
8713     /**
8714      * Return if an asset contains haptic channels or not.
8715      *
8716      * @param context the {@link Context} to resolve the uri.
8717      * @param uri the {@link Uri} of the asset.
8718      * @return true if the assert contains haptic channels.
8719      * @hide
8720      */
hasHapticChannels(@ullable Context context, @NonNull Uri uri)8721     public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
8722         Objects.requireNonNull(uri);
8723 
8724         if (context != null) {
8725             return hasHapticChannelsImpl(context, uri);
8726         }
8727 
8728         Context cachedContext = sContext.get();
8729         if (cachedContext != null) {
8730             if (DEBUG) {
8731                 Log.d(TAG, "Try to use static context to query if having haptic channels");
8732             }
8733             return hasHapticChannelsImpl(cachedContext, uri);
8734         }
8735 
8736         // Try with audio service context, this may fail to get correct result.
8737         if (DEBUG) {
8738             Log.d(TAG, "Try to use audio service context to query if having haptic channels");
8739         }
8740         try {
8741             return getService().hasHapticChannels(uri);
8742         } catch (RemoteException e) {
8743             throw e.rethrowFromSystemServer();
8744         }
8745     }
8746 
8747     /**
8748      * Set whether or not there is an active RTT call.
8749      * This method should be called by Telecom service.
8750      * @hide
8751      * TODO: make this a @SystemApi
8752      */
setRttEnabled(boolean rttEnabled)8753     public static void setRttEnabled(boolean rttEnabled) {
8754         try {
8755             getService().setRttEnabled(rttEnabled);
8756         } catch (RemoteException e) {
8757             throw e.rethrowFromSystemServer();
8758         }
8759     }
8760 
8761     /**
8762      * Adjusts the volume of the most relevant stream, or the given fallback
8763      * stream.
8764      * <p>
8765      * This method should only be used by applications that replace the
8766      * platform-wide management of audio settings or the main telephony
8767      * application.
8768      * <p>
8769      * This method has no effect if the device implements a fixed volume policy
8770      * as indicated by {@link #isVolumeFixed()}.
8771      * <p>This API checks if the caller has the necessary permissions based on the provided
8772      * component name, uid, and pid values.
8773      * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
8774      *
8775      * @param suggestedStreamType The stream type that will be used if there
8776      *         isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
8777      *         valid here.
8778      * @param direction The direction to adjust the volume. One of
8779      *         {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
8780      *         {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
8781      *         {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
8782      * @param flags
8783      * @param packageName the package name of client application
8784      * @param uid the uid of client application
8785      * @param pid the pid of client application
8786      * @param targetSdkVersion the target sdk version of client application
8787      * @see #adjustVolume(int, int)
8788      * @see #adjustStreamVolume(int, int, int)
8789      * @see #setStreamVolume(int, int, int)
8790      * @see #isVolumeFixed()
8791      *
8792      * @hide
8793      */
8794     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8795     public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction,
8796             @SystemVolumeFlags int flags,
8797             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8798         try {
8799             getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
8800                     packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8801         } catch (RemoteException e) {
8802             throw e.rethrowFromSystemServer();
8803         }
8804     }
8805 
8806     /**
8807      * Adjusts the volume of a particular stream by one step in a direction.
8808      * <p>
8809      * This method should only be used by applications that replace the platform-wide
8810      * management of audio settings or the main telephony application.
8811      * <p>This method has no effect if the device implements a fixed volume policy
8812      * as indicated by {@link #isVolumeFixed()}.
8813      * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
8814      * unless the app has been granted Do Not Disturb Access.
8815      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8816      * <p>This API checks if the caller has the necessary permissions based on the provided
8817      * component name, uid, and pid values.
8818      * See {@link #adjustStreamVolume(int, int, int)}.
8819      *
8820      * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
8821      *         {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
8822      *         {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
8823      * @param direction The direction to adjust the volume. One of
8824      *         {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
8825      *         {@link #ADJUST_SAME}.
8826      * @param flags
8827      * @param packageName the package name of client application
8828      * @param uid the uid of client application
8829      * @param pid the pid of client application
8830      * @param targetSdkVersion the target sdk version of client application
8831      * @see #adjustVolume(int, int)
8832      * @see #setStreamVolume(int, int, int)
8833      * @throws SecurityException if the adjustment triggers a Do Not Disturb change
8834      *         and the caller is not granted notification policy access.
8835      *
8836      * @hide
8837      */
8838     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
adjustStreamVolumeForUid(int streamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8839     public void adjustStreamVolumeForUid(int streamType, int direction,
8840             @SystemVolumeFlags int flags,
8841             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8842         try {
8843             getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
8844                     pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8845         } catch (RemoteException e) {
8846             throw e.rethrowFromSystemServer();
8847         }
8848     }
8849 
8850     /**
8851      * Sets the volume index for a particular stream.
8852      * <p>This method has no effect if the device implements a fixed volume policy
8853      * as indicated by {@link #isVolumeFixed()}.
8854      * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
8855      * the app has been granted Do Not Disturb Access.
8856      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
8857      * <p>This API checks if the caller has the necessary permissions based on the provided
8858      * component name, uid, and pid values.
8859      * See {@link #setStreamVolume(int, int, int)}.
8860      *
8861      * @param streamType The stream whose volume index should be set.
8862      * @param index The volume index to set. See
8863      *         {@link #getStreamMaxVolume(int)} for the largest valid value.
8864      * @param flags
8865      * @param packageName the package name of client application
8866      * @param uid the uid of client application
8867      * @param pid the pid of client application
8868      * @param targetSdkVersion the target sdk version of client application
8869      * @see #getStreamMaxVolume(int)
8870      * @see #getStreamVolume(int)
8871      * @see #isVolumeFixed()
8872      * @throws SecurityException if the volume change triggers a Do Not Disturb change
8873      *         and the caller is not granted notification policy access.
8874      *
8875      * @hide
8876      */
8877     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
setStreamVolumeForUid(int streamType, int index, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8878     public void setStreamVolumeForUid(int streamType, int index,
8879             @SystemVolumeFlags int flags,
8880             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
8881         try {
8882             getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
8883                     UserHandle.getUserHandleForUid(uid), targetSdkVersion);
8884         } catch (RemoteException e) {
8885             throw e.rethrowFromSystemServer();
8886         }
8887     }
8888 
8889 
8890     /** @hide
8891      * TODO: make this a @SystemApi */
8892     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setMultiAudioFocusEnabled(boolean enabled)8893     public void setMultiAudioFocusEnabled(boolean enabled) {
8894         try {
8895             getService().setMultiAudioFocusEnabled(enabled);
8896         } catch (RemoteException e) {
8897             throw e.rethrowFromSystemServer();
8898         }
8899     }
8900 
8901 
8902     /**
8903      * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
8904      * For more details on Hardware A/V synchronization please refer to
8905      *  <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
8906      * media tunneling documentation</a>.
8907      * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
8908      * @return the HW A/V sync ID for this audio session (an integer different from 0).
8909      * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
8910      */
getAudioHwSyncForSession(int sessionId)8911     public int getAudioHwSyncForSession(int sessionId) {
8912         int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
8913         if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
8914             throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
8915         }
8916         return hwSyncId;
8917     }
8918 
8919     /**
8920      * Selects the audio device that should be used for communication use cases, for instance voice
8921      * or video calls. This method can be used by voice or video chat applications to select a
8922      * different audio device than the one selected by default by the platform.
8923      * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
8924      * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
8925      * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
8926      * source device is selected automatically by the platform.
8927      * <p>The selection is active as long as the requesting application process lives, until
8928      * {@link #clearCommunicationDevice} is called or until the device is disconnected.
8929      * It is therefore important for applications to clear the request when a call ends or the
8930      * the requesting activity or service is stopped or destroyed.
8931      * <p>In case of simultaneous requests by multiple applications the priority is given to the
8932      * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
8933      * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
8934      * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
8935      * telephony application with permission
8936      * {@link Manifest.permission#MODIFY_PHONE_STATE}.
8937      * <p> If the requested devices is not currently available, the request will be rejected and
8938      * the method will return false.
8939      * <p>This API replaces the following deprecated APIs:
8940      * <ul>
8941      *   <li> {@link #startBluetoothSco()}
8942      *   <li> {@link #stopBluetoothSco()}
8943      *   <li> {@link #setSpeakerphoneOn(boolean)}
8944      * </ul>
8945      * <h4>Example</h4>
8946      * <p>The example below shows how to enable and disable speakerphone mode.
8947      * <pre class="prettyprint">
8948      * // Get an AudioManager instance
8949      * AudioManager audioManager = Context.getSystemService(AudioManager.class);
8950      * AudioDeviceInfo speakerDevice = null;
8951      * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
8952      * for (AudioDeviceInfo device : devices) {
8953      *     if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
8954      *         speakerDevice = device;
8955      *         break;
8956      *     }
8957      * }
8958      * if (speakerDevice != null) {
8959      *     // Turn speakerphone ON.
8960      *     boolean result = audioManager.setCommunicationDevice(speakerDevice);
8961      *     if (!result) {
8962      *         // Handle error.
8963      *     }
8964      *     // Turn speakerphone OFF.
8965      *     audioManager.clearCommunicationDevice();
8966      * }
8967      * </pre>
8968      * @param device the requested audio device.
8969      * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
8970      * @throws IllegalArgumentException If an invalid device is specified.
8971      */
setCommunicationDevice(@onNull AudioDeviceInfo device)8972     public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
8973         Objects.requireNonNull(device);
8974         try {
8975             if (device.getId() == 0) {
8976                 Log.w(TAG, "setCommunicationDevice: device not found: " + device);
8977                 return false;
8978             }
8979             return getService().setCommunicationDevice(mICallBack, device.getId());
8980         } catch (RemoteException e) {
8981             throw e.rethrowFromSystemServer();
8982         }
8983     }
8984 
8985     /**
8986      * Cancels previous communication device selection made with
8987      * {@link #setCommunicationDevice(AudioDeviceInfo)}.
8988      */
clearCommunicationDevice()8989     public void clearCommunicationDevice() {
8990         try {
8991             getService().setCommunicationDevice(mICallBack, 0);
8992         } catch (RemoteException e) {
8993             throw e.rethrowFromSystemServer();
8994         }
8995     }
8996 
8997     /**
8998      * Returns currently selected audio device for communication.
8999      * <p>This API replaces the following deprecated APIs:
9000      * <ul>
9001      *   <li> {@link #isBluetoothScoOn()}
9002      *   <li> {@link #isSpeakerphoneOn()}
9003      * </ul>
9004      * @return an {@link AudioDeviceInfo} indicating which audio device is
9005      * currently selected for communication use cases. Can be null on platforms
9006      * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
9007      * is used.
9008      */
9009     @Nullable
getCommunicationDevice()9010     public AudioDeviceInfo getCommunicationDevice() {
9011         try {
9012             return getDeviceForPortId(
9013                     getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
9014         } catch (RemoteException e) {
9015             throw e.rethrowFromSystemServer();
9016         }
9017     }
9018 
9019     /**
9020      * Returns a list of audio devices that can be selected for communication use cases via
9021      * {@link #setCommunicationDevice(AudioDeviceInfo)}.
9022      * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
9023      */
9024     @NonNull
getAvailableCommunicationDevices()9025     public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
9026         try {
9027             ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
9028             int[] portIds = getService().getAvailableCommunicationDeviceIds();
9029             for (int portId : portIds) {
9030                 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
9031                 if (device == null) {
9032                     continue;
9033                 }
9034                 devices.add(device);
9035             }
9036             return devices;
9037         } catch (RemoteException e) {
9038             throw e.rethrowFromSystemServer();
9039         }
9040     }
9041 
9042     /**
9043      * Returns a list of direct {@link AudioProfile} that are supported for the specified
9044      * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback
9045      * is possible.
9046      *
9047      * <p>Direct playback means that the audio stream is not resampled or downmixed
9048      * by the framework. Checking for direct support can help the app select the representation
9049      * of audio content that most closely matches the capabilities of the device and peripherals
9050      * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded
9051      * or mixed with other streams, if needed.
9052      * <p>When using this information to inform your application which audio format to play,
9053      * query again whenever audio output devices change (see {@link AudioDeviceCallback}).
9054      * @param attributes a non-null {@link AudioAttributes} instance.
9055      * @return a list of {@link AudioProfile}
9056      */
9057     @NonNull
getDirectProfilesForAttributes(@onNull AudioAttributes attributes)9058     public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) {
9059         Objects.requireNonNull(attributes);
9060         ArrayList<AudioProfile> audioProfilesList = new ArrayList<>();
9061         int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList);
9062         if (status != SUCCESS) {
9063             Log.w(TAG, "getDirectProfilesForAttributes failed.");
9064             return new ArrayList<>();
9065         }
9066         return audioProfilesList;
9067     }
9068 
9069     /**
9070      * @hide
9071      * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
9072      * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
9073      * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
9074      * The method will return null if no device of the provided type is connected.
9075      * If more than one device of the provided type is connected, an object corresponding to the
9076      * first device encountered in the enumeration list will be returned.
9077      * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
9078      *                   object is queried.
9079      * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
9080      * @throws IllegalArgumentException If an invalid device type is specified.
9081      */
9082     @TestApi
9083     @Nullable
getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)9084     public static AudioDeviceInfo getDeviceInfoFromType(
9085             @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
9086         return getDeviceInfoFromTypeAndAddress(deviceType, null);
9087     }
9088 
9089     /**
9090      * @hide
9091      * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
9092      * address provided.
9093      * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
9094      * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
9095      * If a null address is provided, the matching will happen on the type only.
9096      * The method will return null if no device of the provided type and address is connected.
9097      * If more than one device of the provided type is connected, an object corresponding to the
9098      * first device encountered in the enumeration list will be returned.
9099      * @param type The device device for which an <code>AudioDeviceInfo</code>
9100      *             object is queried.
9101      * @param address The device address for which an <code>AudioDeviceInfo</code>
9102      *                object is queried or null if requesting match on type only.
9103      * @return An AudioDeviceInfo object or null if no matching device is connected.
9104      * @throws IllegalArgumentException If an invalid device type is specified.
9105      */
9106     @Nullable
getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)9107     public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
9108             @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
9109         AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
9110         AudioDeviceInfo deviceForType = null;
9111         for (AudioDeviceInfo device : devices) {
9112             if (device.getType() == type) {
9113                 deviceForType = device;
9114                 if (address == null || address.equals(device.getAddress())) {
9115                     return device;
9116                 }
9117             }
9118         }
9119         return deviceForType;
9120     }
9121 
9122     /**
9123      * Listener registered by client to be notified upon communication audio device change.
9124      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
9125      */
9126     public interface OnCommunicationDeviceChangedListener {
9127         /**
9128          * Callback method called upon communication audio device change.
9129          * @param device the audio device requested for communication use cases.
9130          *               Can be null on platforms not supporting
9131          *               {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
9132          */
onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)9133         void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
9134     }
9135 
9136     /**
9137      * manages the OnCommunicationDeviceChangedListener listeners and the
9138      * CommunicationDeviceDispatcherStub
9139      */
9140     private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
9141             mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
9142     /**
9143      * Adds a listener for being notified of changes to the communication audio device.
9144      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
9145      * @param executor
9146      * @param listener
9147      */
addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)9148     public void addOnCommunicationDeviceChangedListener(
9149             @NonNull @CallbackExecutor Executor executor,
9150             @NonNull OnCommunicationDeviceChangedListener listener) {
9151         mCommDeviceChangedListenerMgr.addListener(
9152                             executor, listener, "addOnCommunicationDeviceChangedListener",
9153                             () -> new CommunicationDeviceDispatcherStub());
9154     }
9155 
9156     /**
9157      * Removes a previously added listener of changes to the communication audio device.
9158      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
9159      * @param listener
9160      */
removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)9161     public void removeOnCommunicationDeviceChangedListener(
9162             @NonNull OnCommunicationDeviceChangedListener listener) {
9163         mCommDeviceChangedListenerMgr.removeListener(listener,
9164                 "removeOnCommunicationDeviceChangedListener");
9165     }
9166 
9167     private final class CommunicationDeviceDispatcherStub
9168             extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {
9169 
9170         @Override
register(boolean register)9171         public void register(boolean register) {
9172             try {
9173                 if (register) {
9174                     getService().registerCommunicationDeviceDispatcher(this);
9175                 } else {
9176                     getService().unregisterCommunicationDeviceDispatcher(this);
9177                 }
9178             } catch (RemoteException e) {
9179                 e.rethrowFromSystemServer();
9180             }
9181         }
9182 
9183         @Override
dispatchCommunicationDeviceChanged(int portId)9184         public void dispatchCommunicationDeviceChanged(int portId) {
9185             AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
9186             mCommDeviceChangedListenerMgr.callListeners(
9187                     (listener) -> listener.onCommunicationDeviceChanged(device));
9188         }
9189     }
9190 
9191 
9192     /**
9193      * @hide
9194      * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing
9195      * PSTN call.
9196      * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain
9197      * an AudioTrack for call uplink audio injection and
9198      * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain
9199      * an AudioRecord for call downlink audio extraction.
9200      * @return true if PSTN call audio is accessible, false otherwise.
9201      */
9202     @TestApi
9203     @SystemApi
9204     @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
isPstnCallAudioInterceptable()9205     public boolean isPstnCallAudioInterceptable() {
9206         final IAudioService service = getService();
9207         try {
9208             return service.isPstnCallAudioInterceptable();
9209         } catch (RemoteException e) {
9210             throw e.rethrowFromSystemServer();
9211         }
9212     }
9213 
9214     /** @hide */
9215     @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = {
9216             CALL_REDIRECT_NONE,
9217             CALL_REDIRECT_PSTN,
9218             CALL_REDIRECT_VOIP }
9219             )
9220     @Retention(RetentionPolicy.SOURCE)
9221     public @interface CallRedirectionMode {}
9222 
9223     /**
9224      * Not used for call redirection
9225      * @hide
9226      */
9227     public static final int CALL_REDIRECT_NONE = 0;
9228     /**
9229      * Used to redirect  PSTN call
9230      * @hide
9231      */
9232     public static final int CALL_REDIRECT_PSTN = 1;
9233     /**
9234      * Used to redirect  VoIP call
9235      * @hide
9236      */
9237     public static final int CALL_REDIRECT_VOIP = 2;
9238 
9239 
getCallRedirectMode()9240     private @CallRedirectionMode int getCallRedirectMode() {
9241         int mode = getMode();
9242         if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING
9243                 || mode == MODE_CALL_REDIRECT) {
9244             return CALL_REDIRECT_PSTN;
9245         } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) {
9246             return CALL_REDIRECT_VOIP;
9247         }
9248         return CALL_REDIRECT_NONE;
9249     }
9250 
checkCallRedirectionFormat(AudioFormat format, boolean isOutput)9251     private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) {
9252         if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT
9253                 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) {
9254             throw new UnsupportedOperationException(" Unsupported encoding ");
9255         }
9256         if (format.getSampleRate() < 8000
9257                 || format.getSampleRate() > 48000) {
9258             throw new UnsupportedOperationException(" Unsupported sample rate ");
9259         }
9260         if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO
9261                 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) {
9262             throw new UnsupportedOperationException(" Unsupported output channel mask ");
9263         }
9264         if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO
9265                 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) {
9266             throw new UnsupportedOperationException(" Unsupported input channel mask ");
9267         }
9268     }
9269 
9270     class CallIRedirectionClientInfo {
9271         public WeakReference trackOrRecord;
9272         public int redirectMode;
9273     }
9274 
9275     private Object mCallRedirectionLock = new Object();
9276     @GuardedBy("mCallRedirectionLock")
9277     private CallInjectionModeChangedListener mCallRedirectionModeListener;
9278     @GuardedBy("mCallRedirectionLock")
9279     private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients;
9280 
9281     /**
9282      * @hide
9283      * Returns an AudioTrack that can be used to inject audio to an active call uplink.
9284      * This can be used for functions like call screening or call audio redirection and is reserved
9285      * to system apps with privileged permission.
9286      * @param format the desired audio format for audio playback.
9287      * p>Formats accepted are:
9288      * <ul>
9289      *   <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
9290      *   <li><em>Channel mask</em> - Mono or Stereo </li>
9291      *   <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
9292      * </ul>
9293      *
9294      * @return The AudioTrack used for audio injection
9295      * @throws NullPointerException if AudioFormat argument is null.
9296      * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
9297      * @throws IllegalArgumentException if an invalid AudioFormat is specified.
9298      * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION  is missing .
9299      * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
9300      *         MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
9301      *         or MODE_COMMUNICATION_REDIRECT.
9302      */
9303     @TestApi
9304     @SystemApi
9305     @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
getCallUplinkInjectionAudioTrack(@onNull AudioFormat format)9306     public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) {
9307         Objects.requireNonNull(format);
9308         checkCallRedirectionFormat(format, true /* isOutput */);
9309 
9310         AudioTrack track = null;
9311         int redirectMode = getCallRedirectMode();
9312         if (redirectMode == CALL_REDIRECT_NONE) {
9313             throw new IllegalStateException(
9314                     " not available in mode " + AudioSystem.modeToString(getMode()));
9315         } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
9316             throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
9317         }
9318 
9319         track = new AudioTrack.Builder()
9320                 .setAudioAttributes(new AudioAttributes.Builder()
9321                         .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT)
9322                         .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
9323                         .build())
9324                 .setAudioFormat(format)
9325                 .setCallRedirectionMode(redirectMode)
9326                 .build();
9327 
9328         if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) {
9329             synchronized (mCallRedirectionLock) {
9330                 if (mCallRedirectionModeListener == null) {
9331                     mCallRedirectionModeListener = new CallInjectionModeChangedListener();
9332                     try {
9333                         addOnModeChangedListener(
9334                                 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
9335                     } catch (Exception e) {
9336                         Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
9337                         mCallRedirectionModeListener = null;
9338                         throw new UnsupportedOperationException(" Cannot register mode listener ");
9339                     }
9340                     mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
9341                 }
9342                 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
9343                 info.redirectMode = redirectMode;
9344                 info.trackOrRecord = new WeakReference<AudioTrack>(track);
9345                 mCallIRedirectionClients.add(info);
9346             }
9347         } else {
9348             throw new UnsupportedOperationException(" Cannot create the AudioTrack");
9349         }
9350         return track;
9351     }
9352 
9353     /**
9354      * @hide
9355      * Returns an AudioRecord that can be used to extract audio from an active call downlink.
9356      * This can be used for functions like call screening or call audio redirection and is reserved
9357      * to system apps with privileged permission.
9358      * @param format the desired audio format for audio capture.
9359      *<p>Formats accepted are:
9360      * <ul>
9361      *   <li><em>Sampling rate</em> - 8kHz to 48kHz. </li>
9362      *   <li><em>Channel mask</em> - Mono or Stereo </li>
9363      *   <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li>
9364      * </ul>
9365      *
9366      * @return The AudioRecord used for audio extraction
9367      * @throws UnsupportedOperationException if on unsupported AudioFormat is specified.
9368      * @throws IllegalArgumentException if an invalid AudioFormat is specified.
9369      * @throws NullPointerException if AudioFormat argument is null.
9370      * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION  is missing .
9371      * @throws IllegalStateException if current audio mode is not MODE_IN_CALL,
9372      *         MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT
9373      *         or MODE_COMMUNICATION_REDIRECT.
9374      */
9375     @TestApi
9376     @SystemApi
9377     @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION)
getCallDownlinkExtractionAudioRecord(@onNull AudioFormat format)9378     public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) {
9379         Objects.requireNonNull(format);
9380         checkCallRedirectionFormat(format, false /* isOutput */);
9381 
9382         AudioRecord record = null;
9383         int redirectMode = getCallRedirectMode();
9384         if (redirectMode == CALL_REDIRECT_NONE) {
9385             throw new IllegalStateException(
9386                     " not available in mode " + AudioSystem.modeToString(getMode()));
9387         } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) {
9388             throw new UnsupportedOperationException(" PSTN Call audio not accessible ");
9389         }
9390 
9391         record = new AudioRecord.Builder()
9392                 .setAudioAttributes(new AudioAttributes.Builder()
9393                         .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK)
9394                         .build())
9395                 .setAudioFormat(format)
9396                 .setCallRedirectionMode(redirectMode)
9397                 .build();
9398 
9399         if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) {
9400             synchronized (mCallRedirectionLock) {
9401                 if (mCallRedirectionModeListener == null) {
9402                     mCallRedirectionModeListener = new CallInjectionModeChangedListener();
9403                     try {
9404                         addOnModeChangedListener(
9405                                 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener);
9406                     } catch (Exception e) {
9407                         Log.e(TAG, "addOnModeChangedListener failed with exception: " + e);
9408                         mCallRedirectionModeListener = null;
9409                         throw new UnsupportedOperationException(" Cannot register mode listener ");
9410                     }
9411                     mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>();
9412                 }
9413                 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo();
9414                 info.redirectMode = redirectMode;
9415                 info.trackOrRecord = new WeakReference<AudioRecord>(record);
9416                 mCallIRedirectionClients.add(info);
9417             }
9418         } else {
9419             throw new UnsupportedOperationException(" Cannot create the AudioRecord");
9420         }
9421         return record;
9422     }
9423 
9424     class CallInjectionModeChangedListener implements OnModeChangedListener {
9425         @Override
onModeChanged(@udioMode int mode)9426         public void onModeChanged(@AudioMode int mode) {
9427             synchronized (mCallRedirectionLock) {
9428                 final ArrayList<CallIRedirectionClientInfo> clientInfos =
9429                         (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone();
9430                 for (CallIRedirectionClientInfo info : clientInfos) {
9431                     Object trackOrRecord = info.trackOrRecord.get();
9432                     if (trackOrRecord != null) {
9433                         if ((info.redirectMode ==  CALL_REDIRECT_PSTN
9434                                 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING
9435                                 && mode != MODE_CALL_REDIRECT)
9436                                 || (info.redirectMode == CALL_REDIRECT_VOIP
9437                                     && mode != MODE_IN_COMMUNICATION
9438                                     && mode != MODE_COMMUNICATION_REDIRECT)) {
9439                             if (trackOrRecord instanceof AudioTrack) {
9440                                 AudioTrack track = (AudioTrack) trackOrRecord;
9441                                 track.release();
9442                             } else {
9443                                 AudioRecord record = (AudioRecord) trackOrRecord;
9444                                 record.release();
9445                             }
9446                             mCallIRedirectionClients.remove(info);
9447                         }
9448                     }
9449                 }
9450                 if (mCallIRedirectionClients.isEmpty()) {
9451                     try {
9452                         if (mCallRedirectionModeListener != null) {
9453                             removeOnModeChangedListener(mCallRedirectionModeListener);
9454                         }
9455                     } catch (Exception e) {
9456                         Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e);
9457                     } finally {
9458                         mCallRedirectionModeListener = null;
9459                         mCallIRedirectionClients = null;
9460                     }
9461                 }
9462             }
9463         }
9464     }
9465 
9466     //---------------------------------------------------------
9467     // audio device connection-dependent muting
9468     /**
9469      * @hide
9470      * Mute a set of playback use cases until a given audio device is connected.
9471      * Automatically unmute upon connection of the device, or after the given timeout, whichever
9472      * happens first.
9473      * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example
9474      *                     {@link AudioAttributes#USAGE_MEDIA}) to mute until the
9475      *                     device connects
9476      * @param device the audio device expected to connect within the timeout duration
9477      * @param timeout the maximum amount of time to wait for the device connection
9478      * @param timeUnit the unit for the timeout
9479      * @throws IllegalStateException when trying to issue the command while another is already in
9480      *         progress and hasn't been cancelled by
9481      *         {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See
9482      *         {@link #getMutingExpectedDevice()} to check if a muting command is active.
9483      * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
9484      */
9485     @SystemApi
9486     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
muteAwaitConnection(@onNull int[] usagesToMute, @NonNull AudioDeviceAttributes device, long timeout, @NonNull TimeUnit timeUnit)9487     public void muteAwaitConnection(@NonNull int[] usagesToMute,
9488             @NonNull AudioDeviceAttributes device,
9489             long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException {
9490         if (timeout <= 0) {
9491             throw new IllegalArgumentException("Timeout must be greater than 0");
9492         }
9493         Objects.requireNonNull(usagesToMute);
9494         if (usagesToMute.length == 0) {
9495             throw new IllegalArgumentException("Array of usages to mute cannot be empty");
9496         }
9497         Objects.requireNonNull(device);
9498         Objects.requireNonNull(timeUnit);
9499         try {
9500             getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout));
9501         } catch (RemoteException e) {
9502             throw e.rethrowFromSystemServer();
9503         }
9504     }
9505 
9506     /**
9507      * @hide
9508      * Query which audio device, if any, is causing some playback use cases to be muted until it
9509      * connects.
9510      * @return the audio device used in
9511      *        {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null
9512      *        if there is no active muting command (either because the muting command was not issued
9513      *        or because it timed out)
9514      */
9515     @SystemApi
9516     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getMutingExpectedDevice()9517     public @Nullable AudioDeviceAttributes getMutingExpectedDevice() {
9518         try {
9519             return getService().getMutingExpectedDevice();
9520         } catch (RemoteException e) {
9521             throw e.rethrowFromSystemServer();
9522         }
9523     }
9524 
9525     /**
9526      * @hide
9527      * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
9528      * command.
9529      * @param device the device whose connection was expected when the {@code muteAwaitConnection}
9530      *               command was issued.
9531      * @throws IllegalStateException when trying to issue the command for a device whose connection
9532      *         is not anticipated by a previous call to
9533      *         {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}
9534      */
9535     @SystemApi
9536     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
cancelMuteAwaitConnection(@onNull AudioDeviceAttributes device)9537     public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device)
9538             throws IllegalStateException {
9539         Objects.requireNonNull(device);
9540         try {
9541             getService().cancelMuteAwaitConnection(device);
9542         } catch (RemoteException e) {
9543             throw e.rethrowFromSystemServer();
9544         }
9545     }
9546 
9547     /**
9548      * @hide
9549      * A callback class to receive events about the muting and unmuting of playback use cases
9550      * conditional on the upcoming connection of an audio device.
9551      * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback)
9552      */
9553     @SystemApi
9554     public abstract static class MuteAwaitConnectionCallback {
9555 
9556         /**
9557          * An event where the expected audio device connected
9558          * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9559          */
9560         public static final int EVENT_CONNECTION = 1;
9561         /**
9562          * An event where the expected audio device failed connect before the timeout happened
9563          * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9564          */
9565         public static final int EVENT_TIMEOUT    = 2;
9566         /**
9567          * An event where the {@code muteAwaitConnection()} command
9568          * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}
9569          * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[])
9570          */
9571         public static final int EVENT_CANCEL     = 3;
9572 
9573         /** @hide */
9574         @IntDef(flag = false, prefix = "EVENT_", value = {
9575                 EVENT_CONNECTION,
9576                 EVENT_TIMEOUT,
9577                 EVENT_CANCEL }
9578         )
9579         @Retention(RetentionPolicy.SOURCE)
9580         public @interface UnmuteEvent {}
9581 
9582         /**
9583          * Called when a number of playback use cases are muted in response to a call to
9584          * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}.
9585          * @param device the audio device whose connection is expected. Playback use cases are
9586          *               unmuted when that device connects
9587          * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected
9588          *                    playback use cases.
9589          */
onMutedUntilConnection( @onNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9590         public void onMutedUntilConnection(
9591                 @NonNull AudioDeviceAttributes device,
9592                 @NonNull int[] mutedUsages) {}
9593 
9594         /**
9595          * Called when an event occurred that caused playback uses cases to be unmuted
9596          * @param unmuteEvent the nature of the event
9597          * @param device the device that was expected to connect
9598          * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until
9599          *                    the event occurred
9600          */
onUnmutedEvent( @nmuteEvent int unmuteEvent, @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9601         public void onUnmutedEvent(
9602                 @UnmuteEvent int unmuteEvent,
9603                 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {}
9604     }
9605 
9606 
9607     /**
9608      * @hide
9609      * Register a callback to receive updates on the playback muting conditional on a specific
9610      * audio device connection.
9611      * @param executor the {@link Executor} handling the callback
9612      * @param callback the callback to register
9613      */
9614     @SystemApi
9615     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
registerMuteAwaitConnectionCallback( @onNull @allbackExecutor Executor executor, @NonNull MuteAwaitConnectionCallback callback)9616     public void registerMuteAwaitConnectionCallback(
9617             @NonNull @CallbackExecutor Executor executor,
9618             @NonNull MuteAwaitConnectionCallback callback) {
9619         synchronized (mMuteAwaitConnectionListenerLock) {
9620             final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9621                     MuteAwaitConnectionDispatcherStub> res =
9622                     CallbackUtil.addListener("registerMuteAwaitConnectionCallback",
9623                             executor, callback, mMuteAwaitConnectionListeners,
9624                             mMuteAwaitConnDispatcherStub,
9625                             () -> new MuteAwaitConnectionDispatcherStub(),
9626                             stub -> stub.register(true));
9627             mMuteAwaitConnectionListeners = res.first;
9628             mMuteAwaitConnDispatcherStub = res.second;
9629         }
9630     }
9631 
9632     /**
9633      * @hide
9634      * Unregister a previously registered callback for playback muting conditional on device
9635      * connection.
9636      * @param callback the callback to unregister
9637      */
9638     @SystemApi
9639     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
unregisterMuteAwaitConnectionCallback( @onNull MuteAwaitConnectionCallback callback)9640     public void unregisterMuteAwaitConnectionCallback(
9641             @NonNull MuteAwaitConnectionCallback callback) {
9642         synchronized (mMuteAwaitConnectionListenerLock) {
9643             final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>,
9644                     MuteAwaitConnectionDispatcherStub> res =
9645                     CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback",
9646                             callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub,
9647                             stub -> stub.register(false));
9648             mMuteAwaitConnectionListeners = res.first;
9649             mMuteAwaitConnDispatcherStub = res.second;
9650         }
9651     }
9652 
9653     /**
9654      * Add UIDs that can be considered as assistant.
9655      *
9656      * @param assistantUids UIDs of the services that can be considered as assistant.
9657      *
9658      * @hide
9659      */
9660     @SystemApi
9661     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
addAssistantServicesUids(@onNull int[] assistantUids)9662     public void addAssistantServicesUids(@NonNull int[] assistantUids) {
9663         try {
9664             getService().addAssistantServicesUids(assistantUids);
9665         } catch (RemoteException e) {
9666             throw e.rethrowFromSystemServer();
9667         }
9668     }
9669 
9670     /**
9671      * Remove UIDs that can be considered as assistant.
9672      *
9673      * @param assistantUids UIDs of the services that should be remove.
9674      *
9675      * @hide
9676      */
9677     @SystemApi
9678     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
removeAssistantServicesUids(@onNull int[] assistantUids)9679     public void removeAssistantServicesUids(@NonNull int[] assistantUids) {
9680         try {
9681             getService().removeAssistantServicesUids(assistantUids);
9682         } catch (RemoteException e) {
9683             throw e.rethrowFromSystemServer();
9684         }
9685     }
9686 
9687     /**
9688      * Get the assistants UIDs that been added with the
9689      * {@link #addAssistantServicesUids(int[])} and not yet removed with
9690      * {@link #removeAssistantServicesUids(int[])}
9691      *
9692      * <p> Note that during native audioserver crash and after boot up the list of assistant
9693      * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant)
9694      * Just after user switch, the list of assistant will also reset to empty.
9695      * In both cases,The component's UID of the assistiant role or assistant setting will be
9696      * automitically added to the list by the audio service.
9697      *
9698      * @return array of assistants UIDs
9699      *
9700      * @hide
9701      */
9702     @SystemApi
9703     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getAssistantServicesUids()9704     public @NonNull int[] getAssistantServicesUids() {
9705         try {
9706             int[] uids = getService().getAssistantServicesUids();
9707             return Arrays.copyOf(uids, uids.length);
9708         } catch (RemoteException e) {
9709             throw e.rethrowFromSystemServer();
9710         }
9711     }
9712 
9713     /**
9714      * Sets UIDs that can be considered as active assistant. Calling the API with a new array will
9715      * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active.
9716      * In this manner calling the API with an empty array will remove all UIDs previously set.
9717      *
9718      * @param assistantUids UIDs of the services that can be considered active assistant. Can be
9719      * an empty array, for this no UID will be considered active.
9720      *
9721      * <p> Note that during audio service crash reset and after boot up the list of active assistant
9722      * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant).
9723      * Just after user switch the list of active assistant will also reset to empty.
9724      *
9725      * @hide
9726      */
9727     @SystemApi
9728     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setActiveAssistantServiceUids(@onNull int[] assistantUids)9729     public void setActiveAssistantServiceUids(@NonNull int[]  assistantUids) {
9730         try {
9731             getService().setActiveAssistantServiceUids(assistantUids);
9732         } catch (RemoteException e) {
9733             throw e.rethrowFromSystemServer();
9734         }
9735     }
9736 
9737     /**
9738      * Get active assistant UIDs last set with the
9739      * {@link #setActiveAssistantServiceUids(int[])}
9740      *
9741      * @return array of active assistants UIDs
9742      *
9743      * @hide
9744      */
9745     @SystemApi
9746     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
getActiveAssistantServicesUids()9747     public @NonNull int[] getActiveAssistantServicesUids() {
9748         try {
9749             int[] uids = getService().getActiveAssistantServiceUids();
9750             return Arrays.copyOf(uids, uids.length);
9751         } catch (RemoteException e) {
9752             throw e.rethrowFromSystemServer();
9753         }
9754     }
9755 
9756     /**
9757      * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio
9758      * HAL found, null will be returned.
9759      *
9760      * @return @see @link #AudioHalVersionInfo The version of Audio HAL.
9761      * @hide
9762      */
9763     @TestApi
getHalVersion()9764     public static @Nullable AudioHalVersionInfo getHalVersion() {
9765         try {
9766             return getService().getHalVersion();
9767         } catch (RemoteException e) {
9768             Log.e(TAG, "Error querying getHalVersion", e);
9769             throw e.rethrowFromSystemServer();
9770         }
9771     }
9772 
9773     //====================================================================
9774     // Preferred mixer attributes
9775 
9776     /**
9777      * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixer
9778      * attributes via {@link #setPreferredMixerAttributes(
9779      * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}.
9780      * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes. An
9781      * empty list may be returned for all other types of devices as they may not allow dynamic
9782      * configuration.
9783      *
9784      * @param device the device to query
9785      * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes
9786      *         for the given device.
9787      * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9788      */
9789     @NonNull
getSupportedMixerAttributes(@onNull AudioDeviceInfo device)9790     public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) {
9791         Objects.requireNonNull(device);
9792         List<AudioMixerAttributes> mixerAttrs = new ArrayList<>();
9793         return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs)
9794                 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>();
9795     }
9796 
9797     /**
9798      * Configures the mixer attributes for a particular {@link AudioAttributes} over a given
9799      * {@link AudioDeviceInfo}.
9800      * <p>Call {@link #getSupportedMixerAttributes(AudioDeviceInfo)} to determine which mixer
9801      * attributes can be used with the given device.
9802      * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the
9803      * same uid is routed to the given audio device when calling this API, the output mixer/stream
9804      * will be configured with the values previously set via this API.
9805      * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)}
9806      * to cancel setting mixer attributes for this {@link AudioAttributes}.
9807      *
9808      * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9809      *                   Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When
9810      *                   playing audio targeted at the given device, use the same attributes for
9811      *                   playback.
9812      * @param device the device to be routed. Currently, only USB device will be allowed.
9813      * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the
9814      *                        given device, use the same {@link AudioFormat} for both playback
9815      *                        and the mixer attributes.
9816      * @return true only if the preferred mixer attributes are set successfully.
9817      * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9818      * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9819      */
9820     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
setPreferredMixerAttributes(@onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @NonNull AudioMixerAttributes mixerAttributes)9821     public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes,
9822             @NonNull AudioDeviceInfo device,
9823             @NonNull AudioMixerAttributes mixerAttributes) {
9824         Objects.requireNonNull(attributes);
9825         Objects.requireNonNull(device);
9826         Objects.requireNonNull(mixerAttributes);
9827         try {
9828             final int status = getService().setPreferredMixerAttributes(
9829                     attributes, device.getId(), mixerAttributes);
9830             return status == AudioSystem.SUCCESS;
9831         } catch (RemoteException e) {
9832             throw e.rethrowFromSystemServer();
9833         }
9834     }
9835 
9836     /**
9837      * Returns current preferred mixer attributes that is set via
9838      * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9839      *
9840      * @param attributes the {@link AudioAttributes} whose mixer attributes should be set.
9841      * @param device the expected routing device
9842      * @return the preferred mixer attributes, which will be null when no preferred mixer attributes
9843      *         have been set, or when they have been cleared.
9844      * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9845      * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9846      */
9847     @Nullable
getPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)9848     public AudioMixerAttributes getPreferredMixerAttributes(
9849             @NonNull AudioAttributes attributes,
9850             @NonNull AudioDeviceInfo device) {
9851         Objects.requireNonNull(attributes);
9852         Objects.requireNonNull(device);
9853         List<AudioMixerAttributes> mixerAttrList = new ArrayList<>();
9854         int ret = AudioSystem.getPreferredMixerAttributes(
9855                 attributes, device.getId(), mixerAttrList);
9856         if (ret == AudioSystem.SUCCESS) {
9857             return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0);
9858         } else {
9859             Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret);
9860             return null;
9861         }
9862     }
9863 
9864     /**
9865      * Clears the current preferred mixer attributes that were previously set via
9866      * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9867      *
9868      * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared.
9869      * @param device the expected routing device
9870      * @return true only if the preferred mixer attributes are removed successfully.
9871      * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9872      * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9873      */
9874     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
clearPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)9875     public boolean clearPreferredMixerAttributes(
9876             @NonNull AudioAttributes attributes,
9877             @NonNull AudioDeviceInfo device) {
9878         Objects.requireNonNull(attributes);
9879         Objects.requireNonNull(device);
9880         try {
9881             final int status = getService().clearPreferredMixerAttributes(
9882                     attributes, device.getId());
9883             return status == AudioSystem.SUCCESS;
9884         } catch (RemoteException e) {
9885             throw e.rethrowFromSystemServer();
9886         }
9887     }
9888 
9889     /**
9890      * Interface to be notified of changes in the preferred mixer attributes.
9891      * <p>Note that this listener will only be invoked whenever
9892      * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}
9893      * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device
9894      * disconnection causes a change in preferred mixer attributes.
9895      * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)
9896      * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)
9897      */
9898     public interface OnPreferredMixerAttributesChangedListener {
9899         /**
9900          * Called on the listener to indicate that the preferred mixer attributes for the audio
9901          * attributes over the given device has changed.
9902          *
9903          * @param attributes the audio attributes for playback
9904          * @param device the targeted device
9905          * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for
9906          *                        preferred mixer attributes or null if preferred mixer attributes
9907          *                        is cleared
9908          */
onPreferredMixerAttributesChanged( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @Nullable AudioMixerAttributes mixerAttributes)9909         void onPreferredMixerAttributesChanged(
9910                 @NonNull AudioAttributes attributes,
9911                 @NonNull AudioDeviceInfo device,
9912                 @Nullable AudioMixerAttributes mixerAttributes);
9913     }
9914 
9915     /**
9916      * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the
9917      * {@link PreferredMixerAttributesDispatcherStub}.
9918      */
9919     private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener>
9920             mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager();
9921 
9922     /**
9923      * Adds a listener for being notified of changes to the preferred mixer attributes.
9924      * @param executor the executor to execute the callback
9925      * @param listener the listener to be notified of changes in the preferred mixer attributes.
9926      */
addOnPreferredMixerAttributesChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredMixerAttributesChangedListener listener)9927     public void addOnPreferredMixerAttributesChangedListener(
9928             @NonNull @CallbackExecutor Executor executor,
9929             @NonNull OnPreferredMixerAttributesChangedListener listener) {
9930         Objects.requireNonNull(executor);
9931         Objects.requireNonNull(listener);
9932         mPrefMixerAttributesListenerMgr.addListener(executor, listener,
9933                 "addOnPreferredMixerAttributesChangedListener",
9934                 () -> new PreferredMixerAttributesDispatcherStub());
9935     }
9936 
9937     /**
9938      * Removes a previously added listener of changes to the preferred mixer attributes.
9939      * @param listener the listener to be notified of changes in the preferred mixer attributes,
9940      *                 which were added via {@link #addOnPreferredMixerAttributesChangedListener(
9941      *                 Executor, OnPreferredMixerAttributesChangedListener)}.
9942      */
removeOnPreferredMixerAttributesChangedListener( @onNull OnPreferredMixerAttributesChangedListener listener)9943     public void removeOnPreferredMixerAttributesChangedListener(
9944             @NonNull OnPreferredMixerAttributesChangedListener listener) {
9945         Objects.requireNonNull(listener);
9946         mPrefMixerAttributesListenerMgr.removeListener(listener,
9947                 "removeOnPreferredMixerAttributesChangedListener");
9948     }
9949 
9950     private final class PreferredMixerAttributesDispatcherStub
9951             extends IPreferredMixerAttributesDispatcher.Stub
9952             implements CallbackUtil.DispatcherStub {
9953 
9954         @Override
register(boolean register)9955         public void register(boolean register) {
9956             try {
9957                 if (register) {
9958                     getService().registerPreferredMixerAttributesDispatcher(this);
9959                 } else {
9960                     getService().unregisterPreferredMixerAttributesDispatcher(this);
9961                 }
9962             } catch (RemoteException e) {
9963                 e.rethrowFromSystemServer();
9964             }
9965         }
9966 
9967         @Override
dispatchPrefMixerAttributesChanged(@onNull AudioAttributes attr, int deviceId, @Nullable AudioMixerAttributes mixerAttr)9968         public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr,
9969                                                        int deviceId,
9970                                                        @Nullable AudioMixerAttributes mixerAttr) {
9971             // TODO: If the device is disconnected, we may not be able to find the device with
9972             // given device id. We need a better to carry the device information via binder.
9973             AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS);
9974             if (device == null) {
9975                 Log.d(TAG, "Drop preferred mixer attributes changed as the device("
9976                         + deviceId + ") is disconnected");
9977                 return;
9978             }
9979             mPrefMixerAttributesListenerMgr.callListeners(
9980                     (listener) -> listener.onPreferredMixerAttributesChanged(
9981                             attr, device, mixerAttr));
9982         }
9983     }
9984 
9985     /**
9986      * Requests if the implementation supports controlling the latency modes
9987      * over the Bluetooth A2DP or LE Audio links.
9988      *
9989      * @return true if supported, false otherwise
9990      *
9991      * @hide
9992      */
9993     @SystemApi
9994     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
supportsBluetoothVariableLatency()9995     public boolean supportsBluetoothVariableLatency() {
9996         try {
9997             return getService().supportsBluetoothVariableLatency();
9998         } catch (RemoteException e) {
9999             throw e.rethrowFromSystemServer();
10000         }
10001     }
10002 
10003     /**
10004      * Enables or disables the variable Bluetooth latency control mechanism in the
10005      * audio framework and the audio HAL. This does not apply to the latency mode control
10006      * on the spatializer output as this is a built-in feature.
10007      *
10008      * @hide
10009      */
10010     @SystemApi
10011     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
setBluetoothVariableLatencyEnabled(boolean enabled)10012     public void setBluetoothVariableLatencyEnabled(boolean enabled) {
10013         try {
10014             getService().setBluetoothVariableLatencyEnabled(enabled);
10015         } catch (RemoteException e) {
10016             throw e.rethrowFromSystemServer();
10017         }
10018     }
10019 
10020     /**
10021      * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
10022      * @hide
10023      */
10024     @SystemApi
10025     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
isBluetoothVariableLatencyEnabled()10026     public boolean isBluetoothVariableLatencyEnabled() {
10027         try {
10028             return getService().isBluetoothVariableLatencyEnabled();
10029         } catch (RemoteException e) {
10030             throw e.rethrowFromSystemServer();
10031         }
10032     }
10033 
10034     //====================================================================
10035     // Stream aliasing changed listener, getter for stream alias or independent streams
10036 
10037     /**
10038      * manages the stream aliasing listeners and StreamAliasingDispatcherStub
10039      */
10040     private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr =
10041             new CallbackUtil.LazyListenerManager();
10042 
10043 
10044     final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub
10045             implements CallbackUtil.DispatcherStub {
10046 
10047         @Override
register(boolean register)10048         public void register(boolean register) {
10049             try {
10050                 getService().registerStreamAliasingDispatcher(this, register);
10051             } catch (RemoteException e) {
10052                 e.rethrowFromSystemServer();
10053             }
10054         }
10055 
10056         @Override
dispatchStreamAliasingChanged()10057         public void dispatchStreamAliasingChanged() {
10058             mStreamAliasingListenerMgr.callListeners((listener) -> listener.run());
10059         }
10060     }
10061 
10062     /**
10063      * @hide
10064      * Adds a listener to be notified of changes to volume stream type aliasing.
10065      * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
10066      * @param executor the Executor running the listener
10067      * @param onStreamAliasingChangedListener the listener to add for the aliasing changes
10068      */
10069     @SystemApi
10070     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
addOnStreamAliasingChangedListener( @onNull @allbackExecutor Executor executor, @NonNull Runnable onStreamAliasingChangedListener)10071     public void addOnStreamAliasingChangedListener(
10072             @NonNull @CallbackExecutor Executor executor,
10073             @NonNull Runnable onStreamAliasingChangedListener) {
10074         mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener,
10075                 "addOnStreamAliasingChangedListener",
10076                 () -> new StreamAliasingDispatcherStub());
10077     }
10078 
10079     /**
10080      * @hide
10081      * Removes a previously added listener for changes to stream aliasing.
10082      * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)}
10083      * @see #addOnStreamAliasingChangedListener(Executor, Runnable)
10084      * @param onStreamAliasingChangedListener the previously added listener of aliasing changes
10085      */
10086     @SystemApi
10087     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
removeOnStreamAliasingChangedListener( @onNull Runnable onStreamAliasingChangedListener)10088     public void removeOnStreamAliasingChangedListener(
10089             @NonNull Runnable onStreamAliasingChangedListener) {
10090         mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener,
10091                 "removeOnStreamAliasingChangedListener");
10092     }
10093 
10094     /**
10095      * @hide
10096      * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
10097      * volumes will be updated in case of a change.
10098      * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING
10099      */
10100     @TestApi
10101     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
setNotifAliasRingForTest(boolean isAliased)10102     public void setNotifAliasRingForTest(boolean isAliased) {
10103         final IAudioService service = getService();
10104         try {
10105             service.setNotifAliasRingForTest(isAliased);
10106         } catch (RemoteException e) {
10107             throw e.rethrowFromSystemServer();
10108         }
10109     }
10110 
10111     /**
10112      * @hide
10113      * Return the list of independent stream types for volume control.
10114      * A stream type is considered independent when the volume changes of that type do not
10115      * affect any other independent volume control stream type.
10116      * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}.
10117      * @return list of independent stream types, where each value can be one of
10118      *     {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, {@link #STREAM_RING},
10119      *     {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, {@link #STREAM_NOTIFICATION},
10120      *     {@link #STREAM_DTMF} and {@link #STREAM_ACCESSIBILITY}.
10121      */
10122     @SystemApi
10123     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
getIndependentStreamTypes()10124     public @NonNull List<Integer> getIndependentStreamTypes() {
10125         final IAudioService service = getService();
10126         try {
10127             return service.getIndependentStreamTypes();
10128         } catch (RemoteException e) {
10129             throw e.rethrowFromSystemServer();
10130         }
10131     }
10132 
10133     /**
10134      * @hide
10135      * Return the stream type that a given stream is aliased to.
10136      * A stream alias means that any change to the source stream will also be applied to the alias,
10137      * and vice-versa.
10138      * If a stream is independent (i.e. part of the stream types returned by
10139      * {@link #getIndependentStreamTypes()}), its alias is itself.
10140      * @param sourceStreamType the stream type to query for the alias.
10141      * @return the stream type the source type is aliased to.
10142      */
10143     @SystemApi
10144     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
getStreamTypeAlias(@ublicStreamTypes int sourceStreamType)10145     public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) {
10146         final IAudioService service = getService();
10147         try {
10148             return service.getStreamTypeAlias(sourceStreamType);
10149         } catch (RemoteException e) {
10150             throw e.rethrowFromSystemServer();
10151         }
10152     }
10153 
10154     /**
10155      * @hide
10156      * Returns whether the system uses {@link AudioVolumeGroup} for volume control
10157      * @return true when volume control is performed through volume groups, false if it uses
10158      *     stream types.
10159      */
10160     @TestApi
10161     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED)
isVolumeControlUsingVolumeGroups()10162     public boolean isVolumeControlUsingVolumeGroups() {
10163         final IAudioService service = getService();
10164         try {
10165             return service.isVolumeControlUsingVolumeGroups();
10166         } catch (RemoteException e) {
10167             throw e.rethrowFromSystemServer();
10168         }
10169     }
10170 
10171     /**
10172      * @hide
10173      * Checks whether a notification sound should be played or not, as reported by the state
10174      * of the audio framework. Querying whether playback should proceed is favored over
10175      * playing and letting the sound be muted or not.
10176      * @param aa the {@link AudioAttributes} of the notification about to maybe play
10177      * @return true if the audio framework state is such that the notification should be played
10178      *    because at time of checking, and the notification will be heard,
10179      *    false otherwise
10180      */
10181     @TestApi
10182     @FlaggedApi(FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING)
10183     @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE)
shouldNotificationSoundPlay(@onNull final AudioAttributes aa)10184     public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) {
10185         final IAudioService service = getService();
10186         try {
10187             return service.shouldNotificationSoundPlay(Objects.requireNonNull(aa));
10188         } catch (RemoteException e) {
10189             throw e.rethrowFromSystemServer();
10190         }
10191     }
10192 
10193     //====================================================================
10194     // Mute await connection
10195 
10196     private final Object mMuteAwaitConnectionListenerLock = new Object();
10197 
10198     @GuardedBy("mMuteAwaitConnectionListenerLock")
10199     private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>
10200             mMuteAwaitConnectionListeners;
10201 
10202     @GuardedBy("mMuteAwaitConnectionListenerLock")
10203     private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub;
10204 
10205     private final class MuteAwaitConnectionDispatcherStub
10206             extends IMuteAwaitConnectionCallback.Stub {
register(boolean register)10207         public void register(boolean register) {
10208             try {
10209                 getService().registerMuteAwaitConnectionDispatcher(this, register);
10210             } catch (RemoteException e) {
10211                 throw e.rethrowFromSystemServer();
10212             }
10213         }
10214 
10215         @Override
10216         @SuppressLint("GuardedBy") // lock applied inside callListeners method
dispatchOnMutedUntilConnection(AudioDeviceAttributes device, int[] mutedUsages)10217         public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device,
10218                 int[] mutedUsages) {
10219             CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
10220                     mMuteAwaitConnectionListenerLock,
10221                     (listener) -> listener.onMutedUntilConnection(device, mutedUsages));
10222         }
10223 
10224         @Override
10225         @SuppressLint("GuardedBy") // lock applied inside callListeners method
dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device, int[] mutedUsages)10226         public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device,
10227                 int[] mutedUsages) {
10228             CallbackUtil.callListeners(mMuteAwaitConnectionListeners,
10229                     mMuteAwaitConnectionListenerLock,
10230                     (listener) -> listener.onUnmutedEvent(event, device, mutedUsages));
10231         }
10232     }
10233 
10234     //====================================================================
10235     // Flag related utilities
10236 
10237     private boolean mIsAutomotive = false;
10238 
initPlatform()10239     private void initPlatform() {
10240         try {
10241             final Context context = getContext();
10242             if (context != null) {
10243                 mIsAutomotive = context.getPackageManager()
10244                         .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
10245             }
10246         } catch (Exception e) {
10247             Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e);
10248         }
10249     }
10250 
applyAutoHardening()10251     private boolean applyAutoHardening() {
10252         if (mIsAutomotive && autoPublicVolumeApiHardening()) {
10253             return true;
10254         }
10255         return false;
10256     }
10257 
10258     //---------------------------------------------------------
10259     // Inner classes
10260     //--------------------
10261     /**
10262      * Helper class to handle the forwarding of native events to the appropriate listener
10263      * (potentially) handled in a different thread.
10264      */
10265     private class NativeEventHandlerDelegate {
10266         private final Handler mHandler;
10267 
NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)10268         NativeEventHandlerDelegate(final AudioDeviceCallback callback,
10269                                    Handler handler) {
10270             // find the looper for our new event handler
10271             Looper looper;
10272             if (handler != null) {
10273                 looper = handler.getLooper();
10274             } else {
10275                 // no given handler, use the looper the addListener call was called in
10276                 looper = Looper.getMainLooper();
10277             }
10278 
10279             // construct the event handler with this looper
10280             if (looper != null) {
10281                 // implement the event handler delegate
10282                 mHandler = new Handler(looper) {
10283                     @Override
10284                     public void handleMessage(Message msg) {
10285                         switch(msg.what) {
10286                         case MSG_DEVICES_CALLBACK_REGISTERED:
10287                         case MSG_DEVICES_DEVICES_ADDED:
10288                             if (callback != null) {
10289                                 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
10290                             }
10291                             break;
10292 
10293                         case MSG_DEVICES_DEVICES_REMOVED:
10294                             if (callback != null) {
10295                                 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
10296                             }
10297                            break;
10298 
10299                         default:
10300                             Log.e(TAG, "Unknown native event type: " + msg.what);
10301                             break;
10302                         }
10303                     }
10304                 };
10305             } else {
10306                 mHandler = null;
10307             }
10308         }
10309 
getHandler()10310         Handler getHandler() {
10311             return mHandler;
10312         }
10313     }
10314 }
10315