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