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