• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SdkConstant;
26 import android.annotation.SdkConstant.SdkConstantType;
27 import android.annotation.SuppressLint;
28 import android.annotation.SystemApi;
29 import android.annotation.SystemService;
30 import android.annotation.TestApi;
31 import android.app.NotificationManager;
32 import android.app.PendingIntent;
33 import android.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, "FLAG_SHOW_UI")638         FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES")639         FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND")640         FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE")641         FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE")642         FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME")643         FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME")644         FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT")645         FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME")646         FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY")647         FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS")648         FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT")649         FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY")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     private 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     // Bluetooth SCO control
2443     /**
2444      * Sticky broadcast intent action indicating that the Bluetooth SCO audio
2445      * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
2446      * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2447      * or {@link #SCO_AUDIO_STATE_CONNECTED}
2448      *
2449      * @see #startBluetoothSco()
2450      * @deprecated Use  {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
2451      */
2452     @Deprecated
2453     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2454     public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2455             "android.media.SCO_AUDIO_STATE_CHANGED";
2456 
2457      /**
2458      * Sticky broadcast intent action indicating that the Bluetooth SCO audio
2459      * connection state has been updated.
2460      * <p>This intent has two extras:
2461      * <ul>
2462      *   <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2463      *   <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2464      * </ul>
2465      * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2466      * <ul>
2467      *   <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2468      *   <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2469      *   <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2470      * </ul>
2471      * @see #startBluetoothSco()
2472      */
2473     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2474     public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2475             "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2476 
2477     /**
2478      * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2479      * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
2480      */
2481     public static final String EXTRA_SCO_AUDIO_STATE =
2482             "android.media.extra.SCO_AUDIO_STATE";
2483 
2484     /**
2485      * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2486      * bluetooth SCO connection state.
2487      */
2488     public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2489             "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2490 
2491     /**
2492      * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2493      * indicating that the SCO audio channel is not established
2494      */
2495     public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2496     /**
2497      * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2498      * indicating that the SCO audio channel is established
2499      */
2500     public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2501     /**
2502      * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2503      * indicating that the SCO audio channel is being established
2504      */
2505     public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2506     /**
2507      * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
2508      * there was an error trying to obtain the state
2509      */
2510     public static final int SCO_AUDIO_STATE_ERROR = -1;
2511 
2512 
2513     /**
2514      * Indicates if current platform supports use of SCO for off call use cases.
2515      * Application wanted to use bluetooth SCO audio when the phone is not in call
2516      * must first call this method to make sure that the platform supports this
2517      * feature.
2518      * @return true if bluetooth SCO can be used for audio when not in call
2519      *         false otherwise
2520      * @see #startBluetoothSco()
2521     */
isBluetoothScoAvailableOffCall()2522     public boolean isBluetoothScoAvailableOffCall() {
2523         return getContext().getResources().getBoolean(
2524                com.android.internal.R.bool.config_bluetooth_sco_off_call);
2525     }
2526 
2527     /**
2528      * Start bluetooth SCO audio connection.
2529      * <p>Requires Permission:
2530      *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2531      * <p>This method can be used by applications wanting to send and received audio
2532      * to/from a bluetooth SCO headset while the phone is not in call.
2533      * <p>As the SCO connection establishment can take several seconds,
2534      * applications should not rely on the connection to be available when the method
2535      * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
2536      * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
2537      * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2538      * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2539      * registration. If the state is already CONNECTED, no state change will be received via the
2540      * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2541      * so that the connection stays active in case the current initiator stops the connection.
2542      * <p>Unless the connection is already active as described above, the state will always
2543      * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2544      * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2545      * <p>When finished with the SCO connection or if the establishment fails, the application must
2546      * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
2547      * <p>Even if a SCO connection is established, the following restrictions apply on audio
2548      * output streams so that they can be routed to SCO headset:
2549      * <ul>
2550      *   <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2551      *   <li> the format must be mono </li>
2552      *   <li> the sampling must be 16kHz or 8kHz </li>
2553      * </ul>
2554      * <p>The following restrictions apply on input streams:
2555      * <ul>
2556      *   <li> the format must be mono </li>
2557      *   <li> the sampling must be 8kHz </li>
2558      * </ul>
2559      * <p>Note that the phone application always has the priority on the usage of the SCO
2560      * connection for telephony. If this method is called while the phone is in call
2561      * it will be ignored. Similarly, if a call is received or sent while an application
2562      * is using the SCO connection, the connection will be lost for the application and NOT
2563      * returned automatically when the call ends.
2564      * <p>NOTE: up to and including API version
2565      * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2566      * voice call to the bluetooth headset.
2567      * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2568      * connection is established.
2569      * @see #stopBluetoothSco()
2570      * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2571      */
startBluetoothSco()2572     public void startBluetoothSco(){
2573         final IAudioService service = getService();
2574         try {
2575             service.startBluetoothSco(mICallBack,
2576                     getContext().getApplicationInfo().targetSdkVersion);
2577         } catch (RemoteException e) {
2578             throw e.rethrowFromSystemServer();
2579         }
2580     }
2581 
2582     /**
2583      * @hide
2584      * Start bluetooth SCO audio connection in virtual call mode.
2585      * <p>Requires Permission:
2586      *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2587      * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2588      * Telephony and communication applications (VoIP, Video Chat) should preferably select
2589      * virtual call mode.
2590      * Applications using voice input for search or commands should first try raw audio connection
2591      * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2592      * failure.
2593      * @see #startBluetoothSco()
2594      * @see #stopBluetoothSco()
2595      * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2596      */
2597     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
startBluetoothScoVirtualCall()2598     public void startBluetoothScoVirtualCall() {
2599         final IAudioService service = getService();
2600         try {
2601             service.startBluetoothScoVirtualCall(mICallBack);
2602         } catch (RemoteException e) {
2603             throw e.rethrowFromSystemServer();
2604         }
2605     }
2606 
2607     /**
2608      * Stop bluetooth SCO audio connection.
2609      * <p>Requires Permission:
2610      *   {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2611      * <p>This method must be called by applications having requested the use of
2612      * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2613      * connection or if connection fails.
2614      * @see #startBluetoothSco()
2615      */
2616     // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
stopBluetoothSco()2617     public void stopBluetoothSco(){
2618         final IAudioService service = getService();
2619         try {
2620             service.stopBluetoothSco(mICallBack);
2621         } catch (RemoteException e) {
2622             throw e.rethrowFromSystemServer();
2623         }
2624     }
2625 
2626     /**
2627      * Request use of Bluetooth SCO headset for communications.
2628      * <p>
2629      * This method should only be used by applications that replace the platform-wide
2630      * management of audio settings or the main telephony application.
2631      *
2632      * @param on set <var>true</var> to use bluetooth SCO for communications;
2633      *               <var>false</var> to not use bluetooth SCO for communications
2634      */
setBluetoothScoOn(boolean on)2635     public void setBluetoothScoOn(boolean on){
2636         final IAudioService service = getService();
2637         try {
2638             service.setBluetoothScoOn(on);
2639         } catch (RemoteException e) {
2640             throw e.rethrowFromSystemServer();
2641         }
2642     }
2643 
2644     /**
2645      * Checks whether communications use Bluetooth SCO.
2646      *
2647      * @return true if SCO is used for communications;
2648      *         false if otherwise
2649      */
isBluetoothScoOn()2650     public boolean isBluetoothScoOn() {
2651         final IAudioService service = getService();
2652         try {
2653             return service.isBluetoothScoOn();
2654         } catch (RemoteException e) {
2655             throw e.rethrowFromSystemServer();
2656         }
2657     }
2658 
2659     /**
2660      * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2661      *           headset; <var>false</var> disable A2DP audio
2662      * @deprecated Do not use.
2663      */
setBluetoothA2dpOn(boolean on)2664     @Deprecated public void setBluetoothA2dpOn(boolean on){
2665     }
2666 
2667     /**
2668      * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
2669      *
2670      * @return true if a Bluetooth A2DP peripheral is connected
2671      *         false if otherwise
2672      * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
2673      */
isBluetoothA2dpOn()2674     public boolean isBluetoothA2dpOn() {
2675         if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
2676                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2677             return true;
2678         } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2679                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2680             return true;
2681         } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2682                 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2683             return true;
2684         }
2685         return false;
2686     }
2687 
2688     /**
2689      * Sets audio routing to the wired headset on or off.
2690      *
2691      * @param on set <var>true</var> to route audio to/from wired
2692      *           headset; <var>false</var> disable wired headset audio
2693      * @deprecated Do not use.
2694      */
setWiredHeadsetOn(boolean on)2695     @Deprecated public void setWiredHeadsetOn(boolean on){
2696     }
2697 
2698     /**
2699      * Checks whether a wired headset is connected or not.
2700      * <p>This is not a valid indication that audio playback is
2701      * actually over the wired headset as audio routing depends on other conditions.
2702      *
2703      * @return true if a wired headset is connected.
2704      *         false if otherwise
2705      * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
2706      */
isWiredHeadsetOn()2707     public boolean isWiredHeadsetOn() {
2708         if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
2709                 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2710             AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
2711                 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2712             AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2713               == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
2714             return false;
2715         } else {
2716             return true;
2717         }
2718     }
2719 
2720     /**
2721      * Sets the microphone mute on or off.
2722      * <p>
2723      * This method should only be used by applications that replace the platform-wide
2724      * management of audio settings or the main telephony application.
2725      *
2726      * @param on set <var>true</var> to mute the microphone;
2727      *           <var>false</var> to turn mute off
2728      */
setMicrophoneMute(boolean on)2729     public void setMicrophoneMute(boolean on) {
2730         final IAudioService service = getService();
2731         try {
2732             service.setMicrophoneMute(on, getContext().getOpPackageName(),
2733                     UserHandle.getCallingUserId());
2734         } catch (RemoteException e) {
2735             throw e.rethrowFromSystemServer();
2736         }
2737     }
2738 
2739     /**
2740      * @hide
2741      * Sets the microphone from switch mute on or off.
2742      * <p>
2743      * This method should only be used by InputManager to notify
2744      * Audio Subsystem about Microphone Mute switch state.
2745      *
2746      * @param on set <var>true</var> to mute the microphone;
2747      *           <var>false</var> to turn mute off
2748      */
2749     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
setMicrophoneMuteFromSwitch(boolean on)2750     public void setMicrophoneMuteFromSwitch(boolean on) {
2751         final IAudioService service = getService();
2752         try {
2753             service.setMicrophoneMuteFromSwitch(on);
2754         } catch (RemoteException e) {
2755             throw e.rethrowFromSystemServer();
2756         }
2757     }
2758 
2759     /**
2760      * Checks whether the microphone mute is on or off.
2761      *
2762      * @return true if microphone is muted, false if it's not
2763      */
isMicrophoneMute()2764     public boolean isMicrophoneMute() {
2765         final IAudioService service = getService();
2766         try {
2767             return service.isMicrophoneMuted();
2768         } catch (RemoteException e) {
2769             throw e.rethrowFromSystemServer();
2770         }
2771     }
2772 
2773     /**
2774      * Broadcast Action: microphone muting state changed.
2775      *
2776      * You <em>cannot</em> receive this through components declared
2777      * in manifests, only by explicitly registering for it with
2778      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2779      * Context.registerReceiver()}.
2780      *
2781      * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2782      * microphone is muted.
2783      */
2784     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2785     public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2786             "android.media.action.MICROPHONE_MUTE_CHANGED";
2787 
2788     /**
2789      * Broadcast Action: speakerphone state changed.
2790      *
2791      * You <em>cannot</em> receive this through components declared
2792      * in manifests, only by explicitly registering for it with
2793      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2794      * Context.registerReceiver()}.
2795      *
2796      * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2797      * speakerphone functionality is enabled or not.
2798      */
2799     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2800     public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2801             "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2802 
2803     /**
2804      * Sets the audio mode.
2805      * <p>
2806      * The audio mode encompasses audio routing AND the behavior of
2807      * the telephony layer. Therefore this method should only be used by applications that
2808      * replace the platform-wide management of audio settings or the main telephony application.
2809      * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2810      * application when it places a phone call, as it will cause signals from the radio layer
2811      * to feed the platform mixer.
2812      *
2813      * @param mode  the requested audio mode.
2814      *              Informs the HAL about the current audio state so that
2815      *              it can route the audio appropriately.
2816      */
setMode(@udioMode int mode)2817     public void setMode(@AudioMode int mode) {
2818         final IAudioService service = getService();
2819         try {
2820             service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
2821         } catch (RemoteException e) {
2822             throw e.rethrowFromSystemServer();
2823         }
2824     }
2825 
2826     /**
2827      * Returns the current audio mode.
2828      *
2829      * @return      the current audio mode.
2830      */
2831     @AudioMode
getMode()2832     public int getMode() {
2833         final IAudioService service = getService();
2834         try {
2835             int mode = service.getMode();
2836             int sdk;
2837             try {
2838                 sdk = getContext().getApplicationInfo().targetSdkVersion;
2839             } catch (NullPointerException e) {
2840                 // some tests don't have a Context
2841                 sdk = Build.VERSION.SDK_INT;
2842             }
2843             if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
2844                 mode = MODE_IN_CALL;
2845             }
2846             return mode;
2847         } catch (RemoteException e) {
2848             throw e.rethrowFromSystemServer();
2849         }
2850     }
2851 
2852     /**
2853      * Interface definition of a callback that is notified when the audio mode changes
2854      */
2855     public interface OnModeChangedListener {
2856         /**
2857          * Called on the listener to indicate that the audio mode has changed
2858          *
2859          * @param mode The current audio mode
2860          */
onModeChanged(@udioMode int mode)2861         void onModeChanged(@AudioMode int mode);
2862     }
2863 
2864     private final Object mModeListenerLock = new Object();
2865     /**
2866      * List of listeners for audio mode and their associated Executor.
2867      * List is lazy-initialized on first registration
2868      */
2869     @GuardedBy("mModeListenerLock")
2870     private @Nullable ArrayList<ModeListenerInfo> mModeListeners;
2871 
2872     @GuardedBy("mModeListenerLock")
2873     private ModeDispatcherStub mModeDispatcherStub;
2874 
2875     private final class ModeDispatcherStub
2876             extends IAudioModeDispatcher.Stub {
2877 
2878         @Override
dispatchAudioModeChanged(int mode)2879         public void dispatchAudioModeChanged(int mode) {
2880             // make a shallow copy of listeners so callback is not executed under lock
2881             final ArrayList<ModeListenerInfo> modeListeners;
2882             synchronized (mModeListenerLock) {
2883                 if (mModeListeners == null || mModeListeners.size() == 0) {
2884                     return;
2885                 }
2886                 modeListeners = (ArrayList<ModeListenerInfo>) mModeListeners.clone();
2887             }
2888             final long ident = Binder.clearCallingIdentity();
2889             try {
2890                 for (ModeListenerInfo info : modeListeners) {
2891                     info.mExecutor.execute(() ->
2892                             info.mListener.onModeChanged(mode));
2893                 }
2894             } finally {
2895                 Binder.restoreCallingIdentity(ident);
2896             }
2897         }
2898     }
2899 
2900     private static class ModeListenerInfo {
2901         final @NonNull OnModeChangedListener mListener;
2902         final @NonNull Executor mExecutor;
2903 
ModeListenerInfo(OnModeChangedListener listener, Executor exe)2904         ModeListenerInfo(OnModeChangedListener listener, Executor exe) {
2905             mListener = listener;
2906             mExecutor = exe;
2907         }
2908     }
2909 
2910     @GuardedBy("mModeListenerLock")
hasModeListener(OnModeChangedListener listener)2911     private boolean hasModeListener(OnModeChangedListener listener) {
2912         return getModeListenerInfo(listener) != null;
2913     }
2914 
2915     @GuardedBy("mModeListenerLock")
getModeListenerInfo( OnModeChangedListener listener)2916     private @Nullable ModeListenerInfo getModeListenerInfo(
2917             OnModeChangedListener listener) {
2918         if (mModeListeners == null) {
2919             return null;
2920         }
2921         for (ModeListenerInfo info : mModeListeners) {
2922             if (info.mListener == listener) {
2923                 return info;
2924             }
2925         }
2926         return null;
2927     }
2928 
2929 
2930     @GuardedBy("mModeListenerLock")
2931     /**
2932      * @return true if the listener was removed from the list
2933      */
removeModeListener(OnModeChangedListener listener)2934     private boolean removeModeListener(OnModeChangedListener listener) {
2935         final ModeListenerInfo infoToRemove = getModeListenerInfo(listener);
2936         if (infoToRemove != null) {
2937             mModeListeners.remove(infoToRemove);
2938             return true;
2939         }
2940         return false;
2941     }
2942 
2943     /**
2944      * Adds a listener to be notified of changes to the audio mode.
2945      * See {@link #getMode()}
2946      * @param executor
2947      * @param listener
2948      */
addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)2949     public void addOnModeChangedListener(
2950             @NonNull @CallbackExecutor Executor executor,
2951             @NonNull OnModeChangedListener listener) {
2952         Objects.requireNonNull(executor);
2953         Objects.requireNonNull(listener);
2954         synchronized (mModeListenerLock) {
2955             if (hasModeListener(listener)) {
2956                 throw new IllegalArgumentException("attempt to call addOnModeChangedListener() "
2957                         + "on a previously registered listener");
2958             }
2959             // lazy initialization of the list of strategy-preferred device listener
2960             if (mModeListeners == null) {
2961                 mModeListeners = new ArrayList<>();
2962             }
2963             final int oldCbCount = mModeListeners.size();
2964             mModeListeners.add(new ModeListenerInfo(listener, executor));
2965             if (oldCbCount == 0) {
2966                 // register binder for callbacks
2967                 if (mModeDispatcherStub == null) {
2968                     mModeDispatcherStub = new ModeDispatcherStub();
2969                 }
2970                 try {
2971                     getService().registerModeDispatcher(mModeDispatcherStub);
2972                 } catch (RemoteException e) {
2973                     throw e.rethrowFromSystemServer();
2974                 }
2975             }
2976         }
2977     }
2978 
2979     /**
2980      * Removes a previously added listener for changes to audio mode.
2981      * See {@link #getMode()}
2982      * @param listener
2983      */
removeOnModeChangedListener(@onNull OnModeChangedListener listener)2984     public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
2985         Objects.requireNonNull(listener);
2986         synchronized (mModeListenerLock) {
2987             if (!removeModeListener(listener)) {
2988                 throw new IllegalArgumentException("attempt to call removeOnModeChangedListener() "
2989                         + "on an unregistered listener");
2990             }
2991             if (mModeListeners.size() == 0) {
2992                 // unregister binder for callbacks
2993                 try {
2994                     getService().unregisterModeDispatcher(mModeDispatcherStub);
2995                 } catch (RemoteException e) {
2996                     throw e.rethrowFromSystemServer();
2997                 } finally {
2998                     mModeDispatcherStub = null;
2999                     mModeListeners = null;
3000                 }
3001             }
3002         }
3003     }
3004 
3005     /**
3006     * Indicates if the platform supports a special call screening and call monitoring mode.
3007     * <p>
3008     * When this mode is supported, it is possible to perform call screening and monitoring
3009     * functions while other use cases like music or movie playback are active.
3010     * <p>
3011     * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3012     * call screening mode.
3013     * <p>
3014     * If call screening mode is not supported, setting mode to
3015     * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3016     *  {@link #getMode()}.
3017     * @return true if call screening mode is supported, false otherwise.
3018     */
isCallScreeningModeSupported()3019     public boolean isCallScreeningModeSupported() {
3020         final IAudioService service = getService();
3021         try {
3022             return service.isCallScreeningModeSupported();
3023         } catch (RemoteException e) {
3024             throw e.rethrowFromSystemServer();
3025         }
3026     }
3027 
3028     /* modes for setMode/getMode/setRoute/getRoute */
3029     /**
3030      * Audio harware modes.
3031      */
3032     /**
3033      * Invalid audio mode.
3034      */
3035     public static final int MODE_INVALID            = AudioSystem.MODE_INVALID;
3036     /**
3037      * Current audio mode. Used to apply audio routing to current mode.
3038      */
3039     public static final int MODE_CURRENT            = AudioSystem.MODE_CURRENT;
3040     /**
3041      * Normal audio mode: not ringing and no call established.
3042      */
3043     public static final int MODE_NORMAL             = AudioSystem.MODE_NORMAL;
3044     /**
3045      * Ringing audio mode. An incoming is being signaled.
3046      */
3047     public static final int MODE_RINGTONE           = AudioSystem.MODE_RINGTONE;
3048     /**
3049      * In call audio mode. A telephony call is established.
3050      */
3051     public static final int MODE_IN_CALL            = AudioSystem.MODE_IN_CALL;
3052     /**
3053      * In communication audio mode. An audio/video chat or VoIP call is established.
3054      */
3055     public static final int MODE_IN_COMMUNICATION   = AudioSystem.MODE_IN_COMMUNICATION;
3056     /**
3057      * Call screening in progress. Call is connected and audio is accessible to call
3058      * screening applications but other audio use cases are still possible.
3059      */
3060     public static final int MODE_CALL_SCREENING     = AudioSystem.MODE_CALL_SCREENING;
3061 
3062     /** @hide */
3063     @IntDef(flag = false, prefix = "MODE_", value = {
3064             MODE_NORMAL,
3065             MODE_RINGTONE,
3066             MODE_IN_CALL,
3067             MODE_IN_COMMUNICATION,
3068             MODE_CALL_SCREENING }
3069     )
3070     @Retention(RetentionPolicy.SOURCE)
3071     public @interface AudioMode {}
3072 
3073     /* Routing bits for setRouting/getRouting API */
3074     /**
3075      * Routing audio output to earpiece
3076      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3077      * setBluetoothScoOn() methods instead.
3078      */
3079     @Deprecated public static final int ROUTE_EARPIECE          = AudioSystem.ROUTE_EARPIECE;
3080     /**
3081      * Routing audio output to speaker
3082      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3083      * setBluetoothScoOn() methods instead.
3084      */
3085     @Deprecated public static final int ROUTE_SPEAKER           = AudioSystem.ROUTE_SPEAKER;
3086     /**
3087      * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
3088      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3089      * setBluetoothScoOn() methods instead.
3090      */
3091     @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3092     /**
3093      * Routing audio output to bluetooth SCO
3094      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3095      * setBluetoothScoOn() methods instead.
3096      */
3097     @Deprecated public static final int ROUTE_BLUETOOTH_SCO     = AudioSystem.ROUTE_BLUETOOTH_SCO;
3098     /**
3099      * Routing audio output to headset
3100      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3101      * setBluetoothScoOn() methods instead.
3102      */
3103     @Deprecated public static final int ROUTE_HEADSET           = AudioSystem.ROUTE_HEADSET;
3104     /**
3105      * Routing audio output to bluetooth A2DP
3106      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3107      * setBluetoothScoOn() methods instead.
3108      */
3109     @Deprecated public static final int ROUTE_BLUETOOTH_A2DP    = AudioSystem.ROUTE_BLUETOOTH_A2DP;
3110     /**
3111      * Used for mask parameter of {@link #setRouting(int,int,int)}.
3112      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3113      * setBluetoothScoOn() methods instead.
3114      */
3115     @Deprecated public static final int ROUTE_ALL               = AudioSystem.ROUTE_ALL;
3116 
3117     /**
3118      * Sets the audio routing for a specified mode
3119      *
3120      * @param mode   audio mode to change route. E.g., MODE_RINGTONE.
3121      * @param routes bit vector of routes requested, created from one or
3122      *               more of ROUTE_xxx types. Set bits indicate that route should be on
3123      * @param mask   bit vector of routes to change, created from one or more of
3124      * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
3125      *
3126      * @deprecated   Do not set audio routing directly, use setSpeakerphoneOn(),
3127      * setBluetoothScoOn() methods instead.
3128      */
3129     @Deprecated
setRouting(int mode, int routes, int mask)3130     public void setRouting(int mode, int routes, int mask) {
3131     }
3132 
3133     /**
3134      * Returns the current audio routing bit vector for a specified mode.
3135      *
3136      * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3137      * @return an audio route bit vector that can be compared with ROUTE_xxx
3138      * bits
3139      * @deprecated   Do not query audio routing directly, use isSpeakerphoneOn(),
3140      * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
3141      */
3142     @Deprecated
getRouting(int mode)3143     public int getRouting(int mode) {
3144         return -1;
3145     }
3146 
3147     /**
3148      * Checks whether any music is active.
3149      *
3150      * @return true if any music tracks are active.
3151      */
isMusicActive()3152     public boolean isMusicActive() {
3153         final IAudioService service = getService();
3154         try {
3155             return service.isMusicActive(false /*remotely*/);
3156         } catch (RemoteException e) {
3157             throw e.rethrowFromSystemServer();
3158         }
3159     }
3160 
3161     /**
3162      * @hide
3163      * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3164      *   display). Note that BT audio sinks are not considered remote devices.
3165      * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3166      */
3167     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isMusicActiveRemotely()3168     public boolean isMusicActiveRemotely() {
3169         final IAudioService service = getService();
3170         try {
3171             return service.isMusicActive(true /*remotely*/);
3172         } catch (RemoteException e) {
3173             throw e.rethrowFromSystemServer();
3174         }
3175     }
3176 
3177     /**
3178      * @hide
3179      * Checks whether the current audio focus is exclusive.
3180      * @return true if the top of the audio focus stack requested focus
3181      *     with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3182      */
isAudioFocusExclusive()3183     public boolean isAudioFocusExclusive() {
3184         final IAudioService service = getService();
3185         try {
3186             return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3187         } catch (RemoteException e) {
3188             throw e.rethrowFromSystemServer();
3189         }
3190     }
3191 
3192     /**
3193      * Return a new audio session identifier not associated with any player or effect.
3194      * An audio session identifier is a system wide unique identifier for a set of audio streams
3195      * (one or more mixed together).
3196      * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3197      * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3198      * session ID will be applied to the mixed audio content of the players that share the same
3199      * audio session.
3200      * <p>This method can for instance be used when creating one of the
3201      * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3202      * or to specify a session for a speech synthesis utterance
3203      * in {@link android.speech.tts.TextToSpeech.Engine}.
3204      * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
3205      *   system failed to generate a new session, a condition in which audio playback or recording
3206      *   will subsequently fail as well.
3207      */
generateAudioSessionId()3208     public int generateAudioSessionId() {
3209         int session = AudioSystem.newAudioSessionId();
3210         if (session > 0) {
3211             return session;
3212         } else {
3213             Log.e(TAG, "Failure to generate a new audio session ID");
3214             return ERROR;
3215         }
3216     }
3217 
3218     /**
3219      * A special audio session ID to indicate that the audio session ID isn't known and the
3220      * framework should generate a new value. This can be used when building a new
3221      * {@link AudioTrack} instance with
3222      * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3223      */
3224     public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3225 
3226 
3227     /*
3228      * Sets a generic audio configuration parameter. The use of these parameters
3229      * are platform dependant, see libaudio
3230      *
3231      * ** Temporary interface - DO NOT USE
3232      *
3233      * TODO: Replace with a more generic key:value get/set mechanism
3234      *
3235      * param key   name of parameter to set. Must not be null.
3236      * param value value of parameter. Must not be null.
3237      */
3238     /**
3239      * @hide
3240      * @deprecated Use {@link #setParameters(String)} instead
3241      */
setParameter(String key, String value)3242     @Deprecated public void setParameter(String key, String value) {
3243         setParameters(key+"="+value);
3244     }
3245 
3246     /**
3247      * Sets a variable number of parameter values to audio hardware.
3248      *
3249      * @param keyValuePairs list of parameters key value pairs in the form:
3250      *    key1=value1;key2=value2;...
3251      *
3252      */
setParameters(String keyValuePairs)3253     public void setParameters(String keyValuePairs) {
3254         AudioSystem.setParameters(keyValuePairs);
3255     }
3256 
3257     /**
3258      * Gets a variable number of parameter values from audio hardware.
3259      *
3260      * @param keys list of parameters
3261      * @return list of parameters key value pairs in the form:
3262      *    key1=value1;key2=value2;...
3263      */
getParameters(String keys)3264     public String getParameters(String keys) {
3265         return AudioSystem.getParameters(keys);
3266     }
3267 
3268     /* Sound effect identifiers */
3269     /**
3270      * Keyboard and direction pad click sound
3271      * @see #playSoundEffect(int)
3272      */
3273     public static final int FX_KEY_CLICK = 0;
3274     /**
3275      * Focus has moved up
3276      * @see #playSoundEffect(int)
3277      */
3278     public static final int FX_FOCUS_NAVIGATION_UP = 1;
3279     /**
3280      * Focus has moved down
3281      * @see #playSoundEffect(int)
3282      */
3283     public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3284     /**
3285      * Focus has moved left
3286      * @see #playSoundEffect(int)
3287      */
3288     public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3289     /**
3290      * Focus has moved right
3291      * @see #playSoundEffect(int)
3292      */
3293     public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3294     /**
3295      * IME standard keypress sound
3296      * @see #playSoundEffect(int)
3297      */
3298     public static final int FX_KEYPRESS_STANDARD = 5;
3299     /**
3300      * IME spacebar keypress sound
3301      * @see #playSoundEffect(int)
3302      */
3303     public static final int FX_KEYPRESS_SPACEBAR = 6;
3304     /**
3305      * IME delete keypress sound
3306      * @see #playSoundEffect(int)
3307      */
3308     public static final int FX_KEYPRESS_DELETE = 7;
3309     /**
3310      * IME return_keypress sound
3311      * @see #playSoundEffect(int)
3312      */
3313     public static final int FX_KEYPRESS_RETURN = 8;
3314 
3315     /**
3316      * Invalid keypress sound
3317      * @see #playSoundEffect(int)
3318      */
3319     public static final int FX_KEYPRESS_INVALID = 9;
3320 
3321     /**
3322      * Back sound
3323      * @see #playSoundEffect(int)
3324      */
3325     public static final int FX_BACK = 10;
3326 
3327     /**
3328      * @hide Home sound
3329      * <p>
3330      * To be played by the framework when the home app becomes active if config_enableHomeSound is
3331      * set to true. This is currently only used on TV devices.
3332      * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3333      * @see #playSoundEffect(int)
3334      */
3335     public static final int FX_HOME = 11;
3336 
3337     /**
3338      * @hide Navigation repeat sound 1
3339      * <p>
3340      * To be played by the framework when a focus navigation is repeatedly triggered
3341      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3342      * This is currently only used on TV devices.
3343      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3344      * @see #playSoundEffect(int)
3345      */
3346     public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
3347 
3348     /**
3349      * @hide Navigation repeat sound 2
3350      * <p>
3351      * To be played by the framework when a focus navigation is repeatedly triggered
3352      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3353      * This is currently only used on TV devices.
3354      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3355      * @see #playSoundEffect(int)
3356      */
3357     public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
3358 
3359     /**
3360      * @hide Navigation repeat sound 3
3361      * <p>
3362      * To be played by the framework when a focus navigation is repeatedly triggered
3363      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3364      * This is currently only used on TV devices.
3365      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3366      * @see #playSoundEffect(int)
3367      */
3368     public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
3369 
3370     /**
3371      * @hide Navigation repeat sound 4
3372      * <p>
3373      * To be played by the framework when a focus navigation is repeatedly triggered
3374      * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
3375      * This is currently only used on TV devices.
3376      * Note that this sound is only available if a sound file is specified in audio_assets.xml
3377      * @see #playSoundEffect(int)
3378      */
3379     public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
3380 
3381     /**
3382      * @hide Number of sound effects
3383      */
3384     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
3385     public static final int NUM_SOUND_EFFECTS = 16;
3386 
3387     /** @hide */
3388     @IntDef(prefix = { "FX_" }, value = {
3389             FX_KEY_CLICK,
3390             FX_FOCUS_NAVIGATION_UP,
3391             FX_FOCUS_NAVIGATION_DOWN,
3392             FX_FOCUS_NAVIGATION_LEFT,
3393             FX_FOCUS_NAVIGATION_RIGHT,
3394             FX_KEYPRESS_STANDARD,
3395             FX_KEYPRESS_SPACEBAR,
3396             FX_KEYPRESS_DELETE,
3397             FX_KEYPRESS_RETURN,
3398             FX_KEYPRESS_INVALID,
3399             FX_BACK
3400     })
3401     @Retention(RetentionPolicy.SOURCE)
3402     public @interface SystemSoundEffect {}
3403 
3404     /**
3405      * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
3406      */
3407     public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
3408 
3409     /**
3410      * @hide
3411      * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3412      * @return The id of a navigation repeat sound effect or -1 if out of bounds
3413      */
getNthNavigationRepeatSoundEffect(int n)3414     public static int getNthNavigationRepeatSoundEffect(int n) {
3415         switch (n) {
3416             case 0:
3417                 return FX_FOCUS_NAVIGATION_REPEAT_1;
3418             case 1:
3419                 return FX_FOCUS_NAVIGATION_REPEAT_2;
3420             case 2:
3421                 return FX_FOCUS_NAVIGATION_REPEAT_3;
3422             case 3:
3423                 return FX_FOCUS_NAVIGATION_REPEAT_4;
3424             default:
3425                 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
3426                 return -1;
3427         }
3428     }
3429 
3430     /**
3431      * @hide
3432      */
setNavigationRepeatSoundEffectsEnabled(boolean enabled)3433     public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
3434         try {
3435             getService().setNavigationRepeatSoundEffectsEnabled(enabled);
3436         } catch (RemoteException e) {
3437 
3438         }
3439     }
3440 
3441     /**
3442      * @hide
3443      * @return true if the navigation repeat sound effects are enabled
3444      */
areNavigationRepeatSoundEffectsEnabled()3445     public boolean areNavigationRepeatSoundEffectsEnabled() {
3446         try {
3447             return getService().areNavigationRepeatSoundEffectsEnabled();
3448         } catch (RemoteException e) {
3449             throw e.rethrowFromSystemServer();
3450         }
3451     }
3452 
3453     /**
3454      * @hide
3455      * @param enabled
3456      */
setHomeSoundEffectEnabled(boolean enabled)3457     public void setHomeSoundEffectEnabled(boolean enabled) {
3458         try {
3459             getService().setHomeSoundEffectEnabled(enabled);
3460         } catch (RemoteException e) {
3461 
3462         }
3463     }
3464 
3465     /**
3466      * @hide
3467      * @return true if the home sound effect is enabled
3468      */
isHomeSoundEffectEnabled()3469     public boolean isHomeSoundEffectEnabled() {
3470         try {
3471             return getService().isHomeSoundEffectEnabled();
3472         } catch (RemoteException e) {
3473             throw e.rethrowFromSystemServer();
3474         }
3475     }
3476 
3477     /**
3478      * Plays a sound effect (Key clicks, lid open/close...)
3479      * @param effectType The type of sound effect.
3480      * NOTE: This version uses the UI settings to determine
3481      * whether sounds are heard or not.
3482      */
playSoundEffect(@ystemSoundEffect int effectType)3483     public void playSoundEffect(@SystemSoundEffect int effectType) {
3484         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3485             return;
3486         }
3487 
3488         if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) {
3489             return;
3490         }
3491 
3492         final IAudioService service = getService();
3493         try {
3494             service.playSoundEffect(effectType);
3495         } catch (RemoteException e) {
3496             throw e.rethrowFromSystemServer();
3497         }
3498     }
3499 
3500     /**
3501      * Plays a sound effect (Key clicks, lid open/close...)
3502      * @param effectType The type of sound effect.
3503      * @param userId The current user to pull sound settings from
3504      * NOTE: This version uses the UI settings to determine
3505      * whether sounds are heard or not.
3506      * @hide
3507      */
playSoundEffect(@ystemSoundEffect int effectType, int userId)3508     public void  playSoundEffect(@SystemSoundEffect int effectType, int userId) {
3509         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3510             return;
3511         }
3512 
3513         if (!querySoundEffectsEnabled(userId)) {
3514             return;
3515         }
3516 
3517         final IAudioService service = getService();
3518         try {
3519             service.playSoundEffect(effectType);
3520         } catch (RemoteException e) {
3521             throw e.rethrowFromSystemServer();
3522         }
3523     }
3524 
3525     /**
3526      * Plays a sound effect (Key clicks, lid open/close...)
3527      * @param effectType The type of sound effect.
3528      * @param volume Sound effect volume.
3529      * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3530      * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
3531      * NOTE: This version is for applications that have their own
3532      * settings panel for enabling and controlling volume.
3533      */
playSoundEffect(@ystemSoundEffect int effectType, float volume)3534     public void  playSoundEffect(@SystemSoundEffect int effectType, float volume) {
3535         if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3536             return;
3537         }
3538 
3539         final IAudioService service = getService();
3540         try {
3541             service.playSoundEffectVolume(effectType, volume);
3542         } catch (RemoteException e) {
3543             throw e.rethrowFromSystemServer();
3544         }
3545     }
3546 
3547     /**
3548      * Settings has an in memory cache, so this is fast.
3549      */
querySoundEffectsEnabled(int user)3550     private boolean querySoundEffectsEnabled(int user) {
3551         return Settings.System.getIntForUser(getContext().getContentResolver(),
3552                 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
3553     }
3554 
3555     /**
3556      *  Load Sound effects.
3557      *  This method must be called when sound effects are enabled.
3558      */
loadSoundEffects()3559     public void loadSoundEffects() {
3560         final IAudioService service = getService();
3561         try {
3562             service.loadSoundEffects();
3563         } catch (RemoteException e) {
3564             throw e.rethrowFromSystemServer();
3565         }
3566     }
3567 
3568     /**
3569      *  Unload Sound effects.
3570      *  This method can be called to free some memory when
3571      *  sound effects are disabled.
3572      */
unloadSoundEffects()3573     public void unloadSoundEffects() {
3574         final IAudioService service = getService();
3575         try {
3576             service.unloadSoundEffects();
3577         } catch (RemoteException e) {
3578             throw e.rethrowFromSystemServer();
3579         }
3580     }
3581 
3582     /**
3583      * @hide
3584      */
audioFocusToString(int focus)3585     public static String audioFocusToString(int focus) {
3586         switch (focus) {
3587             case AUDIOFOCUS_NONE:
3588                 return "AUDIOFOCUS_NONE";
3589             case AUDIOFOCUS_GAIN:
3590                 return "AUDIOFOCUS_GAIN";
3591             case AUDIOFOCUS_GAIN_TRANSIENT:
3592                 return "AUDIOFOCUS_GAIN_TRANSIENT";
3593             case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3594                 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3595             case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3596                 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3597             case AUDIOFOCUS_LOSS:
3598                 return "AUDIOFOCUS_LOSS";
3599             case AUDIOFOCUS_LOSS_TRANSIENT:
3600                 return "AUDIOFOCUS_LOSS_TRANSIENT";
3601             case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3602                 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3603             default:
3604                 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3605         }
3606     }
3607 
3608     /**
3609      * Used to indicate no audio focus has been gained or lost, or requested.
3610      */
3611     public static final int AUDIOFOCUS_NONE = 0;
3612 
3613     /**
3614      * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
3615      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3616      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3617      */
3618     public static final int AUDIOFOCUS_GAIN = 1;
3619     /**
3620      * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3621      * amount of time. Examples of temporary changes are the playback of driving directions, or an
3622      * event notification.
3623      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3624      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3625      */
3626     public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
3627     /**
3628      * Used to indicate a temporary request of audio focus, anticipated to last a short
3629      * amount of time, and where it is acceptable for other audio applications to keep playing
3630      * after having lowered their output level (also referred to as "ducking").
3631      * Examples of temporary changes are the playback of driving directions where playback of music
3632      * in the background is acceptable.
3633      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3634      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3635      */
3636     public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3637     /**
3638      * Used to indicate a temporary request of audio focus, anticipated to last a short
3639      * amount of time, during which no other applications, or system components, should play
3640      * anything. Examples of exclusive and transient audio focus requests are voice
3641      * memo recording and speech recognition, during which the system shouldn't play any
3642      * notifications, and media playback should have paused.
3643      * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3644      */
3645     public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3646     /**
3647      * Used to indicate a loss of audio focus of unknown duration.
3648      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3649      */
3650     public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3651     /**
3652      * Used to indicate a transient loss of audio focus.
3653      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3654      */
3655     public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3656     /**
3657      * Used to indicate a transient loss of audio focus where the loser of the audio focus can
3658      * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3659      * the new focus owner doesn't require others to be silent.
3660      * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
3661      */
3662     public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3663             -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
3664 
3665     /**
3666      * Interface definition for a callback to be invoked when the audio focus of the system is
3667      * updated.
3668      */
3669     public interface OnAudioFocusChangeListener {
3670         /**
3671          * Called on the listener to notify it the audio focus for this listener has been changed.
3672          * The focusChange value indicates whether the focus was gained,
3673          * whether the focus was lost, and whether that loss is transient, or whether the new focus
3674          * holder will hold it for an unknown amount of time.
3675          * When losing focus, listeners can use the focus change information to decide what
3676          * behavior to adopt when losing focus. A music player could for instance elect to lower
3677          * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3678          * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
3679          *   {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
3680          *   and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
3681          */
onAudioFocusChange(int focusChange)3682         public void onAudioFocusChange(int focusChange);
3683     }
3684 
3685     /**
3686      * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3687      */
3688     private static class FocusRequestInfo {
3689         @NonNull  final AudioFocusRequest mRequest;
3690         @Nullable final Handler mHandler;
FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)3691         FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3692             mRequest = afr;
3693             mHandler = handler;
3694         }
3695     }
3696 
3697     /**
3698      * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3699      * to actual listener objects.
3700      */
3701     @UnsupportedAppUsage
3702     private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3703             new ConcurrentHashMap<String, FocusRequestInfo>();
3704 
findFocusRequestInfo(String id)3705     private FocusRequestInfo findFocusRequestInfo(String id) {
3706         return mAudioFocusIdListenerMap.get(id);
3707     }
3708 
3709     /**
3710      * Handler for events (audio focus change, recording config change) coming from the
3711      * audio service.
3712      */
3713     private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
3714             new ServiceEventHandlerDelegate(null);
3715 
3716     /**
3717      * Event types
3718      */
3719     private final static int MSSG_FOCUS_CHANGE = 0;
3720     private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
3721     private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
3722 
3723     /**
3724      * Helper class to handle the forwarding of audio service events to the appropriate listener
3725      */
3726     private class ServiceEventHandlerDelegate {
3727         private final Handler mHandler;
3728 
ServiceEventHandlerDelegate(Handler handler)3729         ServiceEventHandlerDelegate(Handler handler) {
3730             Looper looper;
3731             if (handler == null) {
3732                 if ((looper = Looper.myLooper()) == null) {
3733                     looper = Looper.getMainLooper();
3734                 }
3735             } else {
3736                 looper = handler.getLooper();
3737             }
3738 
3739             if (looper != null) {
3740                 // implement the event handler delegate to receive events from audio service
3741                 mHandler = new Handler(looper) {
3742                     @Override
3743                     public void handleMessage(Message msg) {
3744                         switch (msg.what) {
3745                             case MSSG_FOCUS_CHANGE: {
3746                                 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3747                                 if (fri != null)  {
3748                                     final OnAudioFocusChangeListener listener =
3749                                             fri.mRequest.getOnAudioFocusChangeListener();
3750                                     if (listener != null) {
3751                                         Log.d(TAG, "dispatching onAudioFocusChange("
3752                                                 + msg.arg1 + ") to " + msg.obj);
3753                                         listener.onAudioFocusChange(msg.arg1);
3754                                     }
3755                                 }
3756                             } break;
3757                             case MSSG_RECORDING_CONFIG_CHANGE: {
3758                                 final RecordConfigChangeCallbackData cbData =
3759                                         (RecordConfigChangeCallbackData) msg.obj;
3760                                 if (cbData.mCb != null) {
3761                                     cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
3762                                 }
3763                             } break;
3764                             case MSSG_PLAYBACK_CONFIG_CHANGE: {
3765                                 final PlaybackConfigChangeCallbackData cbData =
3766                                         (PlaybackConfigChangeCallbackData) msg.obj;
3767                                 if (cbData.mCb != null) {
3768                                     if (DEBUG) {
3769                                         Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3770                                     }
3771                                     cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3772                                 }
3773                             } break;
3774                             default:
3775                                 Log.e(TAG, "Unknown event " + msg.what);
3776                         }
3777                     }
3778                 };
3779             } else {
3780                 mHandler = null;
3781             }
3782         }
3783 
getHandler()3784         Handler getHandler() {
3785             return mHandler;
3786         }
3787     }
3788 
3789     private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
3790         @Override
3791         public void dispatchAudioFocusChange(int focusChange, String id) {
3792             final FocusRequestInfo fri = findFocusRequestInfo(id);
3793             if (fri != null)  {
3794                 final OnAudioFocusChangeListener listener =
3795                         fri.mRequest.getOnAudioFocusChangeListener();
3796                 if (listener != null) {
3797                     final Handler h = (fri.mHandler == null) ?
3798                             mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3799                     final Message m = h.obtainMessage(
3800                             MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3801                             id/*obj*/);
3802                     h.sendMessage(m);
3803                 }
3804             }
3805         }
3806 
3807         @Override
3808         public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3809             synchronized (mFocusRequestsLock) {
3810                 // TODO use generation counter as the key instead
3811                 final BlockingFocusResultReceiver focusReceiver =
3812                         mFocusRequestsAwaitingResult.remove(clientId);
3813                 if (focusReceiver != null) {
3814                     focusReceiver.notifyResult(requestResult);
3815                 } else {
3816                     Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3817                 }
3818             }
3819         }
3820     };
3821 
getIdForAudioFocusListener(OnAudioFocusChangeListener l)3822     private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
3823         if (l == null) {
3824             return new String(this.toString());
3825         } else {
3826             return new String(this.toString() + l.toString());
3827         }
3828     }
3829 
3830     /**
3831      * @hide
3832      * Registers a listener to be called when audio focus changes and keeps track of the associated
3833      * focus request (including Handler to use for the listener).
3834      * @param afr the full request parameters
3835      */
registerAudioFocusRequest(@onNull AudioFocusRequest afr)3836     public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3837         final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3838         final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3839             new ServiceEventHandlerDelegate(h).getHandler());
3840         final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3841         mAudioFocusIdListenerMap.put(key, fri);
3842     }
3843 
3844     /**
3845      * @hide
3846      * Causes the specified listener to not be called anymore when focus is gained or lost.
3847      * @param l the listener to unregister.
3848      */
unregisterAudioFocusRequest(OnAudioFocusChangeListener l)3849     public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
3850         // remove locally
3851         mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
3852     }
3853 
3854 
3855     /**
3856      * A failed focus change request.
3857      */
3858     public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3859     /**
3860      * A successful focus change request.
3861      */
3862     public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
3863      /**
3864       * A focus change request whose granting is delayed: the request was successful, but the
3865       * requester will only be granted audio focus once the condition that prevented immediate
3866       * granting has ended.
3867       * See {@link #requestAudioFocus(AudioFocusRequest)} and
3868       * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
3869       */
3870     public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
3871 
3872     /** @hide */
3873     @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3874             AUDIOFOCUS_REQUEST_FAILED,
3875             AUDIOFOCUS_REQUEST_GRANTED,
3876             AUDIOFOCUS_REQUEST_DELAYED }
3877     )
3878     @Retention(RetentionPolicy.SOURCE)
3879     public @interface FocusRequestResult {}
3880 
3881     /**
3882      * @hide
3883      * code returned when a synchronous focus request on the client-side is to be blocked
3884      * until the external audio focus policy decides on the response for the client
3885      */
3886     public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3887 
3888     /**
3889      * Timeout duration in ms when waiting on an external focus policy for the result for a
3890      * focus request
3891      */
3892     private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
3893 
3894     private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
3895 
3896     private final Object mFocusRequestsLock = new Object();
3897     /**
3898      * Map of all receivers of focus request results, one per unresolved focus request.
3899      * Receivers are added before sending the request to the external focus policy,
3900      * and are removed either after receiving the result, or after the timeout.
3901      * This variable is lazily initialized.
3902      */
3903     @GuardedBy("mFocusRequestsLock")
3904     private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
3905 
3906 
3907     /**
3908      *  Request audio focus.
3909      *  Send a request to obtain the audio focus
3910      *  @param l the listener to be notified of audio focus changes
3911      *  @param streamType the main audio stream type affected by the focus request
3912      *  @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
3913      *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
3914      *      for the playback of driving directions, or notifications sounds.
3915      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
3916      *      the previous focus owner to keep playing if it ducks its audio output.
3917      *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
3918      *      that benefits from the system not playing disruptive sounds like notifications, for
3919      *      usecases such as voice memo recording, or speech recognition.
3920      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
3921      *      as the playback of a song or a video.
3922      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
3923      *  @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
3924      */
requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)3925     public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
3926         PlayerBase.deprecateStreamTypeForPlayback(streamType,
3927                 "AudioManager", "requestAudioFocus()");
3928         int status = AUDIOFOCUS_REQUEST_FAILED;
3929 
3930         try {
3931             // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
3932             // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
3933             // AUDIOFOCUS_FLAG_DELAY_OK flag
3934             status = requestAudioFocus(l,
3935                     new AudioAttributes.Builder()
3936                             .setInternalLegacyStreamType(streamType).build(),
3937                     durationHint,
3938                     0 /* flags, legacy behavior */);
3939         } catch (IllegalArgumentException e) {
3940             Log.e(TAG, "Audio focus request denied due to ", e);
3941         }
3942 
3943         return status;
3944     }
3945 
3946     // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
3947     /**
3948      * @hide
3949      * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
3950      * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
3951      * the system is in a state where focus cannot change, but be granted focus later when
3952      * this condition ends.
3953      */
3954     @SystemApi
3955     public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
3956     /**
3957      * @hide
3958      * Use this flag when requesting audio focus to indicate that the requester
3959      * will pause its media playback (if applicable) when losing audio focus with
3960      * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
3961      * <br>On some platforms, the ducking may be handled without the application being aware of it
3962      * (i.e. it will not transiently lose focus). For applications that for instance play spoken
3963      * content, such as audio book or podcast players, ducking may never be acceptable, and will
3964      * thus always pause. This flag enables them to be declared as such whenever they request focus.
3965      */
3966     @SystemApi
3967     public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
3968     /**
3969      * @hide
3970      * Use this flag to lock audio focus so granting is temporarily disabled.
3971      * <br>This flag can only be used by owners of a registered
3972      * {@link android.media.audiopolicy.AudioPolicy} in
3973      * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
3974      */
3975     @SystemApi
3976     public static final int AUDIOFOCUS_FLAG_LOCK     = 0x1 << 2;
3977 
3978     /**
3979      * @hide
3980      * flag set on test API calls,
3981      * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
3982      * note that it isn't used in conjunction with other flags, it is passed as the single
3983      * value for flags */
3984     public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
3985     /** @hide */
3986     public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
3987             | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
3988     /** @hide */
3989     public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
3990             | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
3991 
3992     /**
3993      * Request audio focus.
3994      * See the {@link AudioFocusRequest} for information about the options available to configure
3995      * your request, and notification of focus gain and loss.
3996      * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
3997      *   requested.
3998      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
3999      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4000      *     <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4001      *     is requested without building the {@link AudioFocusRequest} with
4002      *     {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4003      *     {@code true}.
4004      * @throws NullPointerException if passed a null argument
4005      */
requestAudioFocus(@onNull AudioFocusRequest focusRequest)4006     public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
4007         return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
4008     }
4009 
4010     /**
4011      *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4012      *  @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4013      *      with {@link #requestAudioFocus(AudioFocusRequest)}.
4014      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4015      *  @throws IllegalArgumentException if passed a null argument
4016      */
abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4017     public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4018         if (focusRequest == null) {
4019             throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4020         }
4021         return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4022                 focusRequest.getAudioAttributes());
4023     }
4024 
4025     /**
4026      * @hide
4027      * Request audio focus.
4028      * Send a request to obtain the audio focus. This method differs from
4029      * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4030      * that the requester accepts delayed grants of audio focus.
4031      * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4032      *     when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4033      * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4034      *     requesting audio focus.
4035      * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4036      *      is temporary, and focus will be abandonned shortly. Examples of transient requests are
4037      *      for the playback of driving directions, or notifications sounds.
4038      *      Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4039      *      the previous focus owner to keep playing if it ducks its audio output.
4040      *      Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4041      *      that benefits from the system not playing disruptive sounds like notifications, for
4042      *      usecases such as voice memo recording, or speech recognition.
4043      *      Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4044      *      as the playback of a song or a video.
4045      * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4046      *     {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
4047      *     <br>Use 0 when not using any flags for the request, which behaves like
4048      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4049      *     focus is granted immediately, or the grant request fails because the system is in a
4050      *     state where focus cannot change (e.g. a phone call).
4051      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4052      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4053      *     The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4054      *     without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4055      * @throws IllegalArgumentException
4056      */
4057     @SystemApi
4058     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags)4059     public int requestAudioFocus(OnAudioFocusChangeListener l,
4060             @NonNull AudioAttributes requestAttributes,
4061             int durationHint,
4062             int flags) throws IllegalArgumentException {
4063         if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4064             throw new IllegalArgumentException("Invalid flags 0x"
4065                     + Integer.toHexString(flags).toUpperCase());
4066         }
4067         return requestAudioFocus(l, requestAttributes, durationHint,
4068                 flags & AUDIOFOCUS_FLAGS_APPS,
4069                 null /* no AudioPolicy*/);
4070     }
4071 
4072     /**
4073      * @hide
4074      * Request or lock audio focus.
4075      * This method is to be used by system components that have registered an
4076      * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4077      * so focus granting is temporarily disabled.
4078      * @param l see the description of the same parameter in
4079      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4080      * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4081      *     requesting audio focus.
4082      * @param durationHint see the description of the same parameter in
4083      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4084      * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4085      *     {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
4086      *     <br>Use 0 when not using any flags for the request, which behaves like
4087      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4088      *     focus is granted immediately, or the grant request fails because the system is in a
4089      *     state where focus cannot change (e.g. a phone call).
4090      * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4091      *     focus, or null.
4092      * @return see the description of the same return value in
4093      *     {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4094      * @throws IllegalArgumentException
4095      * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
4096      */
4097     @SystemApi
4098     @RequiresPermission(anyOf= {
4099             android.Manifest.permission.MODIFY_PHONE_STATE,
4100             android.Manifest.permission.MODIFY_AUDIO_ROUTING
4101     })
requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int durationHint, int flags, AudioPolicy ap)4102     public int requestAudioFocus(OnAudioFocusChangeListener l,
4103             @NonNull AudioAttributes requestAttributes,
4104             int durationHint,
4105             int flags,
4106             AudioPolicy ap) throws IllegalArgumentException {
4107         // parameter checking
4108         if (requestAttributes == null) {
4109             throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4110         }
4111         if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
4112             throw new IllegalArgumentException("Invalid duration hint");
4113         }
4114         if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
4115             throw new IllegalArgumentException("Illegal flags 0x"
4116                 + Integer.toHexString(flags).toUpperCase());
4117         }
4118         if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4119             throw new IllegalArgumentException(
4120                     "Illegal null focus listener when flagged as accepting delayed focus grant");
4121         }
4122         if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4123                 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4124             throw new IllegalArgumentException(
4125                     "Illegal null focus listener when flagged as pausing instead of ducking");
4126         }
4127         if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4128             throw new IllegalArgumentException(
4129                     "Illegal null audio policy when locking audio focus");
4130         }
4131 
4132         final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
4133                 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
4134                 .setAudioAttributes(requestAttributes)
4135                 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4136                         == AUDIOFOCUS_FLAG_DELAY_OK)
4137                 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4138                         == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4139                 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4140                 .build();
4141         return requestAudioFocus(afr, ap);
4142     }
4143 
4144     /**
4145      * @hide
4146      * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4147      * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4148      * @param afr the parameters of the request
4149      * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4150      * @param clientFakeUid the UID of the client, here an arbitrary int,
4151      *                      doesn't have to be a real UID
4152      * @param clientTargetSdk the target SDK used by the client
4153      * @return return code indicating status of the request
4154      */
4155     @TestApi
4156     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4157     public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4158             @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4159         Objects.requireNonNull(afr);
4160         Objects.requireNonNull(clientFakeId);
4161         try {
4162             return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4163                     afr.getFocusGain(),
4164                     mICallBack,
4165                     mAudioFocusDispatcher,
4166                     clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
4167         } catch (RemoteException e) {
4168             throw e.rethrowFromSystemServer();
4169         }
4170     }
4171 
4172     /**
4173      * @hide
4174      * Test API to abandon audio focus for an arbitrary client.
4175      * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4176      * @param afr the parameters used for the request
4177      * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4178      *      would be requesting
4179      * @return return code indicating status of the request
4180      */
4181     @TestApi
4182     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4183     public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4184             @NonNull String clientFakeId) {
4185         Objects.requireNonNull(afr);
4186         Objects.requireNonNull(clientFakeId);
4187         try {
4188             return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4189                     clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4190         } catch (RemoteException e) {
4191             throw e.rethrowFromSystemServer();
4192         }
4193     }
4194 
4195     /**
4196      * @hide
4197      * Return the duration of the fade out applied when a player of the given AudioAttributes
4198      * is losing audio focus
4199      * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4200      * @return a duration in ms, 0 indicates no fade out is applied
4201      */
4202     @TestApi
4203     @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4204     public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4205     {
4206         Objects.requireNonNull(aa);
4207         try {
4208             return getService().getFadeOutDurationOnFocusLossMillis(aa);
4209         } catch (RemoteException e) {
4210             throw e.rethrowFromSystemServer();
4211         }
4212     }
4213 
4214     /**
4215      * @hide
4216      * Request or lock audio focus.
4217      * This method is to be used by system components that have registered an
4218      * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4219      * so focus granting is temporarily disabled.
4220      * @param afr see the description of the same parameter in
4221      *     {@link #requestAudioFocus(AudioFocusRequest)}
4222      * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4223      *     focus, or null.
4224      * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4225      *     or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4226      * @throws NullPointerException if the AudioFocusRequest is null
4227      * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4228      */
4229     @SystemApi
4230     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)4231     public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4232         if (afr == null) {
4233             throw new NullPointerException("Illegal null AudioFocusRequest");
4234         }
4235         // this can only be checked now, not during the creation of the AudioFocusRequest instance
4236         if (afr.locksFocus() && ap == null) {
4237             throw new IllegalArgumentException(
4238                     "Illegal null audio policy when locking audio focus");
4239         }
4240         registerAudioFocusRequest(afr);
4241         final IAudioService service = getService();
4242         final int status;
4243         int sdk;
4244         try {
4245             sdk = getContext().getApplicationInfo().targetSdkVersion;
4246         } catch (NullPointerException e) {
4247             // some tests don't have a Context
4248             sdk = Build.VERSION.SDK_INT;
4249         }
4250 
4251         final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4252         final BlockingFocusResultReceiver focusReceiver;
4253         synchronized (mFocusRequestsLock) {
4254             try {
4255                 // TODO status contains result and generation counter for ext policy
4256                 status = service.requestAudioFocus(afr.getAudioAttributes(),
4257                         afr.getFocusGain(), mICallBack,
4258                         mAudioFocusDispatcher,
4259                         clientId,
4260                         getContext().getOpPackageName() /* package name */, afr.getFlags(),
4261                         ap != null ? ap.cb() : null,
4262                         sdk);
4263             } catch (RemoteException e) {
4264                 throw e.rethrowFromSystemServer();
4265             }
4266             if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4267                 // default path with no external focus policy
4268                 return status;
4269             }
4270             if (mFocusRequestsAwaitingResult == null) {
4271                 mFocusRequestsAwaitingResult =
4272                         new HashMap<String, BlockingFocusResultReceiver>(1);
4273             }
4274             focusReceiver = new BlockingFocusResultReceiver(clientId);
4275             mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
4276         }
4277         focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4278         if (DEBUG && !focusReceiver.receivedResult()) {
4279             Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4280         }
4281         synchronized (mFocusRequestsLock) {
4282             mFocusRequestsAwaitingResult.remove(clientId);
4283         }
4284         return focusReceiver.requestResult();
4285     }
4286 
4287     // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4288     private static final class SafeWaitObject {
4289         private boolean mQuit = false;
4290 
safeNotify()4291         public void safeNotify() {
4292             synchronized (this) {
4293                 mQuit = true;
4294                 this.notify();
4295             }
4296         }
4297 
safeWait(long millis)4298         public void safeWait(long millis) throws InterruptedException {
4299             final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4300             synchronized (this) {
4301                 while (!mQuit) {
4302                     final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4303                     if (timeToWait < 0) { break; }
4304                     this.wait(timeToWait);
4305                 }
4306             }
4307         }
4308     }
4309 
4310     private static final class BlockingFocusResultReceiver {
4311         private final SafeWaitObject mLock = new SafeWaitObject();
4312         @GuardedBy("mLock")
4313         private boolean mResultReceived = false;
4314         // request denied by default (e.g. timeout)
4315         private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4316         private final String mFocusClientId;
4317 
BlockingFocusResultReceiver(String clientId)4318         BlockingFocusResultReceiver(String clientId) {
4319             mFocusClientId = clientId;
4320         }
4321 
receivedResult()4322         boolean receivedResult() { return mResultReceived; }
requestResult()4323         int requestResult() { return mFocusRequestResult; }
4324 
notifyResult(int requestResult)4325         void notifyResult(int requestResult) {
4326             synchronized (mLock) {
4327                 mResultReceived = true;
4328                 mFocusRequestResult = requestResult;
4329                 mLock.safeNotify();
4330             }
4331         }
4332 
waitForResult(long timeOutMs)4333         public void waitForResult(long timeOutMs) {
4334             synchronized (mLock) {
4335                 if (mResultReceived) {
4336                     // the result was received before waiting
4337                     return;
4338                 }
4339                 try {
4340                     mLock.safeWait(timeOutMs);
4341                 } catch (InterruptedException e) { }
4342             }
4343         }
4344     }
4345 
4346     /**
4347      * @hide
4348      * Used internally by telephony package to request audio focus. Will cause the focus request
4349      * to be associated with the "voice communication" identifier only used in AudioService
4350      * to identify this use case.
4351      * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4352      *    the establishment of the call
4353      * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4354      *    media applications resume after a call
4355      */
4356     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
requestAudioFocusForCall(int streamType, int durationHint)4357     public void requestAudioFocusForCall(int streamType, int durationHint) {
4358         final IAudioService service = getService();
4359         try {
4360             service.requestAudioFocus(new AudioAttributes.Builder()
4361                         .setInternalLegacyStreamType(streamType).build(),
4362                     durationHint, mICallBack, null,
4363                     AudioSystem.IN_VOICE_COMM_FOCUS_ID,
4364                     getContext().getOpPackageName(),
4365                     AUDIOFOCUS_FLAG_LOCK,
4366                     null /* policy token */, 0 /* sdk n/a here*/);
4367         } catch (RemoteException e) {
4368             throw e.rethrowFromSystemServer();
4369         }
4370     }
4371 
4372     /**
4373      * @hide
4374      * Return the volume ramping time for a sound to be played after the given focus request,
4375      *   and to play a sound of the given attributes
4376      * @param focusGain
4377      * @param attr
4378      * @return
4379      */
getFocusRampTimeMs(int focusGain, AudioAttributes attr)4380     public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
4381         final IAudioService service = getService();
4382         try {
4383             return service.getFocusRampTimeMs(focusGain, attr);
4384         } catch (RemoteException e) {
4385             throw e.rethrowFromSystemServer();
4386         }
4387     }
4388 
4389     /**
4390      * @hide
4391      * Set the result to the audio focus request received through
4392      * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4393      * @param afi the information about the focus requester
4394      * @param requestResult the result to the focus request to be passed to the requester
4395      * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4396      */
4397     @SystemApi
4398     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)4399     public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4400             @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4401         if (afi == null) {
4402             throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4403         }
4404         if (ap == null) {
4405             throw new IllegalArgumentException("Illegal null AudioPolicy");
4406         }
4407         final IAudioService service = getService();
4408         try {
4409             service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4410         } catch (RemoteException e) {
4411             throw e.rethrowFromSystemServer();
4412         }
4413     }
4414 
4415     /**
4416      * @hide
4417      * Notifies an application with a focus listener of gain or loss of audio focus.
4418      * This method can only be used by owners of an {@link AudioPolicy} configured with
4419      * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4420      * @param afi the recipient of the focus change, that has previously requested audio focus, and
4421      *     that was received by the {@code AudioPolicy} through
4422      *     {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4423      * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4424      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4425      *     {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4426      *     or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4427      *     {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4428      *     or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4429      *     <br>For the focus gain, the change type should be the same as the app requested.
4430      * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4431      * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4432      *     {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4433      *     if there was an error sending the request.
4434      * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4435      */
4436     @SystemApi
4437     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)4438     public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4439             @NonNull AudioPolicy ap) {
4440         if (afi == null) {
4441             throw new NullPointerException("Illegal null AudioFocusInfo");
4442         }
4443         if (ap == null) {
4444             throw new NullPointerException("Illegal null AudioPolicy");
4445         }
4446         final IAudioService service = getService();
4447         try {
4448             return service.dispatchFocusChange(afi, focusChange, ap.cb());
4449         } catch (RemoteException e) {
4450             throw e.rethrowFromSystemServer();
4451         }
4452     }
4453 
4454     /**
4455      * @hide
4456      * Used internally by telephony package to abandon audio focus, typically after a call or
4457      * when ringing ends and the call is rejected or not answered.
4458      * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4459      */
4460     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
abandonAudioFocusForCall()4461     public void abandonAudioFocusForCall() {
4462         final IAudioService service = getService();
4463         try {
4464             service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
4465                     null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
4466         } catch (RemoteException e) {
4467             throw e.rethrowFromSystemServer();
4468         }
4469     }
4470 
4471     /**
4472      *  Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4473      *  @param l the listener with which focus was requested.
4474      *  @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4475      *  @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
4476      */
abandonAudioFocus(OnAudioFocusChangeListener l)4477     public int abandonAudioFocus(OnAudioFocusChangeListener l) {
4478         return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4479     }
4480 
4481     /**
4482      * @hide
4483      * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4484      *  @param l the listener with which focus was requested.
4485      * @param aa the {@link AudioAttributes} with which audio focus was requested
4486      * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4487      * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
4488      */
4489     @SystemApi
4490     @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4491     // have been done by a matching requestAudioFocus
abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)4492     public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
4493         int status = AUDIOFOCUS_REQUEST_FAILED;
4494         unregisterAudioFocusRequest(l);
4495         final IAudioService service = getService();
4496         try {
4497             status = service.abandonAudioFocus(mAudioFocusDispatcher,
4498                     getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
4499         } catch (RemoteException e) {
4500             throw e.rethrowFromSystemServer();
4501         }
4502         return status;
4503     }
4504 
4505     //====================================================================
4506     // Remote Control
4507     /**
4508      * Register a component to be the sole receiver of MEDIA_BUTTON intents.
4509      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4510      *      that will receive the media button intent. This broadcast receiver must be declared
4511      *      in the application manifest. The package of the component must match that of
4512      *      the context you're registering from.
4513      * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
4514      */
4515     @Deprecated
registerMediaButtonEventReceiver(ComponentName eventReceiver)4516     public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
4517         if (eventReceiver == null) {
4518             return;
4519         }
4520         if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
4521             Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4522                     "receiver and context package names don't match");
4523             return;
4524         }
4525         // construct a PendingIntent for the media button and register it
4526         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4527         //     the associated intent will be handled by the component being registered
4528         mediaButtonIntent.setComponent(eventReceiver);
4529         PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4530                 0/*requestCode, ignored*/, mediaButtonIntent,
4531                 PendingIntent.FLAG_IMMUTABLE);
4532         registerMediaButtonIntent(pi, eventReceiver);
4533     }
4534 
4535     /**
4536      * Register a component to be the sole receiver of MEDIA_BUTTON intents.  This is like
4537      * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4538      * the buttons to go to any PendingIntent.  Note that you should only use this form if
4539      * you know you will continue running for the full time until unregistering the
4540      * PendingIntent.
4541      * @param eventReceiver target that will receive media button intents.  The PendingIntent
4542      * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4543      * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4544      * media button that was pressed.
4545      * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
4546      */
4547     @Deprecated
registerMediaButtonEventReceiver(PendingIntent eventReceiver)4548     public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4549         if (eventReceiver == null) {
4550             return;
4551         }
4552         registerMediaButtonIntent(eventReceiver, null);
4553     }
4554 
4555     /**
4556      * @hide
4557      * no-op if (pi == null) or (eventReceiver == null)
4558      */
registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)4559     public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
4560         if (pi == null) {
4561             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4562             return;
4563         }
4564         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4565         helper.addMediaButtonListener(pi, eventReceiver, getContext());
4566     }
4567 
4568     /**
4569      * Unregister the receiver of MEDIA_BUTTON intents.
4570      * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4571      *      that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
4572      * @deprecated Use {@link MediaSession} instead.
4573      */
4574     @Deprecated
unregisterMediaButtonEventReceiver(ComponentName eventReceiver)4575     public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
4576         if (eventReceiver == null) {
4577             return;
4578         }
4579         // construct a PendingIntent for the media button and unregister it
4580         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4581         //     the associated intent will be handled by the component being registered
4582         mediaButtonIntent.setComponent(eventReceiver);
4583         PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4584                 0/*requestCode, ignored*/, mediaButtonIntent,
4585                 PendingIntent.FLAG_IMMUTABLE);
4586         unregisterMediaButtonIntent(pi);
4587     }
4588 
4589     /**
4590      * Unregister the receiver of MEDIA_BUTTON intents.
4591      * @param eventReceiver same PendingIntent that was registed with
4592      *      {@link #registerMediaButtonEventReceiver(PendingIntent)}.
4593      * @deprecated Use {@link MediaSession} instead.
4594      */
4595     @Deprecated
unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)4596     public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4597         if (eventReceiver == null) {
4598             return;
4599         }
4600         unregisterMediaButtonIntent(eventReceiver);
4601     }
4602 
4603     /**
4604      * @hide
4605      */
unregisterMediaButtonIntent(PendingIntent pi)4606     public void unregisterMediaButtonIntent(PendingIntent pi) {
4607         MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4608         helper.removeMediaButtonListener(pi);
4609     }
4610 
4611     /**
4612      * Registers the remote control client for providing information to display on the remote
4613      * controls.
4614      * @param rcClient The remote control client from which remote controls will receive
4615      *      information to display.
4616      * @see RemoteControlClient
4617      * @deprecated Use {@link MediaSession} instead.
4618      */
4619     @Deprecated
registerRemoteControlClient(RemoteControlClient rcClient)4620     public void registerRemoteControlClient(RemoteControlClient rcClient) {
4621         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
4622             return;
4623         }
4624         rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
4625     }
4626 
4627     /**
4628      * Unregisters the remote control client that was providing information to display on the
4629      * remote controls.
4630      * @param rcClient The remote control client to unregister.
4631      * @see #registerRemoteControlClient(RemoteControlClient)
4632      * @deprecated Use {@link MediaSession} instead.
4633      */
4634     @Deprecated
unregisterRemoteControlClient(RemoteControlClient rcClient)4635     public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
4636         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
4637             return;
4638         }
4639         rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
4640     }
4641 
4642     /**
4643      * Registers a {@link RemoteController} instance for it to receive media
4644      * metadata updates and playback state information from applications using
4645      * {@link RemoteControlClient}, and control their playback.
4646      * <p>
4647      * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
4648      * one of the enabled notification listeners (see
4649      * {@link android.service.notification.NotificationListenerService}).
4650      *
4651      * @param rctlr the object to register.
4652      * @return true if the {@link RemoteController} was successfully registered,
4653      *         false if an error occurred, due to an internal system error, or
4654      *         insufficient permissions.
4655      * @deprecated Use
4656      *             {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4657      *             and {@link MediaController} instead.
4658      */
4659     @Deprecated
registerRemoteController(RemoteController rctlr)4660     public boolean registerRemoteController(RemoteController rctlr) {
4661         if (rctlr == null) {
4662             return false;
4663         }
4664         rctlr.startListeningToSessions();
4665         return true;
4666     }
4667 
4668     /**
4669      * Unregisters a {@link RemoteController}, causing it to no longer receive
4670      * media metadata and playback state information, and no longer be capable
4671      * of controlling playback.
4672      *
4673      * @param rctlr the object to unregister.
4674      * @deprecated Use
4675      *             {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4676      *             instead.
4677      */
4678     @Deprecated
unregisterRemoteController(RemoteController rctlr)4679     public void unregisterRemoteController(RemoteController rctlr) {
4680         if (rctlr == null) {
4681             return;
4682         }
4683         rctlr.stopListeningToSessions();
4684     }
4685 
4686 
4687     //====================================================================
4688     // Audio policy
4689     /**
4690      * @hide
4691      * Register the given {@link AudioPolicy}.
4692      * This call is synchronous and blocks until the registration process successfully completed
4693      * or failed to complete.
4694      * @param policy the non-null {@link AudioPolicy} to register.
4695      * @return {@link #ERROR} if there was an error communicating with the registration service
4696      *    or if the user doesn't have the required
4697      *    {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4698      *    {@link #SUCCESS} otherwise.
4699      */
4700     @SystemApi
4701     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
registerAudioPolicy(@onNull AudioPolicy policy)4702     public int registerAudioPolicy(@NonNull AudioPolicy policy) {
4703         return registerAudioPolicyStatic(policy);
4704     }
4705 
registerAudioPolicyStatic(@onNull AudioPolicy policy)4706     static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
4707         if (policy == null) {
4708             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4709         }
4710         final IAudioService service = getService();
4711         try {
4712             MediaProjection projection = policy.getMediaProjection();
4713             String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
4714                     policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4715                     policy.isVolumeController(),
4716                     projection == null ? null : projection.getProjection());
4717             if (regId == null) {
4718                 return ERROR;
4719             } else {
4720                 policy.setRegistration(regId);
4721             }
4722             // successful registration
4723         } catch (RemoteException e) {
4724             throw e.rethrowFromSystemServer();
4725         }
4726         return SUCCESS;
4727     }
4728 
4729     /**
4730      * @hide
4731      * Unregisters an {@link AudioPolicy} asynchronously.
4732      * @param policy the non-null {@link AudioPolicy} to unregister.
4733      */
4734     @SystemApi
4735     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
unregisterAudioPolicyAsync(@onNull AudioPolicy policy)4736     public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
4737         unregisterAudioPolicyAsyncStatic(policy);
4738     }
4739 
unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)4740     static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
4741         if (policy == null) {
4742             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4743         }
4744         final IAudioService service = getService();
4745         try {
4746             service.unregisterAudioPolicyAsync(policy.cb());
4747             policy.reset();
4748         } catch (RemoteException e) {
4749             throw e.rethrowFromSystemServer();
4750         }
4751     }
4752 
4753     /**
4754      * @hide
4755      * Unregisters an {@link AudioPolicy} synchronously.
4756      * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4757      * associated with mixes of this policy.
4758      * @param policy the non-null {@link AudioPolicy} to unregister.
4759      */
4760     @SystemApi
4761     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
unregisterAudioPolicy(@onNull AudioPolicy policy)4762     public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4763         Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4764         final IAudioService service = getService();
4765         try {
4766             policy.invalidateCaptorsAndInjectors();
4767             service.unregisterAudioPolicy(policy.cb());
4768             policy.reset();
4769         } catch (RemoteException e) {
4770             throw e.rethrowFromSystemServer();
4771         }
4772     }
4773 
4774     /**
4775      * @hide
4776      * @return true if an AudioPolicy was previously registered
4777      */
4778     @TestApi
hasRegisteredDynamicPolicy()4779     public boolean hasRegisteredDynamicPolicy() {
4780         final IAudioService service = getService();
4781         try {
4782             return service.hasRegisteredDynamicPolicy();
4783         } catch (RemoteException e) {
4784             throw e.rethrowFromSystemServer();
4785         }
4786     }
4787 
4788     //====================================================================
4789     // Notification of playback activity & playback configuration
4790     /**
4791      * Interface for receiving update notifications about the playback activity on the system.
4792      * Extend this abstract class and register it with
4793      * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4794      * to be notified.
4795      * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4796      * configuration.
4797      * @see AudioPlaybackConfiguration
4798      */
4799     public static abstract class AudioPlaybackCallback {
4800         /**
4801          * Called whenever the playback activity and configuration has changed.
4802          * @param configs list containing the results of
4803          *      {@link AudioManager#getActivePlaybackConfigurations()}.
4804          */
onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)4805         public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4806     }
4807 
4808     private static class AudioPlaybackCallbackInfo {
4809         final AudioPlaybackCallback mCb;
4810         final Handler mHandler;
AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)4811         AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4812             mCb = cb;
4813             mHandler = handler;
4814         }
4815     }
4816 
4817     private final static class PlaybackConfigChangeCallbackData {
4818         final AudioPlaybackCallback mCb;
4819         final List<AudioPlaybackConfiguration> mConfigs;
4820 
PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)4821         PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4822                 List<AudioPlaybackConfiguration> configs) {
4823             mCb = cb;
4824             mConfigs = configs;
4825         }
4826     }
4827 
4828     /**
4829      * Register a callback to be notified of audio playback changes through
4830      * {@link AudioPlaybackCallback}
4831      * @param cb non-null callback to register
4832      * @param handler the {@link Handler} object for the thread on which to execute
4833      * the callback. If <code>null</code>, the {@link Handler} associated with the main
4834      * {@link Looper} will be used.
4835      */
registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)4836     public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4837                                               @Nullable Handler handler)
4838     {
4839         if (cb == null) {
4840             throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4841         }
4842 
4843         synchronized(mPlaybackCallbackLock) {
4844             // lazy initialization of the list of playback callbacks
4845             if (mPlaybackCallbackList == null) {
4846                 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4847             }
4848             final int oldCbCount = mPlaybackCallbackList.size();
4849             if (!hasPlaybackCallback_sync(cb)) {
4850                 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4851                         new ServiceEventHandlerDelegate(handler).getHandler()));
4852                 final int newCbCount = mPlaybackCallbackList.size();
4853                 if ((oldCbCount == 0) && (newCbCount > 0)) {
4854                     // register binder for callbacks
4855                     try {
4856                         getService().registerPlaybackCallback(mPlayCb);
4857                     } catch (RemoteException e) {
4858                         throw e.rethrowFromSystemServer();
4859                     }
4860                 }
4861             } else {
4862                 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4863                         + "registered callback");
4864             }
4865         }
4866     }
4867 
4868     /**
4869      * Unregister an audio playback callback previously registered with
4870      * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4871      * @param cb non-null callback to unregister
4872      */
unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)4873     public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4874         if (cb == null) {
4875             throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4876         }
4877         synchronized(mPlaybackCallbackLock) {
4878             if (mPlaybackCallbackList == null) {
4879                 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4880                         + " that was never registered");
4881                 return;
4882             }
4883             final int oldCbCount = mPlaybackCallbackList.size();
4884             if (removePlaybackCallback_sync(cb)) {
4885                 final int newCbCount = mPlaybackCallbackList.size();
4886                 if ((oldCbCount > 0) && (newCbCount == 0)) {
4887                     // unregister binder for callbacks
4888                     try {
4889                         getService().unregisterPlaybackCallback(mPlayCb);
4890                     } catch (RemoteException e) {
4891                         throw e.rethrowFromSystemServer();
4892                     }
4893                 }
4894             } else {
4895                 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4896                         + " already unregistered or never registered");
4897             }
4898         }
4899     }
4900 
4901     /**
4902      * Returns the current active audio playback configurations of the device
4903      * @return a non-null list of playback configurations. An empty list indicates there is no
4904      *     playback active when queried.
4905      * @see AudioPlaybackConfiguration
4906      */
getActivePlaybackConfigurations()4907     public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
4908         final IAudioService service = getService();
4909         try {
4910             return service.getActivePlaybackConfigurations();
4911         } catch (RemoteException e) {
4912             throw e.rethrowFromSystemServer();
4913         }
4914     }
4915 
4916     /**
4917      * All operations on this list are sync'd on mPlaybackCallbackLock.
4918      * List is lazy-initialized in
4919      * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4920      * List can be null.
4921      */
4922     private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
4923     private final Object mPlaybackCallbackLock = new Object();
4924 
4925     /**
4926      * Must be called synchronized on mPlaybackCallbackLock
4927      */
hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4928     private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4929         if (mPlaybackCallbackList != null) {
4930             for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4931                 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4932                     return true;
4933                 }
4934             }
4935         }
4936         return false;
4937     }
4938 
4939     /**
4940      * Must be called synchronized on mPlaybackCallbackLock
4941      */
removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)4942     private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4943         if (mPlaybackCallbackList != null) {
4944             for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4945                 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4946                     mPlaybackCallbackList.remove(i);
4947                     return true;
4948                 }
4949             }
4950         }
4951         return false;
4952     }
4953 
4954     private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
4955         @Override
4956         public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
4957                 boolean flush) {
4958             if (flush) {
4959                 Binder.flushPendingCommands();
4960             }
4961             synchronized(mPlaybackCallbackLock) {
4962                 if (mPlaybackCallbackList != null) {
4963                     for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4964                         final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
4965                         if (arci.mHandler != null) {
4966                             final Message m = arci.mHandler.obtainMessage(
4967                                     MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
4968                                     new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
4969                             arci.mHandler.sendMessage(m);
4970                         }
4971                     }
4972                 }
4973             }
4974         }
4975 
4976     };
4977 
4978     //====================================================================
4979     // Notification of recording activity & recording configuration
4980     /**
4981      * Interface for receiving update notifications about the recording configuration. Extend
4982      * this abstract class and register it with
4983      * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
4984      * to be notified.
4985      * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
4986      * configuration.
4987      * @see AudioRecordingConfiguration
4988      */
4989     public static abstract class AudioRecordingCallback {
4990         /**
4991          * Called whenever the device recording configuration has changed.
4992          * @param configs list containing the results of
4993          *      {@link AudioManager#getActiveRecordingConfigurations()}.
4994          */
onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)4995         public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
4996     }
4997 
4998     private static class AudioRecordingCallbackInfo {
4999         final AudioRecordingCallback mCb;
5000         final Handler mHandler;
AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5001         AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5002             mCb = cb;
5003             mHandler = handler;
5004         }
5005     }
5006 
5007     private final static class RecordConfigChangeCallbackData {
5008         final AudioRecordingCallback mCb;
5009         final List<AudioRecordingConfiguration> mConfigs;
5010 
RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5011         RecordConfigChangeCallbackData(AudioRecordingCallback cb,
5012                 List<AudioRecordingConfiguration> configs) {
5013             mCb = cb;
5014             mConfigs = configs;
5015         }
5016     }
5017 
5018     /**
5019      * Register a callback to be notified of audio recording changes through
5020      * {@link AudioRecordingCallback}
5021      * @param cb non-null callback to register
5022      * @param handler the {@link Handler} object for the thread on which to execute
5023      * the callback. If <code>null</code>, the {@link Handler} associated with the main
5024      * {@link Looper} will be used.
5025      */
registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5026     public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5027                                                @Nullable Handler handler)
5028     {
5029         if (cb == null) {
5030             throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5031         }
5032 
5033         synchronized(mRecordCallbackLock) {
5034             // lazy initialization of the list of recording callbacks
5035             if (mRecordCallbackList == null) {
5036                 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
5037             }
5038             final int oldCbCount = mRecordCallbackList.size();
5039             if (!hasRecordCallback_sync(cb)) {
5040                 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5041                         new ServiceEventHandlerDelegate(handler).getHandler()));
5042                 final int newCbCount = mRecordCallbackList.size();
5043                 if ((oldCbCount == 0) && (newCbCount > 0)) {
5044                     // register binder for callbacks
5045                     final IAudioService service = getService();
5046                     try {
5047                         service.registerRecordingCallback(mRecCb);
5048                     } catch (RemoteException e) {
5049                         throw e.rethrowFromSystemServer();
5050                     }
5051                 }
5052             } else {
5053                 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5054                         + "registered callback");
5055             }
5056         }
5057     }
5058 
5059     /**
5060      * Unregister an audio recording callback previously registered with
5061      * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5062      * @param cb non-null callback to unregister
5063      */
unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5064     public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5065         if (cb == null) {
5066             throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5067         }
5068         synchronized(mRecordCallbackLock) {
5069             if (mRecordCallbackList == null) {
5070                 return;
5071             }
5072             final int oldCbCount = mRecordCallbackList.size();
5073             if (removeRecordCallback_sync(cb)) {
5074                 final int newCbCount = mRecordCallbackList.size();
5075                 if ((oldCbCount > 0) && (newCbCount == 0)) {
5076                     // unregister binder for callbacks
5077                     final IAudioService service = getService();
5078                     try {
5079                         service.unregisterRecordingCallback(mRecCb);
5080                     } catch (RemoteException e) {
5081                         throw e.rethrowFromSystemServer();
5082                     }
5083                 }
5084             } else {
5085                 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5086                         + " already unregistered or never registered");
5087             }
5088         }
5089     }
5090 
5091     /**
5092      * Returns the current active audio recording configurations of the device.
5093      * @return a non-null list of recording configurations. An empty list indicates there is
5094      *     no recording active when queried.
5095      * @see AudioRecordingConfiguration
5096      */
getActiveRecordingConfigurations()5097     public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
5098         final IAudioService service = getService();
5099         try {
5100             return service.getActiveRecordingConfigurations();
5101         } catch (RemoteException e) {
5102             throw e.rethrowFromSystemServer();
5103         }
5104     }
5105 
5106     /**
5107      * constants for the recording events, to keep in sync
5108      * with frameworks/av/include/media/AudioPolicy.h
5109      */
5110     /** @hide */
5111     public static final int RECORD_CONFIG_EVENT_NONE = -1;
5112     /** @hide */
5113     public static final int RECORD_CONFIG_EVENT_START = 0;
5114     /** @hide */
5115     public static final int RECORD_CONFIG_EVENT_STOP = 1;
5116     /** @hide */
5117     public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5118     /** @hide */
5119     public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
5120     /**
5121      * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5122      */
5123     /** @hide */
5124     public static final int RECORD_RIID_INVALID = -1;
5125     /** @hide */
5126     public static final int RECORDER_STATE_STARTED = 0;
5127     /** @hide */
5128     public static final int RECORDER_STATE_STOPPED = 1;
5129 
5130     /**
5131      * All operations on this list are sync'd on mRecordCallbackLock.
5132      * List is lazy-initialized in
5133      * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5134      * List can be null.
5135      */
5136     private List<AudioRecordingCallbackInfo> mRecordCallbackList;
5137     private final Object mRecordCallbackLock = new Object();
5138 
5139     /**
5140      * Must be called synchronized on mRecordCallbackLock
5141      */
hasRecordCallback_sync(@onNull AudioRecordingCallback cb)5142     private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5143         if (mRecordCallbackList != null) {
5144             for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5145                 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5146                     return true;
5147                 }
5148             }
5149         }
5150         return false;
5151     }
5152 
5153     /**
5154      * Must be called synchronized on mRecordCallbackLock
5155      */
removeRecordCallback_sync(@onNull AudioRecordingCallback cb)5156     private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5157         if (mRecordCallbackList != null) {
5158             for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5159                 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5160                     mRecordCallbackList.remove(i);
5161                     return true;
5162                 }
5163             }
5164         }
5165         return false;
5166     }
5167 
5168     private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
5169         @Override
5170         public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
5171             synchronized(mRecordCallbackLock) {
5172                 if (mRecordCallbackList != null) {
5173                     for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5174                         final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5175                         if (arci.mHandler != null) {
5176                             final Message m = arci.mHandler.obtainMessage(
5177                                     MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5178                                     new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
5179                             arci.mHandler.sendMessage(m);
5180                         }
5181                     }
5182                 }
5183             }
5184         }
5185 
5186     };
5187 
5188     //=====================================================================
5189 
5190     /**
5191      *  @hide
5192      *  Reload audio settings. This method is called by Settings backup
5193      *  agent when audio settings are restored and causes the AudioService
5194      *  to read and apply restored settings.
5195      */
5196     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
reloadAudioSettings()5197     public void reloadAudioSettings() {
5198         final IAudioService service = getService();
5199         try {
5200             service.reloadAudioSettings();
5201         } catch (RemoteException e) {
5202             throw e.rethrowFromSystemServer();
5203         }
5204     }
5205 
5206     /**
5207      * @hide
5208      * Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
5209      * so that AudioService can send volume change events to the A2DP device, rather than handling
5210      * them.
5211      */
avrcpSupportsAbsoluteVolume(String address, boolean support)5212     public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
5213         final IAudioService service = getService();
5214         try {
5215             service.avrcpSupportsAbsoluteVolume(address, support);
5216         } catch (RemoteException e) {
5217             throw e.rethrowFromSystemServer();
5218         }
5219     }
5220 
5221      /**
5222       * {@hide}
5223       */
5224      private final IBinder mICallBack = new Binder();
5225 
5226     /**
5227      * Checks whether the phone is in silent mode, with or without vibrate.
5228      *
5229      * @return true if phone is in silent mode, with or without vibrate.
5230      *
5231      * @see #getRingerMode()
5232      *
5233      * @hide pending API Council approval
5234      */
5235     @UnsupportedAppUsage
isSilentMode()5236     public boolean isSilentMode() {
5237         int ringerMode = getRingerMode();
5238         boolean silentMode =
5239             (ringerMode == RINGER_MODE_SILENT) ||
5240             (ringerMode == RINGER_MODE_VIBRATE);
5241         return silentMode;
5242     }
5243 
5244     // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5245     // class is not used by other parts of the framework, which instead use definitions and methods
5246     // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5247 
5248     /** @hide
5249      * The audio device code for representing "no device." */
5250     public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5251     /** @hide
5252      *  The audio output device code for the small speaker at the front of the device used
5253      *  when placing calls.  Does not refer to an in-ear headphone without attached microphone,
5254      *  such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5255      *  {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5256      */
5257     @UnsupportedAppUsage
5258     public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
5259     /** @hide
5260      *  The audio output device code for the built-in speaker */
5261     @UnsupportedAppUsage
5262     public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
5263     /** @hide
5264      * The audio output device code for a wired headset with attached microphone */
5265     @UnsupportedAppUsage
5266     public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
5267     /** @hide
5268      * The audio output device code for a wired headphone without attached microphone */
5269     @UnsupportedAppUsage
5270     public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5271     /** @hide
5272      * The audio output device code for a USB headphone with attached microphone */
5273     public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5274     /** @hide
5275      * The audio output device code for generic Bluetooth SCO, for voice */
5276     public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
5277     /** @hide
5278      * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5279      * Hands-Free Profile (HFP), for voice
5280      */
5281     @UnsupportedAppUsage
5282     public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5283             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
5284     /** @hide
5285      * The audio output device code for Bluetooth SCO car audio, for voice */
5286     public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5287             AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
5288     /** @hide
5289      * The audio output device code for generic Bluetooth A2DP, for music */
5290     @UnsupportedAppUsage
5291     public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
5292     /** @hide
5293      * The audio output device code for Bluetooth A2DP headphones, for music */
5294     @UnsupportedAppUsage
5295     public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5296             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
5297     /** @hide
5298      * The audio output device code for Bluetooth A2DP external speaker, for music */
5299     @UnsupportedAppUsage
5300     public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5301             AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
5302     /** @hide
5303      * The audio output device code for S/PDIF (legacy) or HDMI
5304      * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
5305     public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
5306     /** @hide
5307      * The audio output device code for HDMI */
5308     @UnsupportedAppUsage
5309     public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5310     /** @hide
5311      * The audio output device code for an analog wired headset attached via a
5312      *  docking station
5313      */
5314     @UnsupportedAppUsage
5315     public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5316     /** @hide
5317      * The audio output device code for a digital wired headset attached via a
5318      *  docking station
5319      */
5320     @UnsupportedAppUsage
5321     public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
5322     /** @hide
5323      * The audio output device code for a USB audio accessory. The accessory is in USB host
5324      * mode and the Android device in USB device mode
5325      */
5326     public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
5327     /** @hide
5328      * The audio output device code for a USB audio device. The device is in USB device
5329      * mode and the Android device in USB host mode
5330      */
5331     public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
5332     /** @hide
5333      * The audio output device code for projection output.
5334      */
5335     public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5336     /** @hide
5337      * The audio output device code the telephony voice TX path.
5338      */
5339     public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5340     /** @hide
5341      * The audio output device code for an analog jack with line impedance detected.
5342      */
5343     public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5344     /** @hide
5345      * The audio output device code for HDMI Audio Return Channel.
5346      */
5347     public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5348     /** @hide
5349      * The audio output device code for HDMI enhanced Audio Return Channel.
5350      */
5351     public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5352     /** @hide
5353      * The audio output device code for S/PDIF digital connection.
5354      */
5355     public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5356     /** @hide
5357      * The audio output device code for built-in FM transmitter.
5358      */
5359     public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5360     /** @hide
5361      * The audio output device code for echo reference injection point.
5362      */
5363     public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5364     /** @hide
5365      * The audio output device code for a BLE audio headset.
5366      */
5367     public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5368     /** @hide
5369      * The audio output device code for a BLE audio speaker.
5370      */
5371     public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5372     /** @hide
5373      * This is not used as a returned value from {@link #getDevicesForStream}, but could be
5374      *  used in the future in a set method to select whatever default device is chosen by the
5375      *  platform-specific implementation.
5376      */
5377     public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5378 
5379     /** @hide
5380      * The audio input device code for default built-in microphone
5381      */
5382     public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5383     /** @hide
5384      * The audio input device code for a Bluetooth SCO headset
5385      */
5386     public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5387                                     AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5388     /** @hide
5389      * The audio input device code for wired headset microphone
5390      */
5391     public static final int DEVICE_IN_WIRED_HEADSET =
5392                                     AudioSystem.DEVICE_IN_WIRED_HEADSET;
5393     /** @hide
5394      * The audio input device code for HDMI
5395      */
5396     public static final int DEVICE_IN_HDMI =
5397                                     AudioSystem.DEVICE_IN_HDMI;
5398     /** @hide
5399      * The audio input device code for HDMI ARC
5400      */
5401     public static final int DEVICE_IN_HDMI_ARC =
5402                                     AudioSystem.DEVICE_IN_HDMI_ARC;
5403 
5404     /** @hide
5405      * The audio input device code for HDMI EARC
5406      */
5407     public static final int DEVICE_IN_HDMI_EARC =
5408                                     AudioSystem.DEVICE_IN_HDMI_EARC;
5409 
5410     /** @hide
5411      * The audio input device code for telephony voice RX path
5412      */
5413     public static final int DEVICE_IN_TELEPHONY_RX =
5414                                     AudioSystem.DEVICE_IN_TELEPHONY_RX;
5415     /** @hide
5416      * The audio input device code for built-in microphone pointing to the back
5417      */
5418     public static final int DEVICE_IN_BACK_MIC =
5419                                     AudioSystem.DEVICE_IN_BACK_MIC;
5420     /** @hide
5421      * The audio input device code for analog from a docking station
5422      */
5423     public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5424                                     AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5425     /** @hide
5426      * The audio input device code for digital from a docking station
5427      */
5428     public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5429                                     AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5430     /** @hide
5431      * The audio input device code for a USB audio accessory. The accessory is in USB host
5432      * mode and the Android device in USB device mode
5433      */
5434     public static final int DEVICE_IN_USB_ACCESSORY =
5435                                     AudioSystem.DEVICE_IN_USB_ACCESSORY;
5436     /** @hide
5437      * The audio input device code for a USB audio device. The device is in USB device
5438      * mode and the Android device in USB host mode
5439      */
5440     public static final int DEVICE_IN_USB_DEVICE =
5441                                     AudioSystem.DEVICE_IN_USB_DEVICE;
5442     /** @hide
5443      * The audio input device code for a FM radio tuner
5444      */
5445     public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5446     /** @hide
5447      * The audio input device code for a TV tuner
5448      */
5449     public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5450     /** @hide
5451      * The audio input device code for an analog jack with line impedance detected
5452      */
5453     public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5454     /** @hide
5455      * The audio input device code for a S/PDIF digital connection
5456      */
5457     public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
5458     /** @hide
5459      * The audio input device code for audio loopback
5460      */
5461     public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
5462     /** @hide
5463      * The audio input device code for an echo reference capture point.
5464      */
5465     public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5466     /** @hide
5467      * The audio input device code for a BLE audio headset.
5468      */
5469     public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
5470 
5471     /**
5472      * Return true if the device code corresponds to an output device.
5473      * @hide
5474      */
isOutputDevice(int device)5475     public static boolean isOutputDevice(int device)
5476     {
5477         return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5478     }
5479 
5480     /**
5481      * Return true if the device code corresponds to an input device.
5482      * @hide
5483      */
isInputDevice(int device)5484     public static boolean isInputDevice(int device)
5485     {
5486         return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5487     }
5488 
5489 
5490     /**
5491      * Return the enabled devices for the specified output stream type.
5492      *
5493      * @param streamType The stream type to query. One of
5494      *            {@link #STREAM_VOICE_CALL},
5495      *            {@link #STREAM_SYSTEM},
5496      *            {@link #STREAM_RING},
5497      *            {@link #STREAM_MUSIC},
5498      *            {@link #STREAM_ALARM},
5499      *            {@link #STREAM_NOTIFICATION},
5500      *            {@link #STREAM_DTMF},
5501      *            {@link #STREAM_ACCESSIBILITY}.
5502      *
5503      * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5504      *         stream. Zero or more of
5505      *            {@link #DEVICE_OUT_EARPIECE},
5506      *            {@link #DEVICE_OUT_SPEAKER},
5507      *            {@link #DEVICE_OUT_WIRED_HEADSET},
5508      *            {@link #DEVICE_OUT_WIRED_HEADPHONE},
5509      *            {@link #DEVICE_OUT_BLUETOOTH_SCO},
5510      *            {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5511      *            {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5512      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5513      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5514      *            {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
5515      *            {@link #DEVICE_OUT_HDMI},
5516      *            {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5517      *            {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
5518      *            {@link #DEVICE_OUT_USB_ACCESSORY}.
5519      *            {@link #DEVICE_OUT_USB_DEVICE}.
5520      *            {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5521      *            {@link #DEVICE_OUT_TELEPHONY_TX}.
5522      *            {@link #DEVICE_OUT_LINE}.
5523      *            {@link #DEVICE_OUT_HDMI_ARC}.
5524      *            {@link #DEVICE_OUT_HDMI_EARC}.
5525      *            {@link #DEVICE_OUT_SPDIF}.
5526      *            {@link #DEVICE_OUT_FM}.
5527      *            {@link #DEVICE_OUT_DEFAULT} is not used here.
5528      *
5529      * The implementation may support additional device codes beyond those listed, so
5530      * the application should ignore any bits which it does not recognize.
5531      * Note that the information may be imprecise when the implementation
5532      * cannot distinguish whether a particular device is enabled.
5533      *
5534      * {@hide}
5535      */
5536     @UnsupportedAppUsage
getDevicesForStream(int streamType)5537     public int getDevicesForStream(int streamType) {
5538         switch (streamType) {
5539         case STREAM_VOICE_CALL:
5540         case STREAM_SYSTEM:
5541         case STREAM_RING:
5542         case STREAM_MUSIC:
5543         case STREAM_ALARM:
5544         case STREAM_NOTIFICATION:
5545         case STREAM_DTMF:
5546         case STREAM_ACCESSIBILITY:
5547             final IAudioService service = getService();
5548             try {
5549                 return service.getDevicesForStream(streamType);
5550             } catch (RemoteException e) {
5551                 throw e.rethrowFromSystemServer();
5552             }
5553         default:
5554             return 0;
5555         }
5556     }
5557 
5558     /**
5559      * @hide
5560      * Get the audio devices that would be used for the routing of the given audio attributes.
5561      * @param attributes the {@link AudioAttributes} for which the routing is being queried
5562      * @return an empty list if there was an issue with the request, a list of audio devices
5563      *   otherwise (typically one device, except for duplicated paths).
5564      */
5565     @SystemApi
5566     @RequiresPermission(anyOf = {
5567             android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5568             android.Manifest.permission.QUERY_AUDIO_STATE
5569     })
getDevicesForAttributes( @onNull AudioAttributes attributes)5570     public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
5571             @NonNull AudioAttributes attributes) {
5572         Objects.requireNonNull(attributes);
5573         final IAudioService service = getService();
5574         try {
5575             return service.getDevicesForAttributes(attributes);
5576         } catch (RemoteException e) {
5577             throw e.rethrowFromSystemServer();
5578         }
5579     }
5580 
5581     /**
5582      * @hide
5583      * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
5584      * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5585      * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
5586      */
5587     public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5588     /**
5589      * @hide
5590      * Volume behavior for an audio device where a software attenuation is applied
5591      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
5592      */
5593     @SystemApi
5594     public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5595     /**
5596      * @hide
5597      * Volume behavior for an audio device where the volume is always set to provide no attenuation
5598      *     nor gain (e.g. unit gain).
5599      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
5600      */
5601     @SystemApi
5602     public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5603     /**
5604      * @hide
5605      * Volume behavior for an audio device where the volume is either set to muted, or to provide
5606      *     no attenuation nor gain (e.g. unit gain).
5607      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
5608      */
5609     @SystemApi
5610     public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5611     /**
5612      * @hide
5613      * Volume behavior for an audio device where no software attenuation is applied, and
5614      *     the volume is kept synchronized between the host and the device itself through a
5615      *     device-specific protocol such as BT AVRCP.
5616      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
5617      */
5618     @SystemApi
5619     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5620     /**
5621      * @hide
5622      * Volume behavior for an audio device where no software attenuation is applied, and
5623      *     the volume is kept synchronized between the host and the device itself through a
5624      *     device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5625      *     normal vs in phone call).
5626      * @see #setMode(int)
5627      * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
5628      */
5629     @SystemApi
5630     public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5631 
5632     /** @hide */
5633     @IntDef({
5634             DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5635             DEVICE_VOLUME_BEHAVIOR_FULL,
5636             DEVICE_VOLUME_BEHAVIOR_FIXED,
5637             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5638             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5639     })
5640     @Retention(RetentionPolicy.SOURCE)
5641     public @interface DeviceVolumeBehavior {}
5642 
5643     /** @hide */
5644     @IntDef({
5645             DEVICE_VOLUME_BEHAVIOR_UNSET,
5646             DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5647             DEVICE_VOLUME_BEHAVIOR_FULL,
5648             DEVICE_VOLUME_BEHAVIOR_FIXED,
5649             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5650             DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5651     })
5652     @Retention(RetentionPolicy.SOURCE)
5653     public @interface DeviceVolumeBehaviorState {}
5654 
5655     /**
5656      * @hide
5657      * Throws IAE on an invalid volume behavior value
5658      * @param volumeBehavior behavior value to check
5659      */
enforceValidVolumeBehavior(int volumeBehavior)5660     public static void enforceValidVolumeBehavior(int volumeBehavior) {
5661         switch (volumeBehavior) {
5662             case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5663             case DEVICE_VOLUME_BEHAVIOR_FULL:
5664             case DEVICE_VOLUME_BEHAVIOR_FIXED:
5665             case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5666             case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5667                 return;
5668             default:
5669                 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5670         }
5671     }
5672 
5673     /**
5674      * @hide
5675      * Sets the volume behavior for an audio output device.
5676      * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5677      * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5678      * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5679      * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5680      * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5681      * @param device the device to be affected
5682      * @param deviceVolumeBehavior one of the device behaviors
5683      */
5684     @SystemApi
5685     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)5686     public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5687             @DeviceVolumeBehavior int deviceVolumeBehavior) {
5688         // verify arguments (validity of device type is enforced in server)
5689         Objects.requireNonNull(device);
5690         enforceValidVolumeBehavior(deviceVolumeBehavior);
5691         // communicate with service
5692         final IAudioService service = getService();
5693         try {
5694             service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5695                     mApplicationContext.getOpPackageName());
5696         } catch (RemoteException e) {
5697             throw e.rethrowFromSystemServer();
5698         }
5699     }
5700 
5701     /**
5702      * @hide
5703      * Returns the volume device behavior for the given audio device
5704      * @param device the audio device
5705      * @return the volume behavior for the device
5706      */
5707     @SystemApi
5708     @RequiresPermission(anyOf = {
5709             android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5710             android.Manifest.permission.QUERY_AUDIO_STATE
5711     })
5712     public @DeviceVolumeBehavior
getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)5713     int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
5714         // verify arguments (validity of device type is enforced in server)
5715         Objects.requireNonNull(device);
5716         // communicate with service
5717         final IAudioService service = getService();
5718         try {
5719             return service.getDeviceVolumeBehavior(device);
5720         } catch (RemoteException e) {
5721             throw e.rethrowFromSystemServer();
5722         }
5723     }
5724 
5725     /**
5726      * @hide
5727      * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5728      */
5729     @TestApi
5730     @RequiresPermission(anyOf = {
5731             android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5732             android.Manifest.permission.QUERY_AUDIO_STATE
5733     })
isFullVolumeDevice()5734     public boolean isFullVolumeDevice() {
5735         final AudioAttributes attributes = new AudioAttributes.Builder()
5736                 .setUsage(AudioAttributes.USAGE_MEDIA)
5737                 .build();
5738         final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5739         for (AudioDeviceAttributes device : devices) {
5740             if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5741                 return true;
5742             }
5743         }
5744         return false;
5745     }
5746 
5747      /**
5748      * Indicate wired accessory connection state change.
5749      * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5750      * @param state  new connection state: 1 connected, 0 disconnected
5751      * @param name   device name
5752      * {@hide}
5753      */
5754     @UnsupportedAppUsage
5755     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
setWiredDeviceConnectionState(int type, int state, String address, String name)5756     public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
5757         final IAudioService service = getService();
5758         try {
5759             service.setWiredDeviceConnectionState(type, state, address, name,
5760                     mApplicationContext.getOpPackageName());
5761         } catch (RemoteException e) {
5762             throw e.rethrowFromSystemServer();
5763         }
5764     }
5765 
5766      /**
5767      * Indicate Hearing Aid connection state change and eventually suppress
5768      * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
5769      * This operation is asynchronous but its execution will still be sequentially scheduled
5770      * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
5771      * * BluetoothDevice, int, int, boolean, int)} and
5772      * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
5773      * @param device Bluetooth device connected/disconnected
5774      * @param state new connection state (BluetoothProfile.STATE_xxx)
5775      * @param musicDevice Default get system volume for the connecting device.
5776      * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
5777      * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
5778      * @param suppressNoisyIntent if true the
5779      * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
5780      * {@hide}
5781      */
setBluetoothHearingAidDeviceConnectionState( BluetoothDevice device, int state, boolean suppressNoisyIntent, int musicDevice)5782     public void setBluetoothHearingAidDeviceConnectionState(
5783                 BluetoothDevice device, int state, boolean suppressNoisyIntent,
5784                 int musicDevice) {
5785         final IAudioService service = getService();
5786         try {
5787             service.setBluetoothHearingAidDeviceConnectionState(device,
5788                 state, suppressNoisyIntent, musicDevice);
5789         } catch (RemoteException e) {
5790             throw e.rethrowFromSystemServer();
5791         }
5792     }
5793 
5794      /**
5795      * Indicate A2DP source or sink connection state change and eventually suppress
5796      * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
5797      * This operation is asynchronous but its execution will still be sequentially scheduled
5798      * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
5799      * int, boolean, int)} and
5800      * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
5801      * @param device Bluetooth device connected/disconnected
5802      * @param state  new connection state, {@link BluetoothProfile#STATE_CONNECTED}
5803      *     or {@link BluetoothProfile#STATE_DISCONNECTED}
5804      * @param profile profile for the A2DP device
5805      * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
5806      * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
5807      * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
5808      * @param suppressNoisyIntent if true the
5809      * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
5810      * {@hide}
5811      */
setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)5812     public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
5813             BluetoothDevice device, int state,
5814             int profile, boolean suppressNoisyIntent, int a2dpVolume) {
5815         final IAudioService service = getService();
5816         try {
5817             service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
5818                 state, profile, suppressNoisyIntent, a2dpVolume);
5819         } catch (RemoteException e) {
5820             throw e.rethrowFromSystemServer();
5821         }
5822     }
5823 
5824      /**
5825      * Indicate A2DP device configuration has changed.
5826      * This operation is asynchronous but its execution will still be sequentially scheduled
5827      * relative to calls to
5828      * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int,
5829      * boolean, int)} and
5830      * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)}
5831      * @param device Bluetooth device whose configuration has changed.
5832      * {@hide}
5833      */
handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)5834     public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
5835         final IAudioService service = getService();
5836         try {
5837             service.handleBluetoothA2dpDeviceConfigChange(device);
5838         } catch (RemoteException e) {
5839             throw e.rethrowFromSystemServer();
5840         }
5841     }
5842 
5843     /** {@hide} */
getRingtonePlayer()5844     public IRingtonePlayer getRingtonePlayer() {
5845         try {
5846             return getService().getRingtonePlayer();
5847         } catch (RemoteException e) {
5848             throw e.rethrowFromSystemServer();
5849         }
5850     }
5851 
5852     /**
5853      * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
5854      * for this device's low latency output stream, in decimal Hz.  Latency-sensitive apps
5855      * should use this value as a default, and offer the user the option to override it.
5856      * The low latency output stream is typically either the device's primary output stream,
5857      * or another output stream with smaller buffers.
5858      */
5859     // FIXME Deprecate
5860     public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5861             "android.media.property.OUTPUT_SAMPLE_RATE";
5862 
5863     /**
5864      * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
5865      * for this device's low latency output stream, in decimal PCM frames.  Latency-sensitive apps
5866      * should use this value as a minimum, and offer the user the option to override it.
5867      * The low latency output stream is typically either the device's primary output stream,
5868      * or another output stream with smaller buffers.
5869      */
5870     // FIXME Deprecate
5871     public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5872             "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5873 
5874     /**
5875      * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5876      * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5877      */
5878     public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
5879             "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
5880 
5881     /**
5882      * Used as a key for {@link #getProperty} to determine if the default speaker audio path
5883      * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5884      */
5885     public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
5886             "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
5887 
5888     /**
5889      * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
5890      * available and supported with the expected frequency range and level response.
5891      */
5892     public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
5893             "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
5894     /**
5895      * Returns the value of the property with the specified key.
5896      * @param key One of the strings corresponding to a property key: either
5897      *            {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
5898      *            {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
5899      *            {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
5900      *            {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
5901      *            {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
5902      * @return A string representing the associated value for that property key,
5903      *         or null if there is no value for that key.
5904      */
getProperty(String key)5905     public String getProperty(String key) {
5906         if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
5907             int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
5908             return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
5909         } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
5910             int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
5911             return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
5912         } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
5913             // Will throw a RuntimeException Resources.NotFoundException if this config value is
5914             // not found.
5915             return String.valueOf(getContext().getResources().getBoolean(
5916                     com.android.internal.R.bool.config_supportMicNearUltrasound));
5917         } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
5918             return String.valueOf(getContext().getResources().getBoolean(
5919                     com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
5920         } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
5921             return String.valueOf(getContext().getResources().getBoolean(
5922                     com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
5923         } else {
5924             // null or unknown key
5925             return null;
5926         }
5927     }
5928 
5929     /**
5930      * @hide
5931      * Sets an additional audio output device delay in milliseconds.
5932      *
5933      * The additional output delay is a request to the output device to
5934      * delay audio presentation (generally with respect to video presentation for better
5935      * synchronization).
5936      * It may not be supported by all output devices,
5937      * and typically increases the audio latency by the amount of additional
5938      * audio delay requested.
5939      *
5940      * If additional audio delay is supported by an audio output device,
5941      * it is expected to be supported for all output streams (and configurations)
5942      * opened on that device.
5943      *
5944      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5945      * @param delayMillis delay in milliseconds desired.  This should be in range of {@code 0}
5946      *     to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
5947      * @return true if successful, false if the device does not support output device delay
5948      *     or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
5949      */
5950     @SystemApi
5951     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)5952     public boolean setAdditionalOutputDeviceDelay(
5953             @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
5954         Objects.requireNonNull(device);
5955         try {
5956             return getService().setAdditionalOutputDeviceDelay(
5957                 new AudioDeviceAttributes(device), delayMillis);
5958         } catch (RemoteException e) {
5959             throw e.rethrowFromSystemServer();
5960         }
5961     }
5962 
5963     /**
5964      * @hide
5965      * Returns the current additional audio output device delay in milliseconds.
5966      *
5967      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5968      * @return the additional output device delay. This is a non-negative number.
5969      *     {@code 0} is returned if unsupported.
5970      */
5971     @SystemApi
5972     @IntRange(from = 0)
getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)5973     public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
5974         Objects.requireNonNull(device);
5975         try {
5976             return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
5977         } catch (RemoteException e) {
5978             throw e.rethrowFromSystemServer();
5979         }
5980     }
5981 
5982     /**
5983      * @hide
5984      * Returns the maximum additional audio output device delay in milliseconds.
5985      *
5986      * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5987      * @return the maximum output device delay in milliseconds that can be set.
5988      *     This is a non-negative number
5989      *     representing the additional audio delay supported for the device.
5990      *     {@code 0} is returned if unsupported.
5991      */
5992     @SystemApi
5993     @IntRange(from = 0)
getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)5994     public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
5995         Objects.requireNonNull(device);
5996         try {
5997             return getService().getMaxAdditionalOutputDeviceDelay(
5998                     new AudioDeviceAttributes(device));
5999         } catch (RemoteException e) {
6000             throw e.rethrowFromSystemServer();
6001         }
6002     }
6003 
6004     /**
6005      * Returns the estimated latency for the given stream type in milliseconds.
6006      *
6007      * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6008      * a better solution.
6009      * @hide
6010      */
6011     @UnsupportedAppUsage
getOutputLatency(int streamType)6012     public int getOutputLatency(int streamType) {
6013         return AudioSystem.getOutputLatency(streamType);
6014     }
6015 
6016     /**
6017      * Registers a global volume controller interface.  Currently limited to SystemUI.
6018      *
6019      * @hide
6020      */
setVolumeController(IVolumeController controller)6021     public void setVolumeController(IVolumeController controller) {
6022         try {
6023             getService().setVolumeController(controller);
6024         } catch (RemoteException e) {
6025             throw e.rethrowFromSystemServer();
6026         }
6027     }
6028 
6029     /**
6030      * Notify audio manager about volume controller visibility changes.
6031      * Currently limited to SystemUI.
6032      *
6033      * @hide
6034      */
notifyVolumeControllerVisible(IVolumeController controller, boolean visible)6035     public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6036         try {
6037             getService().notifyVolumeControllerVisible(controller, visible);
6038         } catch (RemoteException e) {
6039             throw e.rethrowFromSystemServer();
6040         }
6041     }
6042 
6043     /**
6044      * Only useful for volume controllers.
6045      * @hide
6046      */
isStreamAffectedByRingerMode(int streamType)6047     public boolean isStreamAffectedByRingerMode(int streamType) {
6048         try {
6049             return getService().isStreamAffectedByRingerMode(streamType);
6050         } catch (RemoteException e) {
6051             throw e.rethrowFromSystemServer();
6052         }
6053     }
6054 
6055     /**
6056      * Only useful for volume controllers.
6057      * @hide
6058      */
isStreamAffectedByMute(int streamType)6059     public boolean isStreamAffectedByMute(int streamType) {
6060         try {
6061             return getService().isStreamAffectedByMute(streamType);
6062         } catch (RemoteException e) {
6063             throw e.rethrowFromSystemServer();
6064         }
6065     }
6066 
6067     /**
6068      * Only useful for volume controllers.
6069      * @hide
6070      */
disableSafeMediaVolume()6071     public void disableSafeMediaVolume() {
6072         try {
6073             getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
6074         } catch (RemoteException e) {
6075             throw e.rethrowFromSystemServer();
6076         }
6077     }
6078 
6079     /**
6080      * Only useful for volume controllers.
6081      * @hide
6082      */
6083     @UnsupportedAppUsage
setRingerModeInternal(int ringerMode)6084     public void setRingerModeInternal(int ringerMode) {
6085         try {
6086             getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
6087         } catch (RemoteException e) {
6088             throw e.rethrowFromSystemServer();
6089         }
6090     }
6091 
6092     /**
6093      * Only useful for volume controllers.
6094      * @hide
6095      */
6096     @UnsupportedAppUsage
getRingerModeInternal()6097     public int getRingerModeInternal() {
6098         try {
6099             return getService().getRingerModeInternal();
6100         } catch (RemoteException e) {
6101             throw e.rethrowFromSystemServer();
6102         }
6103     }
6104 
6105     /**
6106      * Only useful for volume controllers.
6107      * @hide
6108      */
setVolumePolicy(VolumePolicy policy)6109     public void setVolumePolicy(VolumePolicy policy) {
6110         try {
6111             getService().setVolumePolicy(policy);
6112         } catch (RemoteException e) {
6113             throw e.rethrowFromSystemServer();
6114         }
6115     }
6116 
6117     /**
6118      * Set Hdmi Cec system audio mode.
6119      *
6120      * @param on whether to be on system audio mode
6121      * @return output device type. 0 (DEVICE_NONE) if failed to set device.
6122      * @hide
6123      */
setHdmiSystemAudioSupported(boolean on)6124     public int setHdmiSystemAudioSupported(boolean on) {
6125         try {
6126             return getService().setHdmiSystemAudioSupported(on);
6127         } catch (RemoteException e) {
6128             throw e.rethrowFromSystemServer();
6129         }
6130     }
6131 
6132     /**
6133      * Returns true if Hdmi Cec system audio mode is supported.
6134      *
6135      * @hide
6136      */
6137     @SystemApi
6138     @SuppressLint("RequiresPermission") // FIXME is this still used?
isHdmiSystemAudioSupported()6139     public boolean isHdmiSystemAudioSupported() {
6140         try {
6141             return getService().isHdmiSystemAudioSupported();
6142         } catch (RemoteException e) {
6143             throw e.rethrowFromSystemServer();
6144         }
6145     }
6146 
6147     /**
6148      * Return codes for listAudioPorts(), createAudioPatch() ...
6149      */
6150 
6151     /** @hide */
6152     @SystemApi
6153     public static final int SUCCESS = AudioSystem.SUCCESS;
6154     /**
6155      * A default error code.
6156      */
6157     public static final int ERROR = AudioSystem.ERROR;
6158     /** @hide
6159      * CANDIDATE FOR PUBLIC API
6160      */
6161     public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6162     /** @hide
6163      */
6164     public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6165     /** @hide
6166      */
6167     public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6168     /** @hide
6169      */
6170     public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
6171     /**
6172      * An error code indicating that the object reporting it is no longer valid and needs to
6173      * be recreated.
6174      */
6175     public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6176 
6177     /**
6178      * Returns a list of descriptors for all audio ports managed by the audio framework.
6179      * Audio ports are nodes in the audio framework or audio hardware that can be configured
6180      * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6181      * See AudioPort for a list of attributes of each audio port.
6182      * @param ports An AudioPort ArrayList where the list will be returned.
6183      * @hide
6184      */
6185     @UnsupportedAppUsage
listAudioPorts(ArrayList<AudioPort> ports)6186     public static int listAudioPorts(ArrayList<AudioPort> ports) {
6187         return updateAudioPortCache(ports, null, null);
6188     }
6189 
6190     /**
6191      * Returns a list of descriptors for all audio ports managed by the audio framework as
6192      * it was before the last update calback.
6193      * @param ports An AudioPort ArrayList where the list will be returned.
6194      * @hide
6195      */
listPreviousAudioPorts(ArrayList<AudioPort> ports)6196     public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6197         return updateAudioPortCache(null, null, ports);
6198     }
6199 
6200     /**
6201      * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6202      * @see listAudioPorts(ArrayList<AudioPort>)
6203      * @hide
6204      */
listAudioDevicePorts(ArrayList<AudioDevicePort> devices)6205     public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6206         if (devices == null) {
6207             return ERROR_BAD_VALUE;
6208         }
6209         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6210         int status = updateAudioPortCache(ports, null, null);
6211         if (status == SUCCESS) {
6212             filterDevicePorts(ports, devices);
6213         }
6214         return status;
6215     }
6216 
6217     /**
6218      * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6219      * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6220      * @hide
6221      */
listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)6222     public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6223         if (devices == null) {
6224             return ERROR_BAD_VALUE;
6225         }
6226         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6227         int status = updateAudioPortCache(null, null, ports);
6228         if (status == SUCCESS) {
6229             filterDevicePorts(ports, devices);
6230         }
6231         return status;
6232     }
6233 
filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)6234     private static void filterDevicePorts(ArrayList<AudioPort> ports,
6235                                           ArrayList<AudioDevicePort> devices) {
6236         devices.clear();
6237         for (int i = 0; i < ports.size(); i++) {
6238             if (ports.get(i) instanceof AudioDevicePort) {
6239                 devices.add((AudioDevicePort)ports.get(i));
6240             }
6241         }
6242     }
6243 
6244     /**
6245      * Create a connection between two or more devices. The framework will reject the request if
6246      * device types are not compatible or the implementation does not support the requested
6247      * configuration.
6248      * NOTE: current implementation is limited to one source and one sink per patch.
6249      * @param patch AudioPatch array where the newly created patch will be returned.
6250      *              As input, if patch[0] is not null, the specified patch will be replaced by the
6251      *              new patch created. This avoids calling releaseAudioPatch() when modifying a
6252      *              patch and allows the implementation to optimize transitions.
6253      * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6254      * @param sinks   List of sink audio ports. All must be AudioPort.ROLE_SINK.
6255      *
6256      * @return - {@link #SUCCESS} if connection is successful.
6257      *         - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6258      *         - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6259      *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6260      *         a patch.
6261      *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6262      *         - {@link #ERROR} if patch cannot be connected for any other reason.
6263      *
6264      *         patch[0] contains the newly created patch
6265      * @hide
6266      */
6267     @UnsupportedAppUsage
createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)6268     public static int createAudioPatch(AudioPatch[] patch,
6269                                  AudioPortConfig[] sources,
6270                                  AudioPortConfig[] sinks) {
6271         return AudioSystem.createAudioPatch(patch, sources, sinks);
6272     }
6273 
6274     /**
6275      * Releases an existing audio patch connection.
6276      * @param patch The audio patch to disconnect.
6277      * @return - {@link #SUCCESS} if disconnection is successful.
6278      *         - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6279      *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6280      *         a patch.
6281      *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6282      *         - {@link #ERROR} if patch cannot be released for any other reason.
6283      * @hide
6284      */
6285     @UnsupportedAppUsage
releaseAudioPatch(AudioPatch patch)6286     public static int releaseAudioPatch(AudioPatch patch) {
6287         return AudioSystem.releaseAudioPatch(patch);
6288     }
6289 
6290     /**
6291      * List all existing connections between audio ports.
6292      * @param patches An AudioPatch array where the list will be returned.
6293      * @hide
6294      */
6295     @UnsupportedAppUsage
listAudioPatches(ArrayList<AudioPatch> patches)6296     public static int listAudioPatches(ArrayList<AudioPatch> patches) {
6297         return updateAudioPortCache(null, patches, null);
6298     }
6299 
6300     /**
6301      * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6302      * AudioGain.buildConfig()
6303      * @hide
6304      */
setAudioPortGain(AudioPort port, AudioGainConfig gain)6305     public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
6306         if (port == null || gain == null) {
6307             return ERROR_BAD_VALUE;
6308         }
6309         AudioPortConfig activeConfig = port.activeConfig();
6310         AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6311                                         activeConfig.channelMask(), activeConfig.format(), gain);
6312         config.mConfigMask = AudioPortConfig.GAIN;
6313         return AudioSystem.setAudioPortConfig(config);
6314     }
6315 
6316     /**
6317      * Listener registered by client to be notified upon new audio port connections,
6318      * disconnections or attributes update.
6319      * @hide
6320      */
6321     public interface OnAudioPortUpdateListener {
6322         /**
6323          * Callback method called upon audio port list update.
6324          * @param portList the updated list of audio ports
6325          */
onAudioPortListUpdate(AudioPort[] portList)6326         public void onAudioPortListUpdate(AudioPort[] portList);
6327 
6328         /**
6329          * Callback method called upon audio patch list update.
6330          * @param patchList the updated list of audio patches
6331          */
onAudioPatchListUpdate(AudioPatch[] patchList)6332         public void onAudioPatchListUpdate(AudioPatch[] patchList);
6333 
6334         /**
6335          * Callback method called when the mediaserver dies
6336          */
onServiceDied()6337         public void onServiceDied();
6338     }
6339 
6340     /**
6341      * Register an audio port list update listener.
6342      * @hide
6343      */
6344     @UnsupportedAppUsage
registerAudioPortUpdateListener(OnAudioPortUpdateListener l)6345     public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
6346         sAudioPortEventHandler.init();
6347         sAudioPortEventHandler.registerListener(l);
6348     }
6349 
6350     /**
6351      * Unregister an audio port list update listener.
6352      * @hide
6353      */
6354     @UnsupportedAppUsage
unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)6355     public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
6356         sAudioPortEventHandler.unregisterListener(l);
6357     }
6358 
6359     //
6360     // AudioPort implementation
6361     //
6362 
6363     static final int AUDIOPORT_GENERATION_INIT = 0;
6364     static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6365     static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
6366     static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
6367     static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
6368 
resetAudioPortGeneration()6369     static int resetAudioPortGeneration() {
6370         int generation;
6371         synchronized (sAudioPortGeneration) {
6372             generation = sAudioPortGeneration;
6373             sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
6374         }
6375         return generation;
6376     }
6377 
updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)6378     static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6379                                     ArrayList<AudioPort> previousPorts) {
6380         sAudioPortEventHandler.init();
6381         synchronized (sAudioPortGeneration) {
6382 
6383             if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
6384                 int[] patchGeneration = new int[1];
6385                 int[] portGeneration = new int[1];
6386                 int status;
6387                 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6388                 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6389 
6390                 do {
6391                     newPorts.clear();
6392                     status = AudioSystem.listAudioPorts(newPorts, portGeneration);
6393                     if (status != SUCCESS) {
6394                         Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
6395                         return status;
6396                     }
6397                     newPatches.clear();
6398                     status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
6399                     if (status != SUCCESS) {
6400                         Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
6401                         return status;
6402                     }
6403                     // Loop until patch generation is the same as port generation unless audio ports
6404                     // and audio patches are not null.
6405                 } while (patchGeneration[0] != portGeneration[0]
6406                         && (ports == null || patches == null));
6407                 // If the patch generation doesn't equal port generation, return ERROR here in case
6408                 // of mismatch between audio ports and audio patches.
6409                 if (patchGeneration[0] != portGeneration[0]) {
6410                     return ERROR;
6411                 }
6412 
6413                 for (int i = 0; i < newPatches.size(); i++) {
6414                     for (int j = 0; j < newPatches.get(i).sources().length; j++) {
6415                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6416                                                                    newPorts);
6417                         newPatches.get(i).sources()[j] = portCfg;
6418                     }
6419                     for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
6420                         AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6421                                                                    newPorts);
6422                         newPatches.get(i).sinks()[j] = portCfg;
6423                     }
6424                 }
6425                 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6426                     AudioPatch newPatch = i.next();
6427                     boolean hasInvalidPort = false;
6428                     for (AudioPortConfig portCfg : newPatch.sources()) {
6429                         if (portCfg == null) {
6430                             hasInvalidPort = true;
6431                             break;
6432                         }
6433                     }
6434                     for (AudioPortConfig portCfg : newPatch.sinks()) {
6435                         if (portCfg == null) {
6436                             hasInvalidPort = true;
6437                             break;
6438                         }
6439                     }
6440                     if (hasInvalidPort) {
6441                         // Temporarily remove patches with invalid ports. One who created the patch
6442                         // is responsible for dealing with the port change.
6443                         i.remove();
6444                     }
6445                 }
6446 
6447                 sPreviousAudioPortsCached = sAudioPortsCached;
6448                 sAudioPortsCached = newPorts;
6449                 sAudioPatchesCached = newPatches;
6450                 sAudioPortGeneration = portGeneration[0];
6451             }
6452             if (ports != null) {
6453                 ports.clear();
6454                 ports.addAll(sAudioPortsCached);
6455             }
6456             if (patches != null) {
6457                 patches.clear();
6458                 patches.addAll(sAudioPatchesCached);
6459             }
6460             if (previousPorts != null) {
6461                 previousPorts.clear();
6462                 previousPorts.addAll(sPreviousAudioPortsCached);
6463             }
6464         }
6465         return SUCCESS;
6466     }
6467 
updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)6468     static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
6469         AudioPort port = portCfg.port();
6470         int k;
6471         for (k = 0; k < ports.size(); k++) {
6472             // compare handles because the port returned by JNI is not of the correct
6473             // subclass
6474             if (ports.get(k).handle().equals(port.handle())) {
6475                 port = ports.get(k);
6476                 break;
6477             }
6478         }
6479         if (k == ports.size()) {
6480             // this hould never happen
6481             Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6482             return null;
6483         }
6484         AudioGainConfig gainCfg = portCfg.gain();
6485         if (gainCfg != null) {
6486             AudioGain gain = port.gain(gainCfg.index());
6487             gainCfg = gain.buildConfig(gainCfg.mode(),
6488                                        gainCfg.channelMask(),
6489                                        gainCfg.values(),
6490                                        gainCfg.rampDurationMs());
6491         }
6492         return port.buildConfig(portCfg.samplingRate(),
6493                                                  portCfg.channelMask(),
6494                                                  portCfg.format(),
6495                                                  gainCfg);
6496     }
6497 
6498     private OnAmPortUpdateListener mPortListener = null;
6499 
6500     /**
6501      * The message sent to apps when the contents of the device list changes if they provide
6502      * a {@link Handler} object to addOnAudioDeviceConnectionListener().
6503      */
6504     private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6505     private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6506     private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
6507 
6508     /**
6509      * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6510      */
6511     private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
6512             new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
6513 
6514     /**
6515      * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6516      * the results list to only those device types they are interested in.
6517      */
6518     /**
6519      * Specifies to the {@link AudioManager#getDevices(int)} method to include
6520      * source (i.e. input) audio devices.
6521      */
6522     public static final int GET_DEVICES_INPUTS    = 0x0001;
6523 
6524     /**
6525      * Specifies to the {@link AudioManager#getDevices(int)} method to include
6526      * sink (i.e. output) audio devices.
6527      */
6528     public static final int GET_DEVICES_OUTPUTS   = 0x0002;
6529 
6530     /** @hide */
6531     @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6532             GET_DEVICES_INPUTS,
6533             GET_DEVICES_OUTPUTS }
6534     )
6535     @Retention(RetentionPolicy.SOURCE)
6536     public @interface AudioDeviceRole {}
6537 
6538     /**
6539      * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6540      * source and sink devices.
6541      */
6542     public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6543 
6544     /**
6545      * Determines if a given AudioDevicePort meets the specified filter criteria.
6546      * @param port  The port to test.
6547      * @param flags A set of bitflags specifying the criteria to test.
6548      * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6549      **/
checkFlags(AudioDevicePort port, int flags)6550     private static boolean checkFlags(AudioDevicePort port, int flags) {
6551         return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6552                port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6553     }
6554 
checkTypes(AudioDevicePort port)6555     private static boolean checkTypes(AudioDevicePort port) {
6556         return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
6557                     AudioDeviceInfo.TYPE_UNKNOWN;
6558     }
6559 
6560     /**
6561      * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6562      * currently connected to the system and meeting the criteria specified in the
6563      * <code>flags</code> parameter.
6564      * @param flags A set of bitflags specifying the criteria to test.
6565      * @see #GET_DEVICES_OUTPUTS
6566      * @see #GET_DEVICES_INPUTS
6567      * @see #GET_DEVICES_ALL
6568      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6569      */
getDevices(@udioDeviceRole int flags)6570     public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
6571         return getDevicesStatic(flags);
6572     }
6573 
6574     /**
6575      * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6576      * objects from the current (internal) AudioDevicePort list.
6577      */
6578     private static AudioDeviceInfo[]
infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)6579         infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
6580 
6581         // figure out how many AudioDeviceInfo we need space for...
6582         int numRecs = 0;
6583         for (AudioDevicePort port : ports) {
6584             if (checkTypes(port) && checkFlags(port, flags)) {
6585                 numRecs++;
6586             }
6587         }
6588 
6589         // Now load them up...
6590         AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6591         int slot = 0;
6592         for (AudioDevicePort port : ports) {
6593             if (checkTypes(port) && checkFlags(port, flags)) {
6594                 deviceList[slot++] = new AudioDeviceInfo(port);
6595             }
6596         }
6597 
6598         return deviceList;
6599     }
6600 
6601     /*
6602      * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6603      * the add/remove callback mechanism to provide a list of the newly added or removed devices
6604      * rather than the whole list and make the app figure it out.
6605      * Note that calling this method with:
6606      *  ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6607      *  ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
6608      */
calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)6609     private static AudioDeviceInfo[] calcListDeltas(
6610             ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6611 
6612         ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6613 
6614         AudioDevicePort cur_port = null;
6615         for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6616             boolean cur_port_found = false;
6617             cur_port = ports_B.get(cur_index);
6618             for (int prev_index = 0;
6619                  prev_index < ports_A.size() && !cur_port_found;
6620                  prev_index++) {
6621                 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6622             }
6623 
6624             if (!cur_port_found) {
6625                 delta_ports.add(cur_port);
6626             }
6627         }
6628 
6629         return infoListFromPortList(delta_ports, flags);
6630     }
6631 
6632     /**
6633      * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6634      * connected to the system and meeting the criteria specified in the <code>flags</code>
6635      * parameter.
6636      * This is an internal function. The public API front is getDevices(int).
6637      * @param flags A set of bitflags specifying the criteria to test.
6638      * @see #GET_DEVICES_OUTPUTS
6639      * @see #GET_DEVICES_INPUTS
6640      * @see #GET_DEVICES_ALL
6641      * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6642      * @hide
6643      */
getDevicesStatic(int flags)6644     public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6645         ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6646         int status = AudioManager.listAudioDevicePorts(ports);
6647         if (status != AudioManager.SUCCESS) {
6648             // fail and bail!
6649             return new AudioDeviceInfo[0];  // Always return an array.
6650         }
6651 
6652         return infoListFromPortList(ports, flags);
6653     }
6654 
6655     /**
6656      * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6657      * @param portId The audio port ID to look up for.
6658      * @param flags A set of bitflags specifying the criteria to test.
6659      * @see #GET_DEVICES_OUTPUTS
6660      * @see #GET_DEVICES_INPUTS
6661      * @see #GET_DEVICES_ALL
6662      * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6663      * @hide
6664      */
getDeviceForPortId(int portId, int flags)6665     public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6666         if (portId == 0) {
6667             return null;
6668         }
6669         AudioDeviceInfo[] devices = getDevicesStatic(flags);
6670         for (AudioDeviceInfo device : devices) {
6671             if (device.getId() == portId) {
6672                 return device;
6673             }
6674         }
6675         return null;
6676     }
6677 
6678     /**
6679      * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
6680      * to the set of connected audio devices.
6681      * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6682      * notifications.
6683      * @param handler Specifies the {@link Handler} object for the thread on which to execute
6684      * the callback. If <code>null</code>, the {@link Handler} associated with the main
6685      * {@link Looper} will be used.
6686      */
registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)6687     public void registerAudioDeviceCallback(AudioDeviceCallback callback,
6688             @Nullable Handler handler) {
6689         synchronized (mDeviceCallbacks) {
6690             if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
6691                 if (mDeviceCallbacks.size() == 0) {
6692                     if (mPortListener == null) {
6693                         mPortListener = new OnAmPortUpdateListener();
6694                     }
6695                     registerAudioPortUpdateListener(mPortListener);
6696                 }
6697                 NativeEventHandlerDelegate delegate =
6698                         new NativeEventHandlerDelegate(callback, handler);
6699                 mDeviceCallbacks.put(callback, delegate);
6700                 broadcastDeviceListChange_sync(delegate.getHandler());
6701             }
6702         }
6703     }
6704 
6705     /**
6706      * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
6707      * to receive notifications of changes to the set of connected audio devices.
6708      * @param callback The {@link AudioDeviceCallback} object that was previously registered
6709      * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
6710      */
unregisterAudioDeviceCallback(AudioDeviceCallback callback)6711     public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6712         synchronized (mDeviceCallbacks) {
6713             if (mDeviceCallbacks.containsKey(callback)) {
6714                 mDeviceCallbacks.remove(callback);
6715                 if (mDeviceCallbacks.size() == 0) {
6716                     unregisterAudioPortUpdateListener(mPortListener);
6717                 }
6718             }
6719         }
6720     }
6721 
6722     /**
6723      * Set port id for microphones by matching device type and address.
6724      * @hide
6725      */
setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)6726     public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6727         AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6728         for (int i = microphones.size() - 1; i >= 0; i--) {
6729             boolean foundPortId = false;
6730             for (AudioDeviceInfo device : devices) {
6731                 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6732                         && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6733                     microphones.get(i).setId(device.getId());
6734                     foundPortId = true;
6735                     break;
6736                 }
6737             }
6738             if (!foundPortId) {
6739                 Log.i(TAG, "Failed to find port id for device with type:"
6740                         + microphones.get(i).getType() + " address:"
6741                         + microphones.get(i).getAddress());
6742                 microphones.remove(i);
6743             }
6744         }
6745     }
6746 
6747     /**
6748      * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6749      * @hide
6750      */
microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)6751     public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6752         int deviceType = deviceInfo.getType();
6753         int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6754                 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6755                 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6756                         : MicrophoneInfo.LOCATION_PERIPHERAL;
6757         MicrophoneInfo microphone = new MicrophoneInfo(
6758                 deviceInfo.getPort().name() + deviceInfo.getId(),
6759                 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6760                 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6761                 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6762                 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6763                 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6764                 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6765         microphone.setId(deviceInfo.getId());
6766         return microphone;
6767     }
6768 
6769     /**
6770      * Add {@link MicrophoneInfo} by device information while filtering certain types.
6771      */
addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)6772     private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6773                     HashSet<Integer> filterTypes) {
6774         AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6775         for (AudioDeviceInfo device : devices) {
6776             if (filterTypes.contains(device.getType())) {
6777                 continue;
6778             }
6779             MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6780             microphones.add(microphone);
6781         }
6782     }
6783 
6784     /**
6785      * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6786      * of all available microphones. The list is empty when no microphones are available
6787      * on the device. An error during the query will result in an IOException being thrown.
6788      *
6789      * @return a list that contains all microphones' characteristics
6790      * @throws IOException if an error occurs.
6791      */
getMicrophones()6792     public List<MicrophoneInfo> getMicrophones() throws IOException {
6793         ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6794         int status = AudioSystem.getMicrophones(microphones);
6795         HashSet<Integer> filterTypes = new HashSet<>();
6796         filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
6797         if (status != AudioManager.SUCCESS) {
6798             // fail and populate microphones with unknown characteristics by device information.
6799             if (status != AudioManager.ERROR_INVALID_OPERATION) {
6800                 Log.e(TAG, "getMicrophones failed:" + status);
6801             }
6802             Log.i(TAG, "fallback on device info");
6803             addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6804             return microphones;
6805         }
6806         setPortIdForMicrophones(microphones);
6807         filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6808         addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6809         return microphones;
6810     }
6811 
6812     /**
6813      * Returns a list of audio formats that corresponds to encoding formats
6814      * supported on offload path for A2DP playback.
6815      *
6816      * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
6817      * supported for offload A2DP playback
6818      * @hide
6819      */
getHwOffloadEncodingFormatsSupportedForA2DP()6820     public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
6821         ArrayList<Integer> formatsList = new ArrayList<Integer>();
6822         ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
6823 
6824         int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
6825         if (status != AudioManager.SUCCESS) {
6826             Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6827             return codecConfigList;
6828         }
6829 
6830         for (Integer format : formatsList) {
6831             int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6832             if (btSourceCodec
6833                     != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6834                 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
6835             }
6836         }
6837         return codecConfigList;
6838     }
6839 
6840     // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6841     // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
6842     // of the ports that exist at the time of the last notification.
6843     private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
6844 
6845     /**
6846      * Internal method to compute and generate add/remove messages and then send to any
6847      * registered callbacks. Must be called synchronized on mDeviceCallbacks.
6848      */
broadcastDeviceListChange_sync(Handler handler)6849     private void broadcastDeviceListChange_sync(Handler handler) {
6850         int status;
6851 
6852         // Get the new current set of ports
6853         ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
6854         status = AudioManager.listAudioDevicePorts(current_ports);
6855         if (status != AudioManager.SUCCESS) {
6856             return;
6857         }
6858 
6859         if (handler != null) {
6860             // This is the callback for the registration, so send the current list
6861             AudioDeviceInfo[] deviceList =
6862                     infoListFromPortList(current_ports, GET_DEVICES_ALL);
6863             handler.sendMessage(
6864                     Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
6865         } else {
6866             AudioDeviceInfo[] added_devices =
6867                     calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
6868             AudioDeviceInfo[] removed_devices =
6869                     calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
6870             if (added_devices.length != 0 || removed_devices.length != 0) {
6871                 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
6872                     handler = mDeviceCallbacks.valueAt(i).getHandler();
6873                     if (handler != null) {
6874                         if (removed_devices.length != 0) {
6875                             handler.sendMessage(Message.obtain(handler,
6876                                     MSG_DEVICES_DEVICES_REMOVED,
6877                                     removed_devices));
6878                         }
6879                         if (added_devices.length != 0) {
6880                             handler.sendMessage(Message.obtain(handler,
6881                                     MSG_DEVICES_DEVICES_ADDED,
6882                                     added_devices));
6883                         }
6884                     }
6885                 }
6886             }
6887         }
6888 
6889         mPreviousPorts = current_ports;
6890     }
6891 
6892     /**
6893      * Handles Port list update notifications from the AudioManager
6894      */
6895     private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
6896         static final String TAG = "OnAmPortUpdateListener";
onAudioPortListUpdate(AudioPort[] portList)6897         public void onAudioPortListUpdate(AudioPort[] portList) {
6898             synchronized (mDeviceCallbacks) {
6899                 broadcastDeviceListChange_sync(null);
6900             }
6901         }
6902 
6903         /**
6904          * Callback method called upon audio patch list update.
6905          * Note: We don't do anything with Patches at this time, so ignore this notification.
6906          * @param patchList the updated list of audio patches.
6907          */
onAudioPatchListUpdate(AudioPatch[] patchList)6908         public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
6909 
6910         /**
6911          * Callback method called when the mediaserver dies
6912          */
onServiceDied()6913         public void onServiceDied() {
6914             synchronized (mDeviceCallbacks) {
6915                 broadcastDeviceListChange_sync(null);
6916             }
6917         }
6918     }
6919 
6920 
6921     /**
6922      * @hide
6923      * Abstract class to receive event notification about audioserver process state.
6924      */
6925     @SystemApi
6926     public abstract static class AudioServerStateCallback {
onAudioServerDown()6927         public void onAudioServerDown() { }
onAudioServerUp()6928         public void onAudioServerUp() { }
6929     }
6930 
6931     private Executor mAudioServerStateExec;
6932     private AudioServerStateCallback mAudioServerStateCb;
6933     private final Object mAudioServerStateCbLock = new Object();
6934 
6935     private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
6936             new IAudioServerStateDispatcher.Stub() {
6937         @Override
6938         public void dispatchAudioServerStateChange(boolean state) {
6939             Executor exec;
6940             AudioServerStateCallback cb;
6941 
6942             synchronized (mAudioServerStateCbLock) {
6943                 exec = mAudioServerStateExec;
6944                 cb = mAudioServerStateCb;
6945             }
6946 
6947             if ((exec == null) || (cb == null)) {
6948                 return;
6949             }
6950             if (state) {
6951                 exec.execute(() -> cb.onAudioServerUp());
6952             } else {
6953                 exec.execute(() -> cb.onAudioServerDown());
6954             }
6955         }
6956     };
6957 
6958     /**
6959      * @hide
6960      * Registers a callback for notification of audio server state changes.
6961      * @param executor {@link Executor} to handle the callbacks
6962      * @param stateCallback the callback to receive the audio server state changes
6963      *        To remove the callabck, pass a null reference for both executor and stateCallback.
6964      */
6965     @SystemApi
setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)6966     public void setAudioServerStateCallback(@NonNull Executor executor,
6967             @NonNull AudioServerStateCallback stateCallback) {
6968         if (stateCallback == null) {
6969             throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
6970         }
6971         if (executor == null) {
6972             throw new IllegalArgumentException(
6973                     "Illegal null Executor for the AudioServerStateCallback");
6974         }
6975 
6976         synchronized (mAudioServerStateCbLock) {
6977             if (mAudioServerStateCb != null) {
6978                 throw new IllegalStateException(
6979                     "setAudioServerStateCallback called with already registered callabck");
6980             }
6981             final IAudioService service = getService();
6982             try {
6983                 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
6984             } catch (RemoteException e) {
6985                 throw e.rethrowFromSystemServer();
6986             }
6987             mAudioServerStateExec = executor;
6988             mAudioServerStateCb = stateCallback;
6989         }
6990     }
6991 
6992     /**
6993      * @hide
6994      * Unregisters the callback for notification of audio server state changes.
6995      */
6996     @SystemApi
clearAudioServerStateCallback()6997     public void clearAudioServerStateCallback() {
6998         synchronized (mAudioServerStateCbLock) {
6999             if (mAudioServerStateCb != null) {
7000                 final IAudioService service = getService();
7001                 try {
7002                     service.unregisterAudioServerStateDispatcher(
7003                             mAudioServerStateDispatcher);
7004                 } catch (RemoteException e) {
7005                     throw e.rethrowFromSystemServer();
7006                 }
7007             }
7008             mAudioServerStateExec = null;
7009             mAudioServerStateCb = null;
7010         }
7011     }
7012 
7013     /**
7014      * @hide
7015      * Checks if native audioservice is running or not.
7016      * @return true if native audioservice runs, false otherwise.
7017      */
7018     @SystemApi
isAudioServerRunning()7019     public boolean isAudioServerRunning() {
7020         final IAudioService service = getService();
7021         try {
7022             return service.isAudioServerRunning();
7023         } catch (RemoteException e) {
7024             throw e.rethrowFromSystemServer();
7025         }
7026     }
7027 
7028     /**
7029      * Sets the surround sound mode.
7030      *
7031      * @return true if successful, otherwise false
7032      */
7033     @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)7034     public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7035         try {
7036             return getService().setEncodedSurroundMode(mode);
7037         } catch (RemoteException e) {
7038             throw e.rethrowFromSystemServer();
7039         }
7040     }
7041 
7042     /**
7043      * Gets the surround sound mode.
7044      *
7045      * @return true if successful, otherwise false
7046      */
getEncodedSurroundMode()7047     public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7048         try {
7049             return getService().getEncodedSurroundMode(
7050                     getContext().getApplicationInfo().targetSdkVersion);
7051         } catch (RemoteException e) {
7052             throw e.rethrowFromSystemServer();
7053         }
7054     }
7055 
7056     /**
7057      * @hide
7058      * Returns all surround formats.
7059      * @return a map where the key is a surround format and
7060      * the value indicates the surround format is enabled or not
7061      */
7062     @TestApi
7063     @NonNull
getSurroundFormats()7064     public Map<Integer, Boolean> getSurroundFormats() {
7065         try {
7066             return getService().getSurroundFormats();
7067         } catch (RemoteException e) {
7068             throw e.rethrowFromSystemServer();
7069         }
7070     }
7071 
7072     /**
7073      * Sets and persists a certain surround format as enabled or not.
7074      * <p>
7075      * This API is called by TvSettings surround sound menu when user enables or disables a
7076      * surround sound format. This setting is persisted as global user setting.
7077      * Applications should revert their changes to surround sound settings unless they intend to
7078      * modify the global user settings across all apps. The framework does not auto-revert an
7079      * application's settings after a lifecycle event. Audio focus is not required to apply these
7080      * settings.
7081      *
7082      * @param enabled the required surround format state, true for enabled, false for disabled
7083      * @return true if successful, otherwise false
7084      */
7085     @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)7086     public boolean setSurroundFormatEnabled(
7087             @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
7088         try {
7089             return getService().setSurroundFormatEnabled(audioFormat, enabled);
7090         } catch (RemoteException e) {
7091             throw e.rethrowFromSystemServer();
7092         }
7093     }
7094 
7095     /**
7096      * Gets whether a certain surround format is enabled or not.
7097      * @param audioFormat a surround format
7098      *
7099      * @return whether the required surround format is enabled
7100      */
isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)7101     public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7102         try {
7103             return getService().isSurroundFormatEnabled(audioFormat);
7104         } catch (RemoteException e) {
7105             throw e.rethrowFromSystemServer();
7106         }
7107     }
7108 
7109     /**
7110      * @hide
7111      * Returns all surround formats that are reported by the connected HDMI device.
7112      * The return values are not affected by calling setSurroundFormatEnabled.
7113      *
7114      * @return a list of surround formats
7115      */
7116     @TestApi
7117     @NonNull
getReportedSurroundFormats()7118     public List<Integer> getReportedSurroundFormats() {
7119         try {
7120             return getService().getReportedSurroundFormats();
7121         } catch (RemoteException e) {
7122             throw e.rethrowFromSystemServer();
7123         }
7124     }
7125 
7126     /**
7127      * Return if audio haptic coupled playback is supported or not.
7128      *
7129      * @return whether audio haptic playback supported.
7130      */
isHapticPlaybackSupported()7131     public static boolean isHapticPlaybackSupported() {
7132         return AudioSystem.isHapticPlaybackSupported();
7133     }
7134 
7135     /**
7136      * @hide
7137      * Introspection API to retrieve audio product strategies.
7138      * When implementing {Car|Oem}AudioManager, use this method  to retrieve the collection of
7139      * audio product strategies, which is indexed by a weakly typed index in order to be extended
7140      * by OEM without any needs of AOSP patches.
7141      * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7142      * strategy refered either by its index or human readable string. It will allow clients
7143      * application to start streaming data using these {@link AudioAttributes} on the selected
7144      * device by Audio Policy Engine.
7145      * @return a (possibly zero-length) array of
7146      *         {@see android.media.audiopolicy.AudioProductStrategy} objects.
7147      */
7148     @SystemApi
7149     @NonNull
7150     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
getAudioProductStrategies()7151     public static List<AudioProductStrategy> getAudioProductStrategies() {
7152         final IAudioService service = getService();
7153         try {
7154             return service.getAudioProductStrategies();
7155         } catch (RemoteException e) {
7156             throw e.rethrowFromSystemServer();
7157         }
7158     }
7159 
7160     /**
7161      * @hide
7162      * Introspection API to retrieve audio volume groups.
7163      * When implementing {Car|Oem}AudioManager, use this method  to retrieve the collection of
7164      * audio volume groups.
7165      * @return a (possibly zero-length) List of
7166      *         {@see android.media.audiopolicy.AudioVolumeGroup} objects.
7167      */
7168     @SystemApi
7169     @NonNull
7170     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
getAudioVolumeGroups()7171     public static List<AudioVolumeGroup> getAudioVolumeGroups() {
7172         final IAudioService service = getService();
7173         try {
7174             return service.getAudioVolumeGroups();
7175         } catch (RemoteException e) {
7176             throw e.rethrowFromSystemServer();
7177         }
7178     }
7179 
7180     /**
7181      * @hide
7182      * Callback registered by client to be notified upon volume group change.
7183      */
7184     @SystemApi
7185     public abstract static class VolumeGroupCallback {
7186         /**
7187          * Callback method called upon audio volume group change.
7188          * @param group the group for which the volume has changed
7189          */
onAudioVolumeGroupChanged(int group, int flags)7190         public void onAudioVolumeGroupChanged(int group, int flags) {}
7191     }
7192 
7193    /**
7194     * @hide
7195     * Register an audio volume group change listener.
7196     * @param callback the {@link VolumeGroupCallback} to register
7197     */
7198     @SystemApi
registerVolumeGroupCallback( @onNull Executor executor, @NonNull VolumeGroupCallback callback)7199     public void registerVolumeGroupCallback(
7200             @NonNull Executor executor,
7201             @NonNull VolumeGroupCallback callback) {
7202         Preconditions.checkNotNull(executor, "executor must not be null");
7203         Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7204         sAudioAudioVolumeGroupChangedHandler.init();
7205         // TODO: make use of executor
7206         sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7207     }
7208 
7209    /**
7210     * @hide
7211     * Unregister an audio volume group change listener.
7212     * @param callback the {@link VolumeGroupCallback} to unregister
7213     */
7214     @SystemApi
unregisterVolumeGroupCallback( @onNull VolumeGroupCallback callback)7215     public void unregisterVolumeGroupCallback(
7216             @NonNull VolumeGroupCallback callback) {
7217         Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7218         sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7219     }
7220 
7221     /**
7222      * Return if an asset contains haptic channels or not.
7223      *
7224      * @param context the {@link Context} to resolve the uri.
7225      * @param uri the {@link Uri} of the asset.
7226      * @return true if the assert contains haptic channels.
7227      * @hide
7228      */
hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)7229     public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7230         MediaExtractor extractor = new MediaExtractor();
7231         try {
7232             extractor.setDataSource(context, uri, null);
7233             for (int i = 0; i < extractor.getTrackCount(); i++) {
7234                 MediaFormat format = extractor.getTrackFormat(i);
7235                 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7236                         && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7237                     return true;
7238                 }
7239             }
7240         } catch (IOException e) {
7241             Log.e(TAG, "hasHapticChannels failure:" + e);
7242         }
7243         return false;
7244     }
7245 
7246     /**
7247      * Return if an asset contains haptic channels or not.
7248      *
7249      * @param context the {@link Context} to resolve the uri.
7250      * @param uri the {@link Uri} of the asset.
7251      * @return true if the assert contains haptic channels.
7252      * @hide
7253      */
hasHapticChannels(@ullable Context context, @NonNull Uri uri)7254     public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7255         Objects.requireNonNull(uri);
7256 
7257         if (context != null) {
7258             return hasHapticChannelsImpl(context, uri);
7259         }
7260 
7261         Context cachedContext = sContext.get();
7262         if (cachedContext != null) {
7263             if (DEBUG) {
7264                 Log.d(TAG, "Try to use static context to query if having haptic channels");
7265             }
7266             return hasHapticChannelsImpl(cachedContext, uri);
7267         }
7268 
7269         // Try with audio service context, this may fail to get correct result.
7270         if (DEBUG) {
7271             Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7272         }
7273         try {
7274             return getService().hasHapticChannels(uri);
7275         } catch (RemoteException e) {
7276             throw e.rethrowFromSystemServer();
7277         }
7278     }
7279 
7280     /**
7281      * Set whether or not there is an active RTT call.
7282      * This method should be called by Telecom service.
7283      * @hide
7284      * TODO: make this a @SystemApi
7285      */
setRttEnabled(boolean rttEnabled)7286     public static void setRttEnabled(boolean rttEnabled) {
7287         try {
7288             getService().setRttEnabled(rttEnabled);
7289         } catch (RemoteException e) {
7290             throw e.rethrowFromSystemServer();
7291         }
7292     }
7293 
7294     /**
7295      * Adjusts the volume of the most relevant stream, or the given fallback
7296      * stream.
7297      * <p>
7298      * This method should only be used by applications that replace the
7299      * platform-wide management of audio settings or the main telephony
7300      * application.
7301      * <p>
7302      * This method has no effect if the device implements a fixed volume policy
7303      * as indicated by {@link #isVolumeFixed()}.
7304      * <p>This API checks if the caller has the necessary permissions based on the provided
7305      * component name, uid, and pid values.
7306      * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7307      *
7308      * @param suggestedStreamType The stream type that will be used if there
7309      *         isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7310      *         valid here.
7311      * @param direction The direction to adjust the volume. One of
7312      *         {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7313      *         {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7314      *         {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7315      * @param flags One or more flags.
7316      * @param packageName the package name of client application
7317      * @param uid the uid of client application
7318      * @param pid the pid of client application
7319      * @param targetSdkVersion the target sdk version of client application
7320      * @see #adjustVolume(int, int)
7321      * @see #adjustStreamVolume(int, int, int)
7322      * @see #setStreamVolume(int, int, int)
7323      * @see #isVolumeFixed()
7324      *
7325      * @hide
7326      */
7327     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7328     public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7329             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7330         try {
7331             getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7332                     packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7333         } catch (RemoteException e) {
7334             throw e.rethrowFromSystemServer();
7335         }
7336     }
7337 
7338     /**
7339      * Adjusts the volume of a particular stream by one step in a direction.
7340      * <p>
7341      * This method should only be used by applications that replace the platform-wide
7342      * management of audio settings or the main telephony application.
7343      * <p>This method has no effect if the device implements a fixed volume policy
7344      * as indicated by {@link #isVolumeFixed()}.
7345      * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7346      * unless the app has been granted Do Not Disturb Access.
7347      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7348      * <p>This API checks if the caller has the necessary permissions based on the provided
7349      * component name, uid, and pid values.
7350      * See {@link #adjustStreamVolume(int, int, int)}.
7351      *
7352      * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7353      *         {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7354      *         {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7355      * @param direction The direction to adjust the volume. One of
7356      *         {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7357      *         {@link #ADJUST_SAME}.
7358      * @param flags One or more flags.
7359      * @param packageName the package name of client application
7360      * @param uid the uid of client application
7361      * @param pid the pid of client application
7362      * @param targetSdkVersion the target sdk version of client application
7363      * @see #adjustVolume(int, int)
7364      * @see #setStreamVolume(int, int, int)
7365      * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7366      *         and the caller is not granted notification policy access.
7367      *
7368      * @hide
7369      */
7370     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
adjustStreamVolumeForUid(int streamType, int direction, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7371     public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7372             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7373         try {
7374             getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7375                     pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7376         } catch (RemoteException e) {
7377             throw e.rethrowFromSystemServer();
7378         }
7379     }
7380 
7381     /**
7382      * Sets the volume index for a particular stream.
7383      * <p>This method has no effect if the device implements a fixed volume policy
7384      * as indicated by {@link #isVolumeFixed()}.
7385      * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7386      * the app has been granted Do Not Disturb Access.
7387      * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7388      * <p>This API checks if the caller has the necessary permissions based on the provided
7389      * component name, uid, and pid values.
7390      * See {@link #setStreamVolume(int, int, int)}.
7391      *
7392      * @param streamType The stream whose volume index should be set.
7393      * @param index The volume index to set. See
7394      *         {@link #getStreamMaxVolume(int)} for the largest valid value.
7395      * @param flags One or more flags.
7396      * @param packageName the package name of client application
7397      * @param uid the uid of client application
7398      * @param pid the pid of client application
7399      * @param targetSdkVersion the target sdk version of client application
7400      * @see #getStreamMaxVolume(int)
7401      * @see #getStreamVolume(int)
7402      * @see #isVolumeFixed()
7403      * @throws SecurityException if the volume change triggers a Do Not Disturb change
7404      *         and the caller is not granted notification policy access.
7405      *
7406      * @hide
7407      */
7408     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
setStreamVolumeForUid(int streamType, int index, int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)7409     public void setStreamVolumeForUid(int streamType, int index, int flags,
7410             @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7411         try {
7412             getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7413                     UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7414         } catch (RemoteException e) {
7415             throw e.rethrowFromSystemServer();
7416         }
7417     }
7418 
7419 
7420     /** @hide
7421      * TODO: make this a @SystemApi */
7422     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
setMultiAudioFocusEnabled(boolean enabled)7423     public void setMultiAudioFocusEnabled(boolean enabled) {
7424         try {
7425             getService().setMultiAudioFocusEnabled(enabled);
7426         } catch (RemoteException e) {
7427             throw e.rethrowFromSystemServer();
7428         }
7429     }
7430 
7431 
7432     /**
7433      * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7434      * For more details on Hardware A/V synchronization please refer to
7435      *  <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7436      * media tunneling documentation</a>.
7437      * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7438      * @return the HW A/V sync ID for this audio session (an integer different from 0).
7439      * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7440      */
getAudioHwSyncForSession(int sessionId)7441     public int getAudioHwSyncForSession(int sessionId) {
7442         int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7443         if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7444             throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7445         }
7446         return hwSyncId;
7447     }
7448 
7449     /**
7450      * Selects the audio device that should be used for communication use cases, for instance voice
7451      * or video calls. This method can be used by voice or video chat applications to select a
7452      * different audio device than the one selected by default by the platform.
7453      * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7454      * {@link #getAvailableCommunicationDevices()}.
7455      * The selection is active as long as the requesting application process lives, until
7456      * {@link #clearCommunicationDevice} is called or until the device is disconnected.
7457      * It is therefore important for applications to clear the request when a call ends or the
7458      * the requesting activity or service is stopped or destroyed.
7459      * <p>In case of simultaneous requests by multiple applications the priority is given to the
7460      * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7461      * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7462      * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7463      * telephony application with permission
7464      * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7465      * <p> If the requested devices is not currently available, the request will be rejected and
7466      * the method will return false.
7467      * <p>This API replaces the following deprecated APIs:
7468      * <ul>
7469      *   <li> {@link #startBluetoothSco()}
7470      *   <li> {@link #stopBluetoothSco()}
7471      *   <li> {@link #setSpeakerphoneOn(boolean)}
7472      * </ul>
7473      * <h4>Example</h4>
7474      * <p>The example below shows how to enable and disable speakerphone mode.
7475      * <pre class="prettyprint">
7476      * // Get an AudioManager instance
7477      * AudioManager audioManager = Context.getSystemService(AudioManager.class);
7478      * AudioDeviceInfo speakerDevice = null;
7479      * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7480      * for (AudioDeviceInfo device : devices) {
7481      *     if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7482      *         speakerDevice = device;
7483      *         break;
7484      *     }
7485      * }
7486      * if (speakerDevice != null) {
7487      *     // Turn speakerphone ON.
7488      *     boolean result = audioManager.setCommunicationDevice(speakerDevice);
7489      *     if (!result) {
7490      *         // Handle error.
7491      *     }
7492      *     // Turn speakerphone OFF.
7493      *     audioManager.clearCommunicationDevice();
7494      * }
7495      * </pre>
7496      * @param device the requested audio device.
7497      * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7498      * @throws IllegalArgumentException If an invalid device is specified.
7499      */
setCommunicationDevice(@onNull AudioDeviceInfo device)7500     public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
7501         Objects.requireNonNull(device);
7502         try {
7503             if (device.getId() == 0) {
7504                 throw new IllegalArgumentException("In valid device: " + device);
7505             }
7506             return getService().setCommunicationDevice(mICallBack, device.getId());
7507         } catch (RemoteException e) {
7508             throw e.rethrowFromSystemServer();
7509         }
7510     }
7511 
7512     /**
7513      * Cancels previous communication device selection made with
7514      * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7515      */
clearCommunicationDevice()7516     public void clearCommunicationDevice() {
7517         try {
7518             getService().setCommunicationDevice(mICallBack, 0);
7519         } catch (RemoteException e) {
7520             throw e.rethrowFromSystemServer();
7521         }
7522     }
7523 
7524     /**
7525      * Returns currently selected audio device for communication.
7526      * <p>This API replaces the following deprecated APIs:
7527      * <ul>
7528      *   <li> {@link #isBluetoothScoOn()}
7529      *   <li> {@link #isSpeakerphoneOn()}
7530      * </ul>
7531      * @return an {@link AudioDeviceInfo} indicating which audio device is
7532      * currently selected for communication use cases. Can be null on platforms
7533      * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
7534      * is used.
7535      */
7536     @Nullable
getCommunicationDevice()7537     public AudioDeviceInfo getCommunicationDevice() {
7538         try {
7539             return getDeviceForPortId(
7540                     getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7541         } catch (RemoteException e) {
7542             throw e.rethrowFromSystemServer();
7543         }
7544     }
7545 
7546     /**
7547      * Returns a list of audio devices that can be selected for communication use cases via
7548      * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7549      * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7550      */
7551     @NonNull
getAvailableCommunicationDevices()7552     public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7553         try {
7554             ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7555             int[] portIds = getService().getAvailableCommunicationDeviceIds();
7556             for (int portId : portIds) {
7557                 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7558                 if (device == null) {
7559                     continue;
7560                 }
7561                 devices.add(device);
7562             }
7563             return devices;
7564         } catch (RemoteException e) {
7565             throw e.rethrowFromSystemServer();
7566         }
7567     }
7568 
7569     /**
7570      * @hide
7571      * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7572      * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7573      * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7574      * The method will return null if no device of the provided type is connected.
7575      * If more than one device of the provided type is connected, an object corresponding to the
7576      * first device encountered in the enumeration list will be returned.
7577      * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
7578      *                   object is queried.
7579      * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7580      * @throws IllegalArgumentException If an invalid device type is specified.
7581      */
7582     @TestApi
7583     @Nullable
getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)7584     public static AudioDeviceInfo getDeviceInfoFromType(
7585             @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
7586         return getDeviceInfoFromTypeAndAddress(deviceType, null);
7587     }
7588 
7589         /**
7590      * @hide
7591      * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7592      * address provided.
7593      * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7594      * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7595      * If a null address is provided, the matching will happen on the type only.
7596      * The method will return null if no device of the provided type and address is connected.
7597      * If more than one device of the provided type is connected, an object corresponding to the
7598      * first device encountered in the enumeration list will be returned.
7599      * @param type The device device for which an <code>AudioDeviceInfo</code>
7600      *             object is queried.
7601      * @param address The device address for which an <code>AudioDeviceInfo</code>
7602      *                object is queried or null if requesting match on type only.
7603      * @return An AudioDeviceInfo object or null if no matching device is connected.
7604      * @throws IllegalArgumentException If an invalid device type is specified.
7605      */
7606     @Nullable
getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)7607     public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7608             @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
7609         AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
7610         AudioDeviceInfo deviceForType = null;
7611         for (AudioDeviceInfo device : devices) {
7612             if (device.getType() == type) {
7613                 deviceForType = device;
7614                 if (address == null || address.equals(device.getAddress())) {
7615                     return device;
7616                 }
7617             }
7618         }
7619         return deviceForType;
7620     }
7621 
7622     /**
7623      * Listener registered by client to be notified upon communication audio device change.
7624      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
7625      */
7626     public interface OnCommunicationDeviceChangedListener {
7627         /**
7628          * Callback method called upon communication audio device change.
7629          * @param device the audio device requested for communication use cases.
7630          *               Can be null on platforms not supporting
7631          *               {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
7632          */
onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)7633         void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7634     }
7635 
7636     /**
7637      * Adds a listener for being notified of changes to the communication audio device.
7638      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
7639      * @param executor
7640      * @param listener
7641      */
addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)7642     public void addOnCommunicationDeviceChangedListener(
7643             @NonNull @CallbackExecutor Executor executor,
7644             @NonNull OnCommunicationDeviceChangedListener listener) {
7645         Objects.requireNonNull(executor);
7646         Objects.requireNonNull(listener);
7647         synchronized (mCommDevListenerLock) {
7648             if (hasCommDevListener(listener)) {
7649                 throw new IllegalArgumentException(
7650                         "attempt to call addOnCommunicationDeviceChangedListener() "
7651                                 + "on a previously registered listener");
7652             }
7653             // lazy initialization of the list of strategy-preferred device listener
7654             if (mCommDevListeners == null) {
7655                 mCommDevListeners = new ArrayList<>();
7656             }
7657             final int oldCbCount = mCommDevListeners.size();
7658             mCommDevListeners.add(new CommDevListenerInfo(listener, executor));
7659             if (oldCbCount == 0 && mCommDevListeners.size() > 0) {
7660                 // register binder for callbacks
7661                 if (mCommDevDispatcherStub == null) {
7662                     mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub();
7663                 }
7664                 try {
7665                     getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub);
7666                 } catch (RemoteException e) {
7667                     throw e.rethrowFromSystemServer();
7668                 }
7669             }
7670         }
7671     }
7672 
7673     /**
7674      * Removes a previously added listener of changes to the communication audio device.
7675      * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
7676      * @param listener
7677      */
removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)7678     public void removeOnCommunicationDeviceChangedListener(
7679             @NonNull OnCommunicationDeviceChangedListener listener) {
7680         Objects.requireNonNull(listener);
7681         synchronized (mCommDevListenerLock) {
7682             if (!removeCommDevListener(listener)) {
7683                 throw new IllegalArgumentException(
7684                         "attempt to call removeOnCommunicationDeviceChangedListener() "
7685                                 + "on an unregistered listener");
7686             }
7687             if (mCommDevListeners.size() == 0) {
7688                 // unregister binder for callbacks
7689                 try {
7690                     getService().unregisterCommunicationDeviceDispatcher(
7691                             mCommDevDispatcherStub);
7692                 } catch (RemoteException e) {
7693                     throw e.rethrowFromSystemServer();
7694                 } finally {
7695                     mCommDevDispatcherStub = null;
7696                     mCommDevListeners = null;
7697                 }
7698             }
7699         }
7700     }
7701 
7702     private final Object mCommDevListenerLock = new Object();
7703     /**
7704      * List of listeners for preferred device for strategy and their associated Executor.
7705      * List is lazy-initialized on first registration
7706      */
7707     @GuardedBy("mCommDevListenerLock")
7708     private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners;
7709 
7710     private static class CommDevListenerInfo {
7711         final @NonNull OnCommunicationDeviceChangedListener mListener;
7712         final @NonNull Executor mExecutor;
7713 
CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe)7714         CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) {
7715             mListener = listener;
7716             mExecutor = exe;
7717         }
7718     }
7719 
7720     @GuardedBy("mCommDevListenerLock")
7721     private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
7722 
7723     private final class CommunicationDeviceDispatcherStub
7724             extends ICommunicationDeviceDispatcher.Stub {
7725 
7726         @Override
dispatchCommunicationDeviceChanged(int portId)7727         public void dispatchCommunicationDeviceChanged(int portId) {
7728             // make a shallow copy of listeners so callback is not executed under lock
7729             final ArrayList<CommDevListenerInfo> commDevListeners;
7730             synchronized (mCommDevListenerLock) {
7731                 if (mCommDevListeners == null || mCommDevListeners.size() == 0) {
7732                     return;
7733                 }
7734                 commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone();
7735             }
7736             AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7737             final long ident = Binder.clearCallingIdentity();
7738             try {
7739                 for (CommDevListenerInfo info : commDevListeners) {
7740                     info.mExecutor.execute(() ->
7741                             info.mListener.onCommunicationDeviceChanged(device));
7742                 }
7743             } finally {
7744                 Binder.restoreCallingIdentity(ident);
7745             }
7746         }
7747     }
7748 
7749     @GuardedBy("mCommDevListenerLock")
getCommDevListenerInfo( OnCommunicationDeviceChangedListener listener)7750     private @Nullable CommDevListenerInfo getCommDevListenerInfo(
7751             OnCommunicationDeviceChangedListener listener) {
7752         if (mCommDevListeners == null) {
7753             return null;
7754         }
7755         for (CommDevListenerInfo info : mCommDevListeners) {
7756             if (info.mListener == listener) {
7757                 return info;
7758             }
7759         }
7760         return null;
7761     }
7762 
7763     @GuardedBy("mCommDevListenerLock")
hasCommDevListener(OnCommunicationDeviceChangedListener listener)7764     private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) {
7765         return getCommDevListenerInfo(listener) != null;
7766     }
7767 
7768     @GuardedBy("mCommDevListenerLock")
7769     /**
7770      * @return true if the listener was removed from the list
7771      */
removeCommDevListener(OnCommunicationDeviceChangedListener listener)7772     private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) {
7773         final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener);
7774         if (infoToRemove != null) {
7775             mCommDevListeners.remove(infoToRemove);
7776             return true;
7777         }
7778         return false;
7779     }
7780 
7781     //---------------------------------------------------------
7782     // Inner classes
7783     //--------------------
7784     /**
7785      * Helper class to handle the forwarding of native events to the appropriate listener
7786      * (potentially) handled in a different thread.
7787      */
7788     private class NativeEventHandlerDelegate {
7789         private final Handler mHandler;
7790 
NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)7791         NativeEventHandlerDelegate(final AudioDeviceCallback callback,
7792                                    Handler handler) {
7793             // find the looper for our new event handler
7794             Looper looper;
7795             if (handler != null) {
7796                 looper = handler.getLooper();
7797             } else {
7798                 // no given handler, use the looper the addListener call was called in
7799                 looper = Looper.getMainLooper();
7800             }
7801 
7802             // construct the event handler with this looper
7803             if (looper != null) {
7804                 // implement the event handler delegate
7805                 mHandler = new Handler(looper) {
7806                     @Override
7807                     public void handleMessage(Message msg) {
7808                         switch(msg.what) {
7809                         case MSG_DEVICES_CALLBACK_REGISTERED:
7810                         case MSG_DEVICES_DEVICES_ADDED:
7811                             if (callback != null) {
7812                                 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
7813                             }
7814                             break;
7815 
7816                         case MSG_DEVICES_DEVICES_REMOVED:
7817                             if (callback != null) {
7818                                 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
7819                             }
7820                            break;
7821 
7822                         default:
7823                             Log.e(TAG, "Unknown native event type: " + msg.what);
7824                             break;
7825                         }
7826                     }
7827                 };
7828             } else {
7829                 mHandler = null;
7830             }
7831         }
7832 
getHandler()7833         Handler getHandler() {
7834             return mHandler;
7835         }
7836     }
7837 }
7838