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