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