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