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