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