AudioService.java revision 1a7700793db3c7b60d5e090ee026a1bcfeff91d8
1/*
2 * Copyright (C) 2006 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
17package com.android.server.audio;
18
19import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
20import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
23
24import android.app.ActivityManager;
25import android.app.ActivityManagerNative;
26import android.app.AppOpsManager;
27import android.app.KeyguardManager;
28import android.bluetooth.BluetoothA2dp;
29import android.bluetooth.BluetoothAdapter;
30import android.bluetooth.BluetoothClass;
31import android.bluetooth.BluetoothDevice;
32import android.bluetooth.BluetoothHeadset;
33import android.bluetooth.BluetoothProfile;
34import android.content.BroadcastReceiver;
35import android.content.ComponentName;
36import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
39import android.content.IntentFilter;
40import android.content.pm.PackageManager;
41import android.content.res.Configuration;
42import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
44import android.database.ContentObserver;
45import android.hardware.hdmi.HdmiControlManager;
46import android.hardware.hdmi.HdmiPlaybackClient;
47import android.hardware.hdmi.HdmiTvClient;
48import android.hardware.usb.UsbManager;
49import android.media.AudioAttributes;
50import android.media.AudioDevicePort;
51import android.media.AudioSystem;
52import android.media.AudioFormat;
53import android.media.AudioManager;
54import android.media.AudioManagerInternal;
55import android.media.AudioPort;
56import android.media.AudioRoutesInfo;
57import android.media.IAudioFocusDispatcher;
58import android.media.IAudioRoutesObserver;
59import android.media.IAudioService;
60import android.media.IRemoteControlDisplay;
61import android.media.IRingtonePlayer;
62import android.media.IVolumeController;
63import android.media.MediaPlayer;
64import android.media.SoundPool;
65import android.media.VolumePolicy;
66import android.media.MediaPlayer.OnCompletionListener;
67import android.media.MediaPlayer.OnErrorListener;
68import android.media.audiopolicy.AudioPolicy;
69import android.media.audiopolicy.AudioPolicyConfig;
70import android.media.audiopolicy.IAudioPolicyCallback;
71import android.os.Binder;
72import android.os.Build;
73import android.os.Environment;
74import android.os.Handler;
75import android.os.IBinder;
76import android.os.Looper;
77import android.os.Message;
78import android.os.PowerManager;
79import android.os.RemoteCallbackList;
80import android.os.RemoteException;
81import android.os.SystemClock;
82import android.os.SystemProperties;
83import android.os.UserHandle;
84import android.os.Vibrator;
85import android.provider.Settings;
86import android.provider.Settings.System;
87import android.telecom.TelecomManager;
88import android.text.TextUtils;
89import android.util.Log;
90import android.util.MathUtils;
91import android.util.Slog;
92import android.util.SparseIntArray;
93import android.view.KeyEvent;
94import android.view.OrientationEventListener;
95import android.view.Surface;
96import android.view.WindowManager;
97import android.view.accessibility.AccessibilityManager;
98
99import com.android.internal.util.XmlUtils;
100import com.android.server.EventLogTags;
101import com.android.server.LocalServices;
102
103import org.xmlpull.v1.XmlPullParserException;
104
105import java.io.FileDescriptor;
106import java.io.IOException;
107import java.io.PrintWriter;
108import java.lang.reflect.Field;
109import java.util.ArrayList;
110import java.util.HashMap;
111import java.util.Iterator;
112import java.util.List;
113import java.util.Map;
114import java.util.NoSuchElementException;
115import java.util.Objects;
116import java.util.Set;
117
118/**
119 * The implementation of the volume manager service.
120 * <p>
121 * This implementation focuses on delivering a responsive UI. Most methods are
122 * asynchronous to external calls. For example, the task of setting a volume
123 * will update our internal state, but in a separate thread will set the system
124 * volume and later persist to the database. Similarly, setting the ringer mode
125 * will update the state and broadcast a change and in a separate thread later
126 * persist the ringer mode.
127 *
128 * @hide
129 */
130public class AudioService extends IAudioService.Stub {
131
132    private static final String TAG = "AudioService";
133
134    /** Debug audio mode */
135    protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
136
137    /** Debug audio policy feature */
138    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
139
140    /** Debug volumes */
141    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
142
143    /** debug calls to devices APIs */
144    protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
145
146    /** How long to delay before persisting a change in volume/ringer mode. */
147    private static final int PERSIST_DELAY = 500;
148
149    /** How long to delay after a volume down event before unmuting a stream */
150    private static final int UNMUTE_STREAM_DELAY = 350;
151
152    /**
153     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
154     */
155    private static final int FLAG_ADJUST_VOLUME = 1;
156
157    private final Context mContext;
158    private final ContentResolver mContentResolver;
159    private final AppOpsManager mAppOps;
160
161    // the platform type affects volume and silent mode behavior
162    private final int mPlatformType;
163
164    private boolean isPlatformVoice() {
165        return mPlatformType == AudioSystem.PLATFORM_VOICE;
166    }
167
168    private boolean isPlatformTelevision() {
169        return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
170    }
171
172    /** The controller for the volume UI. */
173    private final VolumeController mVolumeController = new VolumeController();
174    private final ControllerService mControllerService = new ControllerService();
175
176    // sendMsg() flags
177    /** If the msg is already queued, replace it with this one. */
178    private static final int SENDMSG_REPLACE = 0;
179    /** If the msg is already queued, ignore this one and leave the old. */
180    private static final int SENDMSG_NOOP = 1;
181    /** If the msg is already queued, queue this one and leave the old. */
182    private static final int SENDMSG_QUEUE = 2;
183
184    // AudioHandler messages
185    private static final int MSG_SET_DEVICE_VOLUME = 0;
186    private static final int MSG_PERSIST_VOLUME = 1;
187    private static final int MSG_PERSIST_RINGER_MODE = 3;
188    private static final int MSG_MEDIA_SERVER_DIED = 4;
189    private static final int MSG_PLAY_SOUND_EFFECT = 5;
190    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
191    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
192    private static final int MSG_SET_FORCE_USE = 8;
193    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
194    private static final int MSG_SET_ALL_VOLUMES = 10;
195    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
196    private static final int MSG_REPORT_NEW_ROUTES = 12;
197    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
198    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
199    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
200    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
201    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
202    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
203    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
204    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
205    private static final int MSG_SYSTEM_READY = 21;
206    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
207    private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
208    private static final int MSG_UNMUTE_STREAM = 24;
209    // start of messages handled under wakelock
210    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
211    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
212    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
213    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
214    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
215    // end of messages handled under wakelock
216
217    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
218    // Timeout for connection to bluetooth headset service
219    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
220
221    /** @see AudioSystemThread */
222    private AudioSystemThread mAudioSystemThread;
223    /** @see AudioHandler */
224    private AudioHandler mAudioHandler;
225    /** @see VolumeStreamState */
226    private VolumeStreamState[] mStreamStates;
227    private SettingsObserver mSettingsObserver;
228
229    private int mMode = AudioSystem.MODE_NORMAL;
230    // protects mRingerMode
231    private final Object mSettingsLock = new Object();
232
233    private SoundPool mSoundPool;
234    private final Object mSoundEffectsLock = new Object();
235    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
236
237    // Maximum volume adjust steps allowed in a single batch call.
238    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
239
240    /* Sound effect file names  */
241    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
242    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
243
244    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
245     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
246     * uses soundpool (second column) */
247    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
248
249   /** Maximum volume index values for audio streams */
250    private static int[] MAX_STREAM_VOLUME = new int[] {
251        5,  // STREAM_VOICE_CALL
252        7,  // STREAM_SYSTEM
253        7,  // STREAM_RING
254        15, // STREAM_MUSIC
255        7,  // STREAM_ALARM
256        7,  // STREAM_NOTIFICATION
257        15, // STREAM_BLUETOOTH_SCO
258        7,  // STREAM_SYSTEM_ENFORCED
259        15, // STREAM_DTMF
260        15  // STREAM_TTS
261    };
262
263    /** Minimum volume index values for audio streams */
264    private static int[] MIN_STREAM_VOLUME = new int[] {
265        1,  // STREAM_VOICE_CALL
266        0,  // STREAM_SYSTEM
267        0,  // STREAM_RING
268        0,  // STREAM_MUSIC
269        0,  // STREAM_ALARM
270        0,  // STREAM_NOTIFICATION
271        1,  // STREAM_BLUETOOTH_SCO
272        0,  // STREAM_SYSTEM_ENFORCED
273        0,  // STREAM_DTMF
274        0   // STREAM_TTS
275    };
276
277    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
278     * of another stream: This avoids multiplying the volume settings for hidden
279     * stream types that follow other stream behavior for volume settings
280     * NOTE: do not create loops in aliases!
281     * Some streams alias to different streams according to device category (phone or tablet) or
282     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
283     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
284     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
285     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
286    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
287        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
288        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
289        AudioSystem.STREAM_RING,            // STREAM_RING
290        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
291        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
292        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
293        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
294        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
295        AudioSystem.STREAM_RING,            // STREAM_DTMF
296        AudioSystem.STREAM_MUSIC            // STREAM_TTS
297    };
298    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
299        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
300        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
301        AudioSystem.STREAM_MUSIC,       // STREAM_RING
302        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
303        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
304        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
305        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
306        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
307        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
308        AudioSystem.STREAM_MUSIC        // STREAM_TTS
309    };
310    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
311        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
312        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
313        AudioSystem.STREAM_RING,            // STREAM_RING
314        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
315        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
316        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
317        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
318        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
319        AudioSystem.STREAM_RING,            // STREAM_DTMF
320        AudioSystem.STREAM_MUSIC            // STREAM_TTS
321    };
322    private int[] mStreamVolumeAlias;
323
324    /**
325     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
326     * after mapping through mStreamVolumeAlias.
327     */
328    private static final int[] STREAM_VOLUME_OPS = new int[] {
329        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
330        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
331        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
332        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
333        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
334        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
335        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
336        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
337        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
338        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
339    };
340
341    private final boolean mUseFixedVolume;
342
343    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
344        public void onError(int error) {
345            switch (error) {
346            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
347                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
348                        SENDMSG_NOOP, 0, 0, null, 0);
349                break;
350            default:
351                break;
352            }
353        }
354    };
355
356    /**
357     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
358     * {@link AudioManager#RINGER_MODE_SILENT}, or
359     * {@link AudioManager#RINGER_MODE_VIBRATE}.
360     */
361    // protected by mSettingsLock
362    private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
363    private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)
364
365    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
366    private int mRingerModeAffectedStreams = 0;
367
368    // Streams currently muted by ringer mode
369    private int mRingerModeMutedStreams;
370
371    /** Streams that can be muted. Do not resolve to aliases when checking.
372     * @see System#MUTE_STREAMS_AFFECTED */
373    private int mMuteAffectedStreams;
374
375    /**
376     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
377     * mVibrateSetting is just maintained during deprecation period but vibration policy is
378     * now only controlled by mHasVibrator and mRingerMode
379     */
380    private int mVibrateSetting;
381
382    // Is there a vibrator
383    private final boolean mHasVibrator;
384
385    // Broadcast receiver for device connections intent broadcasts
386    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
387
388    // Devices currently connected
389    // Use makeDeviceListKey() to make a unique key for this list.
390    private class DeviceListSpec {
391        int mDeviceType;
392        String mDeviceName;
393        String mDeviceAddress;
394
395        public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
396            mDeviceType = deviceType;
397            mDeviceName = deviceName;
398            mDeviceAddress = deviceAddress;
399        }
400
401        public String toString() {
402            return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
403                    + " address:" + mDeviceAddress + "]";
404        }
405    }
406
407    // Generate a unique key for the mConnectedDevices List by composing the device "type"
408    // and the "address" associated with a specific instance of that device type
409    private String makeDeviceListKey(int device, String deviceAddress) {
410        return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
411    }
412
413    private final HashMap<String, DeviceListSpec> mConnectedDevices =
414            new HashMap<String, DeviceListSpec>();
415
416    // Forced device usage for communications
417    private int mForcedUseForComm;
418
419    // List of binder death handlers for setMode() client processes.
420    // The last process to have called setMode() is at the top of the list.
421    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
422
423    // List of clients having issued a SCO start request
424    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
425
426    // BluetoothHeadset API to control SCO connection
427    private BluetoothHeadset mBluetoothHeadset;
428
429    // Bluetooth headset device
430    private BluetoothDevice mBluetoothHeadsetDevice;
431
432    // Indicate if SCO audio connection is currently active and if the initiator is
433    // audio service (internal) or bluetooth headset (external)
434    private int mScoAudioState;
435    // SCO audio state is not active
436    private static final int SCO_STATE_INACTIVE = 0;
437    // SCO audio activation request waiting for headset service to connect
438    private static final int SCO_STATE_ACTIVATE_REQ = 1;
439    // SCO audio state is active or starting due to a request from AudioManager API
440    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
441    // SCO audio deactivation request waiting for headset service to connect
442    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
443
444    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
445    // in call audio)
446    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
447    // Deactivation request for all SCO connections (initiated by audio mode change)
448    // waiting for headset service to connect
449    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
450
451    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
452    // originated from an app targeting an API version before JB MR2 and raw audio after that.
453    private int mScoAudioMode;
454    // SCO audio mode is undefined
455    private static final int SCO_MODE_UNDEFINED = -1;
456    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
457    private static final int SCO_MODE_VIRTUAL_CALL = 0;
458    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
459    private static final int SCO_MODE_RAW = 1;
460    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
461    private static final int SCO_MODE_VR = 2;
462
463    private static final int SCO_MODE_MAX = 2;
464
465    // Current connection state indicated by bluetooth headset
466    private int mScoConnectionState;
467
468    // true if boot sequence has been completed
469    private boolean mSystemReady;
470    // listener for SoundPool sample load completion indication
471    private SoundPoolCallback mSoundPoolCallBack;
472    // thread for SoundPool listener
473    private SoundPoolListenerThread mSoundPoolListenerThread;
474    // message looper for SoundPool listener
475    private Looper mSoundPoolLooper = null;
476    // volume applied to sound played with playSoundEffect()
477    private static int sSoundEffectVolumeDb;
478    // previous volume adjustment direction received by checkForRingerModeChange()
479    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
480    // Keyguard manager proxy
481    private KeyguardManager mKeyguardManager;
482    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
483    // is controlled by Vol keys.
484    private int  mVolumeControlStream = -1;
485    private final Object mForceControlStreamLock = new Object();
486    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
487    // server process so in theory it is not necessary to monitor the client death.
488    // However it is good to be ready for future evolutions.
489    private ForceControlStreamClient mForceControlStreamClient = null;
490    // Used to play ringtones outside system_server
491    private volatile IRingtonePlayer mRingtonePlayer;
492
493    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
494    private int mDeviceRotation = Surface.ROTATION_0;
495
496    // Request to override default use of A2DP for media.
497    private boolean mBluetoothA2dpEnabled;
498    private final Object mBluetoothA2dpEnabledLock = new Object();
499
500    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
501    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
502    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
503            = new RemoteCallbackList<IAudioRoutesObserver>();
504
505    // Devices for which the volume is fixed and VolumePanel slider should be disabled
506    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
507            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
508            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
509            AudioSystem.DEVICE_OUT_HDMI_ARC |
510            AudioSystem.DEVICE_OUT_SPDIF |
511            AudioSystem.DEVICE_OUT_AUX_LINE;
512    int mFullVolumeDevices = 0;
513
514    // TODO merge orientation and rotation
515    private final boolean mMonitorOrientation;
516    private final boolean mMonitorRotation;
517
518    private boolean mDockAudioMediaEnabled = true;
519
520    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
521
522    // Used when safe volume warning message display is requested by setStreamVolume(). In this
523    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
524    // and used later when/if disableSafeMediaVolume() is called.
525    private StreamVolumeCommand mPendingVolumeCommand;
526
527    private PowerManager.WakeLock mAudioEventWakeLock;
528
529    private final MediaFocusControl mMediaFocusControl;
530
531    // Reference to BluetoothA2dp to query for AbsoluteVolume.
532    private BluetoothA2dp mA2dp;
533    // lock always taken synchronized on mConnectedDevices
534    private final Object mA2dpAvrcpLock = new Object();
535    // If absolute volume is supported in AVRCP device
536    private boolean mAvrcpAbsVolSupported = false;
537
538    private AudioOrientationEventListener mOrientationListener;
539
540    private static Long mLastDeviceConnectMsgTime = new Long(0);
541
542    private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
543    private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
544    private long mLoweredFromNormalToVibrateTime;
545
546    // Intent "extra" data keys.
547    public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
548    public static final String CONNECT_INTENT_KEY_STATE = "state";
549    public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
550    public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
551    public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
552    public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
553    public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
554
555    // Defines the format for the connection "address" for ALSA devices
556    public static String makeAlsaAddressString(int card, int device) {
557        return "card=" + card + ";device=" + device + ";";
558    }
559
560    private final String DEVICE_NAME_A2DP = "a2dp-device";
561
562    ///////////////////////////////////////////////////////////////////////////
563    // Construction
564    ///////////////////////////////////////////////////////////////////////////
565
566    /** @hide */
567    public AudioService(Context context) {
568        mContext = context;
569        mContentResolver = context.getContentResolver();
570        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
571
572        mPlatformType = AudioSystem.getPlatformType(context);
573
574        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
575        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
576
577        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
578        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
579
580        // Initialize volume
581        int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
582                MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
583        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
584            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
585            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
586        }
587        maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
588                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
589        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
590            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
591            AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
592        }
593
594        sSoundEffectVolumeDb = context.getResources().getInteger(
595                com.android.internal.R.integer.config_soundEffectVolumeDb);
596
597        mForcedUseForComm = AudioSystem.FORCE_NONE;
598
599        createAudioSystemThread();
600
601        AudioSystem.setErrorCallback(mAudioSystemCallback);
602
603        boolean cameraSoundForced = readCameraSoundForced();
604        mCameraSoundForced = new Boolean(cameraSoundForced);
605        sendMsg(mAudioHandler,
606                MSG_SET_FORCE_USE,
607                SENDMSG_QUEUE,
608                AudioSystem.FOR_SYSTEM,
609                cameraSoundForced ?
610                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
611                null,
612                0);
613
614        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
615                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
616                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
617        // The default safe volume index read here will be replaced by the actual value when
618        // the mcc is read by onConfigureSafeVolume()
619        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
620                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
621
622        mUseFixedVolume = mContext.getResources().getBoolean(
623                com.android.internal.R.bool.config_useFixedVolume);
624
625        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
626        // array initialized by updateStreamVolumeAlias()
627        updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
628        readPersistedSettings();
629        mSettingsObserver = new SettingsObserver();
630        createStreamStates();
631
632        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
633                mContext, mVolumeController, this);
634
635        readAndSetLowRamDevice();
636
637        // Call setRingerModeInt() to apply correct mute
638        // state on streams affected by ringer mode.
639        mRingerModeMutedStreams = 0;
640        setRingerModeInt(getRingerModeInternal(), false);
641
642        // Register for device connection intent broadcasts.
643        IntentFilter intentFilter =
644                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
645        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
646        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
647        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
648        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
649        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
650        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
651
652        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
653        // TODO merge orientation and rotation
654        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
655        if (mMonitorOrientation) {
656            Log.v(TAG, "monitoring device orientation");
657            // initialize orientation in AudioSystem
658            setOrientationForAudioSystem();
659        }
660        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
661        if (mMonitorRotation) {
662            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
663                    .getDefaultDisplay().getRotation();
664            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
665
666            mOrientationListener = new AudioOrientationEventListener(mContext);
667            mOrientationListener.enable();
668
669            // initialize rotation in AudioSystem
670            setRotationForAudioSystem();
671        }
672
673        context.registerReceiver(mReceiver, intentFilter);
674
675        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
676    }
677
678    public void systemReady() {
679        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
680                0, 0, null, 0);
681    }
682
683    public void onSystemReady() {
684        mSystemReady = true;
685        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
686                0, 0, null, 0);
687
688        mKeyguardManager =
689                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
690        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
691        resetBluetoothSco();
692        getBluetoothHeadset();
693        //FIXME: this is to maintain compatibility with deprecated intent
694        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
695        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
696        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
697                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
698        sendStickyBroadcastToAll(newIntent);
699
700        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
701        if (adapter != null) {
702            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
703                                    BluetoothProfile.A2DP);
704        }
705
706        mHdmiManager =
707                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
708        if (mHdmiManager != null) {
709            synchronized (mHdmiManager) {
710                mHdmiTvClient = mHdmiManager.getTvClient();
711                if (mHdmiTvClient != null) {
712                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
713                }
714                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
715                mHdmiCecSink = false;
716            }
717        }
718
719        sendMsg(mAudioHandler,
720                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
721                SENDMSG_REPLACE,
722                0,
723                0,
724                TAG,
725                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
726
727        StreamOverride.init(mContext);
728        mControllerService.init();
729    }
730
731    private void createAudioSystemThread() {
732        mAudioSystemThread = new AudioSystemThread();
733        mAudioSystemThread.start();
734        waitForAudioHandlerCreation();
735    }
736
737    /** Waits for the volume handler to be created by the other thread. */
738    private void waitForAudioHandlerCreation() {
739        synchronized(this) {
740            while (mAudioHandler == null) {
741                try {
742                    // Wait for mAudioHandler to be set by the other thread
743                    wait();
744                } catch (InterruptedException e) {
745                    Log.e(TAG, "Interrupted while waiting on volume handler.");
746                }
747            }
748        }
749    }
750
751    private void checkAllAliasStreamVolumes() {
752        synchronized (VolumeStreamState.class) {
753            int numStreamTypes = AudioSystem.getNumStreamTypes();
754            for (int streamType = 0; streamType < numStreamTypes; streamType++) {
755                if (streamType != mStreamVolumeAlias[streamType]) {
756                    mStreamStates[streamType].
757                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
758                                            TAG);
759                }
760                // apply stream volume
761                if (!mStreamStates[streamType].mIsMuted) {
762                    mStreamStates[streamType].applyAllVolumes();
763                }
764            }
765        }
766    }
767
768    private void checkAllFixedVolumeDevices()
769    {
770        int numStreamTypes = AudioSystem.getNumStreamTypes();
771        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
772            mStreamStates[streamType].checkFixedVolumeDevices();
773        }
774    }
775
776    private void checkAllFixedVolumeDevices(int streamType) {
777        mStreamStates[streamType].checkFixedVolumeDevices();
778    }
779
780    private void checkMuteAffectedStreams() {
781        // any stream with a min level > 0 is not muteable by definition
782        for (int i = 0; i < mStreamStates.length; i++) {
783            final VolumeStreamState vss = mStreamStates[i];
784            if (vss.mIndexMin > 0) {
785                mMuteAffectedStreams &= ~(1 << vss.mStreamType);
786            }
787        }
788    }
789
790    private void createStreamStates() {
791        int numStreamTypes = AudioSystem.getNumStreamTypes();
792        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
793
794        for (int i = 0; i < numStreamTypes; i++) {
795            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
796        }
797
798        checkAllFixedVolumeDevices();
799        checkAllAliasStreamVolumes();
800        checkMuteAffectedStreams();
801    }
802
803    private void dumpStreamStates(PrintWriter pw) {
804        pw.println("\nStream volumes (device: index)");
805        int numStreamTypes = AudioSystem.getNumStreamTypes();
806        for (int i = 0; i < numStreamTypes; i++) {
807            pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
808            mStreamStates[i].dump(pw);
809            pw.println("");
810        }
811        pw.print("\n- mute affected streams = 0x");
812        pw.println(Integer.toHexString(mMuteAffectedStreams));
813    }
814
815    private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
816        int dtmfStreamAlias;
817
818        switch (mPlatformType) {
819        case AudioSystem.PLATFORM_VOICE:
820            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
821            dtmfStreamAlias = AudioSystem.STREAM_RING;
822            break;
823        case AudioSystem.PLATFORM_TELEVISION:
824            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
825            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
826            break;
827        default:
828            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
829            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
830        }
831
832        if (isPlatformTelevision()) {
833            mRingerModeAffectedStreams = 0;
834        } else {
835            if (isInCommunication()) {
836                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
837                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
838            } else {
839                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
840            }
841        }
842
843        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
844        if (updateVolumes) {
845            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
846                    caller);
847            // apply stream mute states according to new value of mRingerModeAffectedStreams
848            setRingerModeInt(getRingerModeInternal(), false);
849            sendMsg(mAudioHandler,
850                    MSG_SET_ALL_VOLUMES,
851                    SENDMSG_QUEUE,
852                    0,
853                    0,
854                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
855        }
856    }
857
858    private void readDockAudioSettings(ContentResolver cr)
859    {
860        mDockAudioMediaEnabled = Settings.Global.getInt(
861                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
862
863        sendMsg(mAudioHandler,
864                MSG_SET_FORCE_USE,
865                SENDMSG_QUEUE,
866                AudioSystem.FOR_DOCK,
867                mDockAudioMediaEnabled ?
868                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
869                null,
870                0);
871    }
872
873    private void readPersistedSettings() {
874        final ContentResolver cr = mContentResolver;
875
876        int ringerModeFromSettings =
877                Settings.Global.getInt(
878                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
879        int ringerMode = ringerModeFromSettings;
880        // sanity check in case the settings are restored from a device with incompatible
881        // ringer modes
882        if (!isValidRingerMode(ringerMode)) {
883            ringerMode = AudioManager.RINGER_MODE_NORMAL;
884        }
885        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
886            ringerMode = AudioManager.RINGER_MODE_SILENT;
887        }
888        if (ringerMode != ringerModeFromSettings) {
889            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
890        }
891        if (mUseFixedVolume || isPlatformTelevision()) {
892            ringerMode = AudioManager.RINGER_MODE_NORMAL;
893        }
894        synchronized(mSettingsLock) {
895            mRingerMode = ringerMode;
896            if (mRingerModeExternal == -1) {
897                mRingerModeExternal = mRingerMode;
898            }
899
900            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
901            // are still needed while setVibrateSetting() and getVibrateSetting() are being
902            // deprecated.
903            mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
904                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
905                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
906                                                            : AudioManager.VIBRATE_SETTING_OFF);
907            mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
908                                            AudioManager.VIBRATE_TYPE_RINGER,
909                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
910                                                            : AudioManager.VIBRATE_SETTING_OFF);
911
912            updateRingerModeAffectedStreams();
913            readDockAudioSettings(cr);
914        }
915
916        mMuteAffectedStreams = System.getIntForUser(cr,
917                System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
918                UserHandle.USER_CURRENT);
919
920        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
921                0, UserHandle.USER_CURRENT) == 1;
922        if (mUseFixedVolume) {
923            masterMute = false;
924            AudioSystem.setMasterVolume(1.0f);
925        }
926        AudioSystem.setMasterMute(masterMute);
927        broadcastMasterMuteStatus(masterMute);
928
929        boolean microphoneMute =
930                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
931        AudioSystem.muteMicrophone(microphoneMute);
932
933        // Each stream will read its own persisted settings
934
935        // Broadcast the sticky intents
936        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
937        broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
938
939        // Broadcast vibrate settings
940        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
941        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
942
943        // Load settings for the volume controller
944        mVolumeController.loadSettings(cr);
945    }
946
947    private int rescaleIndex(int index, int srcStream, int dstStream) {
948        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
949    }
950
951    private class AudioOrientationEventListener
952            extends OrientationEventListener {
953        public AudioOrientationEventListener(Context context) {
954            super(context);
955        }
956
957        @Override
958        public void onOrientationChanged(int orientation) {
959            //Even though we're responding to phone orientation events,
960            //use display rotation so audio stays in sync with video/dialogs
961            int newRotation = ((WindowManager) mContext.getSystemService(
962                    Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
963            if (newRotation != mDeviceRotation) {
964                mDeviceRotation = newRotation;
965                setRotationForAudioSystem();
966            }
967        }
968    }
969
970    ///////////////////////////////////////////////////////////////////////////
971    // IPC methods
972    ///////////////////////////////////////////////////////////////////////////
973    /** @see AudioManager#adjustVolume(int, int) */
974    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
975            String callingPackage, String caller) {
976        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
977                caller, Binder.getCallingUid());
978    }
979
980    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
981            String callingPackage, String caller, int uid) {
982        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
983                + ", flags=" + flags + ", caller=" + caller);
984        int streamType;
985        boolean isMute = isMuteAdjust(direction);
986        if (mVolumeControlStream != -1) {
987            streamType = mVolumeControlStream;
988        } else {
989            streamType = getActiveStreamType(suggestedStreamType);
990        }
991        final int resolvedStream = mStreamVolumeAlias[streamType];
992
993        // Play sounds on STREAM_RING only.
994        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
995                resolvedStream != AudioSystem.STREAM_RING) {
996            flags &= ~AudioManager.FLAG_PLAY_SOUND;
997        }
998
999        // For notifications/ring, show the ui before making any adjustments
1000        // Don't suppress mute/unmute requests
1001        if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
1002            direction = 0;
1003            flags &= ~AudioManager.FLAG_PLAY_SOUND;
1004            flags &= ~AudioManager.FLAG_VIBRATE;
1005            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1006        }
1007
1008        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
1009    }
1010
1011    /** @see AudioManager#adjustStreamVolume(int, int, int) */
1012    public void adjustStreamVolume(int streamType, int direction, int flags,
1013            String callingPackage) {
1014        adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1015                Binder.getCallingUid());
1016    }
1017
1018    private void adjustStreamVolume(int streamType, int direction, int flags,
1019            String callingPackage, String caller, int uid) {
1020        if (mUseFixedVolume) {
1021            return;
1022        }
1023        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1024                + ", flags=" + flags + ", caller=" + caller);
1025
1026        ensureValidDirection(direction);
1027        ensureValidStreamType(streamType);
1028
1029        boolean isMuteAdjust = isMuteAdjust(direction);
1030
1031        if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1032            return;
1033        }
1034
1035        // use stream type alias here so that streams with same alias have the same behavior,
1036        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1037        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
1038        int streamTypeAlias = mStreamVolumeAlias[streamType];
1039
1040        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1041
1042        final int device = getDeviceForStream(streamTypeAlias);
1043
1044        int aliasIndex = streamState.getIndex(device);
1045        boolean adjustVolume = true;
1046        int step;
1047
1048        // skip a2dp absolute volume control request when the device
1049        // is not an a2dp device
1050        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1051            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1052            return;
1053        }
1054
1055        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1056                != AppOpsManager.MODE_ALLOWED) {
1057            return;
1058        }
1059
1060        // reset any pending volume command
1061        synchronized (mSafeMediaVolumeState) {
1062            mPendingVolumeCommand = null;
1063        }
1064
1065        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1066        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1067               ((device & mFixedVolumeDevices) != 0)) {
1068            flags |= AudioManager.FLAG_FIXED_VOLUME;
1069
1070            // Always toggle between max safe volume and 0 for fixed volume devices where safe
1071            // volume is enforced, and max and 0 for the others.
1072            // This is simulated by stepping by the full allowed volume range
1073            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1074                    (device & mSafeMediaVolumeDevices) != 0) {
1075                step = mSafeMediaVolumeIndex;
1076            } else {
1077                step = streamState.getMaxIndex();
1078            }
1079            if (aliasIndex != 0) {
1080                aliasIndex = step;
1081            }
1082        } else {
1083            // convert one UI step (+/-1) into a number of internal units on the stream alias
1084            step = rescaleIndex(10, streamType, streamTypeAlias);
1085        }
1086
1087        // If either the client forces allowing ringer modes for this adjustment,
1088        // or the stream type is one that is affected by ringer modes
1089        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1090                (streamTypeAlias == getUiSoundsStreamType())) {
1091            int ringerMode = getRingerModeInternal();
1092            // do not vibrate if already in vibrate mode
1093            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1094                flags &= ~AudioManager.FLAG_VIBRATE;
1095            }
1096            // Check if the ringer mode handles this adjustment. If it does we don't
1097            // need to adjust the volume further.
1098            final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
1099            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1100            // If suppressing a volume adjustment in silent mode, display the UI hint
1101            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1102                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1103            }
1104            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1105            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1106                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1107            }
1108        }
1109
1110        int oldIndex = mStreamStates[streamType].getIndex(device);
1111
1112        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
1113            mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
1114
1115            // Check if volume update should be send to AVRCP
1116            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1117                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1118                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1119                synchronized (mA2dpAvrcpLock) {
1120                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1121                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
1122                    }
1123                }
1124            }
1125
1126            if (isMuteAdjust) {
1127                boolean state;
1128                if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1129                    state = !streamState.mIsMuted;
1130                } else {
1131                    state = direction == AudioManager.ADJUST_MUTE;
1132                }
1133                if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1134                    setSystemAudioMute(state);
1135                }
1136                for (int stream = 0; stream < mStreamStates.length; stream++) {
1137                    if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1138                        mStreamStates[stream].mute(state);
1139                    }
1140                }
1141            } else if ((direction == AudioManager.ADJUST_RAISE) &&
1142                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
1143                Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
1144                mVolumeController.postDisplaySafeVolumeWarning(flags);
1145            } else if (streamState.adjustIndex(direction * step, device, caller)
1146                    || streamState.mIsMuted) {
1147                // Post message to set system volume (it in turn will post a
1148                // message to persist).
1149                if (streamState.mIsMuted) {
1150                    // Unmute the stream if it was previously muted
1151                    if (direction == AudioManager.ADJUST_RAISE) {
1152                        // unmute immediately for volume up
1153                        streamState.mute(false);
1154                    } else if (direction == AudioManager.ADJUST_LOWER) {
1155                        if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1156                            sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1157                                    streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1158                        }
1159                    }
1160                }
1161                sendMsg(mAudioHandler,
1162                        MSG_SET_DEVICE_VOLUME,
1163                        SENDMSG_QUEUE,
1164                        device,
1165                        0,
1166                        streamState,
1167                        0);
1168            }
1169
1170            // Check if volume update should be sent to Hdmi system audio.
1171            int newIndex = mStreamStates[streamType].getIndex(device);
1172            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1173                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1174            }
1175            if (mHdmiManager != null) {
1176                synchronized (mHdmiManager) {
1177                    // mHdmiCecSink true => mHdmiPlaybackClient != null
1178                    if (mHdmiCecSink &&
1179                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1180                            oldIndex != newIndex) {
1181                        synchronized (mHdmiPlaybackClient) {
1182                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1183                                    KeyEvent.KEYCODE_VOLUME_UP;
1184                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1185                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1186                        }
1187                    }
1188                }
1189            }
1190        }
1191        int index = mStreamStates[streamType].getIndex(device);
1192        sendVolumeUpdate(streamType, oldIndex, index, flags);
1193    }
1194
1195    // Called after a delay when volume down is pressed while muted
1196    private void onUnmuteStream(int stream, int flags) {
1197        VolumeStreamState streamState = mStreamStates[stream];
1198        streamState.mute(false);
1199
1200        final int device = getDeviceForStream(stream);
1201        final int index = mStreamStates[stream].getIndex(device);
1202        sendVolumeUpdate(stream, index, index, flags);
1203    }
1204
1205    private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1206        if (mHdmiManager == null
1207                || mHdmiTvClient == null
1208                || oldVolume == newVolume
1209                || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1210
1211        // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1212        // is tranformed to HDMI-CEC commands and passed through CEC bus.
1213        synchronized (mHdmiManager) {
1214            if (!mHdmiSystemAudioSupported) return;
1215            synchronized (mHdmiTvClient) {
1216                final long token = Binder.clearCallingIdentity();
1217                try {
1218                    mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
1219                } finally {
1220                    Binder.restoreCallingIdentity(token);
1221                }
1222            }
1223        }
1224    }
1225
1226    // StreamVolumeCommand contains the information needed to defer the process of
1227    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1228    class StreamVolumeCommand {
1229        public final int mStreamType;
1230        public final int mIndex;
1231        public final int mFlags;
1232        public final int mDevice;
1233
1234        StreamVolumeCommand(int streamType, int index, int flags, int device) {
1235            mStreamType = streamType;
1236            mIndex = index;
1237            mFlags = flags;
1238            mDevice = device;
1239        }
1240
1241        @Override
1242        public String toString() {
1243            return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1244                    .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1245                    .append(mDevice).append('}').toString();
1246        }
1247    };
1248
1249    private void onSetStreamVolume(int streamType, int index, int flags, int device,
1250            String caller) {
1251        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, caller);
1252        // setting volume on ui sounds stream type also controls silent mode
1253        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1254                (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
1255            int newRingerMode;
1256            if (index == 0) {
1257                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
1258                        : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
1259                        : AudioManager.RINGER_MODE_NORMAL;
1260            } else {
1261                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1262            }
1263            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
1264        }
1265    }
1266
1267    /** @see AudioManager#setStreamVolume(int, int, int) */
1268    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
1269        setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1270                Binder.getCallingUid());
1271    }
1272
1273    private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1274            String caller, int uid) {
1275        if (mUseFixedVolume) {
1276            return;
1277        }
1278
1279        ensureValidStreamType(streamType);
1280        int streamTypeAlias = mStreamVolumeAlias[streamType];
1281        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1282
1283        final int device = getDeviceForStream(streamType);
1284        int oldIndex;
1285
1286        // skip a2dp absolute volume control request when the device
1287        // is not an a2dp device
1288        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1289            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1290            return;
1291        }
1292
1293        if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1294                != AppOpsManager.MODE_ALLOWED) {
1295            return;
1296        }
1297
1298        synchronized (mSafeMediaVolumeState) {
1299            // reset any pending volume command
1300            mPendingVolumeCommand = null;
1301
1302            oldIndex = streamState.getIndex(device);
1303
1304            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1305
1306            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1307                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1308                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1309                synchronized (mA2dpAvrcpLock) {
1310                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1311                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
1312                    }
1313                }
1314            }
1315
1316            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1317                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
1318            }
1319
1320            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1321            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1322                    ((device & mFixedVolumeDevices) != 0)) {
1323                flags |= AudioManager.FLAG_FIXED_VOLUME;
1324
1325                // volume is either 0 or max allowed for fixed volume devices
1326                if (index != 0) {
1327                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1328                            (device & mSafeMediaVolumeDevices) != 0) {
1329                        index = mSafeMediaVolumeIndex;
1330                    } else {
1331                        index = streamState.getMaxIndex();
1332                    }
1333                }
1334            }
1335
1336            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
1337                mVolumeController.postDisplaySafeVolumeWarning(flags);
1338                mPendingVolumeCommand = new StreamVolumeCommand(
1339                                                    streamType, index, flags, device);
1340            } else {
1341                onSetStreamVolume(streamType, index, flags, device, caller);
1342                index = mStreamStates[streamType].getIndex(device);
1343            }
1344        }
1345        sendVolumeUpdate(streamType, oldIndex, index, flags);
1346    }
1347
1348    /** @see AudioManager#forceVolumeControlStream(int) */
1349    public void forceVolumeControlStream(int streamType, IBinder cb) {
1350        synchronized(mForceControlStreamLock) {
1351            mVolumeControlStream = streamType;
1352            if (mVolumeControlStream == -1) {
1353                if (mForceControlStreamClient != null) {
1354                    mForceControlStreamClient.release();
1355                    mForceControlStreamClient = null;
1356                }
1357            } else {
1358                mForceControlStreamClient = new ForceControlStreamClient(cb);
1359            }
1360        }
1361    }
1362
1363    private class ForceControlStreamClient implements IBinder.DeathRecipient {
1364        private IBinder mCb; // To be notified of client's death
1365
1366        ForceControlStreamClient(IBinder cb) {
1367            if (cb != null) {
1368                try {
1369                    cb.linkToDeath(this, 0);
1370                } catch (RemoteException e) {
1371                    // Client has died!
1372                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1373                    cb = null;
1374                }
1375            }
1376            mCb = cb;
1377        }
1378
1379        public void binderDied() {
1380            synchronized(mForceControlStreamLock) {
1381                Log.w(TAG, "SCO client died");
1382                if (mForceControlStreamClient != this) {
1383                    Log.w(TAG, "unregistered control stream client died");
1384                } else {
1385                    mForceControlStreamClient = null;
1386                    mVolumeControlStream = -1;
1387                }
1388            }
1389        }
1390
1391        public void release() {
1392            if (mCb != null) {
1393                mCb.unlinkToDeath(this, 0);
1394                mCb = null;
1395            }
1396        }
1397    }
1398
1399    private void sendBroadcastToAll(Intent intent) {
1400        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1401        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1402        final long ident = Binder.clearCallingIdentity();
1403        try {
1404            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1405        } finally {
1406            Binder.restoreCallingIdentity(ident);
1407        }
1408    }
1409
1410    private void sendStickyBroadcastToAll(Intent intent) {
1411        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
1412        final long ident = Binder.clearCallingIdentity();
1413        try {
1414            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1415        } finally {
1416            Binder.restoreCallingIdentity(ident);
1417        }
1418    }
1419
1420    // UI update and Broadcast Intent
1421    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1422        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
1423            streamType = AudioSystem.STREAM_NOTIFICATION;
1424        }
1425
1426        if (streamType == AudioSystem.STREAM_MUSIC) {
1427            flags = updateFlagsForSystemAudio(flags);
1428        }
1429        mVolumeController.postVolumeChanged(streamType, flags);
1430    }
1431
1432    // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1433    // receives volume notification from Audio Receiver.
1434    private int updateFlagsForSystemAudio(int flags) {
1435        if (mHdmiTvClient != null) {
1436            synchronized (mHdmiTvClient) {
1437                if (mHdmiSystemAudioSupported &&
1438                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1439                    flags &= ~AudioManager.FLAG_SHOW_UI;
1440                }
1441            }
1442        }
1443        return flags;
1444    }
1445
1446    // UI update and Broadcast Intent
1447    private void sendMasterMuteUpdate(boolean muted, int flags) {
1448        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
1449        broadcastMasterMuteStatus(muted);
1450    }
1451
1452    private void broadcastMasterMuteStatus(boolean muted) {
1453        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1454        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
1455        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1456                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1457        sendStickyBroadcastToAll(intent);
1458    }
1459
1460    /**
1461     * Sets the stream state's index, and posts a message to set system volume.
1462     * This will not call out to the UI. Assumes a valid stream type.
1463     *
1464     * @param streamType Type of the stream
1465     * @param index Desired volume index of the stream
1466     * @param device the device whose volume must be changed
1467     * @param force If true, set the volume even if the desired volume is same
1468     * as the current volume.
1469     */
1470    private void setStreamVolumeInt(int streamType,
1471                                    int index,
1472                                    int device,
1473                                    boolean force,
1474                                    String caller) {
1475        VolumeStreamState streamState = mStreamStates[streamType];
1476
1477        if (streamState.setIndex(index, device, caller) || force) {
1478            // Post message to set system volume (it in turn will post a message
1479            // to persist).
1480            sendMsg(mAudioHandler,
1481                    MSG_SET_DEVICE_VOLUME,
1482                    SENDMSG_QUEUE,
1483                    device,
1484                    0,
1485                    streamState,
1486                    0);
1487        }
1488    }
1489
1490    private void setSystemAudioMute(boolean state) {
1491        if (mHdmiManager == null || mHdmiTvClient == null) return;
1492        synchronized (mHdmiManager) {
1493            if (!mHdmiSystemAudioSupported) return;
1494            synchronized (mHdmiTvClient) {
1495                final long token = Binder.clearCallingIdentity();
1496                try {
1497                    mHdmiTvClient.setSystemAudioMute(state);
1498                } finally {
1499                    Binder.restoreCallingIdentity(token);
1500                }
1501            }
1502        }
1503    }
1504
1505    /** get stream mute state. */
1506    public boolean isStreamMute(int streamType) {
1507        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1508            streamType = getActiveStreamType(streamType);
1509        }
1510        synchronized (VolumeStreamState.class) {
1511            return mStreamStates[streamType].mIsMuted;
1512        }
1513    }
1514
1515    private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1516        private IBinder mICallback; // To be notified of client's death
1517
1518        RmtSbmxFullVolDeathHandler(IBinder cb) {
1519            mICallback = cb;
1520            try {
1521                cb.linkToDeath(this, 0/*flags*/);
1522            } catch (RemoteException e) {
1523                Log.e(TAG, "can't link to death", e);
1524            }
1525        }
1526
1527        boolean isHandlerFor(IBinder cb) {
1528            return mICallback.equals(cb);
1529        }
1530
1531        void forget() {
1532            try {
1533                mICallback.unlinkToDeath(this, 0/*flags*/);
1534            } catch (NoSuchElementException e) {
1535                Log.e(TAG, "error unlinking to death", e);
1536            }
1537        }
1538
1539        public void binderDied() {
1540            Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1541            forceRemoteSubmixFullVolume(false, mICallback);
1542        }
1543    }
1544
1545    /**
1546     * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1547     * @return true if there is a registered death handler, false otherwise */
1548    private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1549        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1550        while (it.hasNext()) {
1551            final RmtSbmxFullVolDeathHandler handler = it.next();
1552            if (handler.isHandlerFor(cb)) {
1553                handler.forget();
1554                mRmtSbmxFullVolDeathHandlers.remove(handler);
1555                return true;
1556            }
1557        }
1558        return false;
1559    }
1560
1561    /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1562    private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1563        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1564        while (it.hasNext()) {
1565            if (it.next().isHandlerFor(cb)) {
1566                return true;
1567            }
1568        }
1569        return false;
1570    }
1571
1572    private int mRmtSbmxFullVolRefCount = 0;
1573    private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1574            new ArrayList<RmtSbmxFullVolDeathHandler>();
1575
1576    public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1577        if (cb == null) {
1578            return;
1579        }
1580        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1581                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1582            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1583            return;
1584        }
1585        synchronized(mRmtSbmxFullVolDeathHandlers) {
1586            boolean applyRequired = false;
1587            if (startForcing) {
1588                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1589                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1590                    if (mRmtSbmxFullVolRefCount == 0) {
1591                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1592                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1593                        applyRequired = true;
1594                    }
1595                    mRmtSbmxFullVolRefCount++;
1596                }
1597            } else {
1598                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1599                    mRmtSbmxFullVolRefCount--;
1600                    if (mRmtSbmxFullVolRefCount == 0) {
1601                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1602                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1603                        applyRequired = true;
1604                    }
1605                }
1606            }
1607            if (applyRequired) {
1608                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1609                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1610                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1611            }
1612        }
1613    }
1614
1615    private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
1616        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1617                != AppOpsManager.MODE_ALLOWED) {
1618            return;
1619        }
1620        if (mute != AudioSystem.getMasterMute()) {
1621            setSystemAudioMute(mute);
1622            AudioSystem.setMasterMute(mute);
1623            // Post a persist master volume msg
1624            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1625                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
1626            sendMasterMuteUpdate(mute, flags);
1627
1628            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1629            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1630            sendBroadcastToAll(intent);
1631        }
1632    }
1633
1634    /** get master mute state. */
1635    public boolean isMasterMute() {
1636        return AudioSystem.getMasterMute();
1637    }
1638
1639    public void setMasterMute(boolean mute, int flags, String callingPackage) {
1640        setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
1641    }
1642
1643    /** @see AudioManager#getStreamVolume(int) */
1644    public int getStreamVolume(int streamType) {
1645        ensureValidStreamType(streamType);
1646        int device = getDeviceForStream(streamType);
1647        synchronized (VolumeStreamState.class) {
1648            int index = mStreamStates[streamType].getIndex(device);
1649
1650            // by convention getStreamVolume() returns 0 when a stream is muted.
1651            if (mStreamStates[streamType].mIsMuted) {
1652                index = 0;
1653            }
1654            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1655                    (device & mFixedVolumeDevices) != 0) {
1656                index = mStreamStates[streamType].getMaxIndex();
1657            }
1658            return (index + 5) / 10;
1659        }
1660    }
1661
1662    /** @see AudioManager#getStreamMaxVolume(int) */
1663    public int getStreamMaxVolume(int streamType) {
1664        ensureValidStreamType(streamType);
1665        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
1666    }
1667
1668    /** @see AudioManager#getStreamMinVolume(int) */
1669    public int getStreamMinVolume(int streamType) {
1670        ensureValidStreamType(streamType);
1671        return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1672    }
1673
1674    /** Get last audible volume before stream was muted. */
1675    public int getLastAudibleStreamVolume(int streamType) {
1676        ensureValidStreamType(streamType);
1677        int device = getDeviceForStream(streamType);
1678        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
1679    }
1680
1681    /** @see AudioManager#getUiSoundsStreamType()  */
1682    public int getUiSoundsStreamType() {
1683        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
1684    }
1685
1686    /** @see AudioManager#setMicrophoneMute(boolean) */
1687    public void setMicrophoneMute(boolean on, String callingPackage) {
1688        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1689                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1690            return;
1691        }
1692        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1693            return;
1694        }
1695
1696        AudioSystem.muteMicrophone(on);
1697        // Post a persist microphone msg.
1698        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1699                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
1700    }
1701
1702    @Override
1703    public int getRingerModeExternal() {
1704        synchronized(mSettingsLock) {
1705            return mRingerModeExternal;
1706        }
1707    }
1708
1709    @Override
1710    public int getRingerModeInternal() {
1711        synchronized(mSettingsLock) {
1712            return mRingerMode;
1713        }
1714    }
1715
1716    private void ensureValidRingerMode(int ringerMode) {
1717        if (!isValidRingerMode(ringerMode)) {
1718            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1719        }
1720    }
1721
1722    /** @see AudioManager#isValidRingerMode(int) */
1723    public boolean isValidRingerMode(int ringerMode) {
1724        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1725    }
1726
1727    public void setRingerModeExternal(int ringerMode, String caller) {
1728        setRingerMode(ringerMode, caller, true /*external*/);
1729    }
1730
1731    public void setRingerModeInternal(int ringerMode, String caller) {
1732        enforceVolumeController("setRingerModeInternal");
1733        setRingerMode(ringerMode, caller, false /*external*/);
1734    }
1735
1736    private void setRingerMode(int ringerMode, String caller, boolean external) {
1737        if (mUseFixedVolume || isPlatformTelevision()) {
1738            return;
1739        }
1740        if (caller == null || caller.length() == 0) {
1741            throw new IllegalArgumentException("Bad caller: " + caller);
1742        }
1743        ensureValidRingerMode(ringerMode);
1744        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1745            ringerMode = AudioManager.RINGER_MODE_SILENT;
1746        }
1747        final long identity = Binder.clearCallingIdentity();
1748        try {
1749            synchronized (mSettingsLock) {
1750                final int ringerModeInternal = getRingerModeInternal();
1751                final int ringerModeExternal = getRingerModeExternal();
1752                if (external) {
1753                    setRingerModeExt(ringerMode);
1754                    if (mRingerModeDelegate != null) {
1755                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1756                                ringerMode, caller, ringerModeInternal, mVolumePolicy);
1757                    }
1758                    if (ringerMode != ringerModeInternal) {
1759                        setRingerModeInt(ringerMode, true /*persist*/);
1760                    }
1761                } else /*internal*/ {
1762                    if (ringerMode != ringerModeInternal) {
1763                        setRingerModeInt(ringerMode, true /*persist*/);
1764                    }
1765                    if (mRingerModeDelegate != null) {
1766                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1767                                ringerMode, caller, ringerModeExternal, mVolumePolicy);
1768                    }
1769                    setRingerModeExt(ringerMode);
1770                }
1771            }
1772        } finally {
1773            Binder.restoreCallingIdentity(identity);
1774        }
1775    }
1776
1777    private void setRingerModeExt(int ringerMode) {
1778        synchronized(mSettingsLock) {
1779            if (ringerMode == mRingerModeExternal) return;
1780            mRingerModeExternal = ringerMode;
1781        }
1782        // Send sticky broadcast
1783        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
1784    }
1785
1786    private void setRingerModeInt(int ringerMode, boolean persist) {
1787        final boolean change;
1788        synchronized(mSettingsLock) {
1789            change = mRingerMode != ringerMode;
1790            mRingerMode = ringerMode;
1791        }
1792
1793        // Mute stream if not previously muted by ringer mode and ringer mode
1794        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1795        // Unmute stream if previously muted by ringer mode and ringer mode
1796        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1797        int numStreamTypes = AudioSystem.getNumStreamTypes();
1798        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1799                || ringerMode == AudioManager.RINGER_MODE_SILENT;
1800        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1801            final boolean isMuted = isStreamMutedByRingerMode(streamType);
1802            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1803            if (isMuted == shouldMute) continue;
1804            if (!shouldMute) {
1805                // unmute
1806                // ring and notifications volume should never be 0 when not silenced
1807                // on voice capable devices or devices that support vibration
1808                if ((isPlatformVoice() || mHasVibrator) &&
1809                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1810                    synchronized (VolumeStreamState.class) {
1811                        final VolumeStreamState vss = mStreamStates[streamType];
1812                        for (int i = 0; i < vss.mIndexMap.size(); i++) {
1813                            int device = vss.mIndexMap.keyAt(i);
1814                            int value = vss.mIndexMap.valueAt(i);
1815                            if (value == 0) {
1816                                vss.setIndex(10, device, TAG);
1817                            }
1818                        }
1819                        // Persist volume for stream ring when it is changed here
1820                      final int device = getDeviceForStream(streamType);
1821                      sendMsg(mAudioHandler,
1822                              MSG_PERSIST_VOLUME,
1823                              SENDMSG_QUEUE,
1824                              device,
1825                              0,
1826                              mStreamStates[streamType],
1827                              PERSIST_DELAY);
1828                    }
1829                }
1830                mStreamStates[streamType].mute(false);
1831                mRingerModeMutedStreams &= ~(1 << streamType);
1832            } else {
1833                // mute
1834                mStreamStates[streamType].mute(true);
1835                mRingerModeMutedStreams |= (1 << streamType);
1836            }
1837        }
1838
1839        // Post a persist ringer mode msg
1840        if (persist) {
1841            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
1842                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1843        }
1844        if (change) {
1845            // Send sticky broadcast
1846            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1847        }
1848    }
1849
1850    /** @see AudioManager#shouldVibrate(int) */
1851    public boolean shouldVibrate(int vibrateType) {
1852        if (!mHasVibrator) return false;
1853
1854        switch (getVibrateSetting(vibrateType)) {
1855
1856            case AudioManager.VIBRATE_SETTING_ON:
1857                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
1858
1859            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1860                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
1861
1862            case AudioManager.VIBRATE_SETTING_OFF:
1863                // return false, even for incoming calls
1864                return false;
1865
1866            default:
1867                return false;
1868        }
1869    }
1870
1871    /** @see AudioManager#getVibrateSetting(int) */
1872    public int getVibrateSetting(int vibrateType) {
1873        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
1874        return (mVibrateSetting >> (vibrateType * 2)) & 3;
1875    }
1876
1877    /** @see AudioManager#setVibrateSetting(int, int) */
1878    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1879
1880        if (!mHasVibrator) return;
1881
1882        mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1883                vibrateSetting);
1884
1885        // Broadcast change
1886        broadcastVibrateSetting(vibrateType);
1887
1888    }
1889
1890    private class SetModeDeathHandler implements IBinder.DeathRecipient {
1891        private IBinder mCb; // To be notified of client's death
1892        private int mPid;
1893        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1894
1895        SetModeDeathHandler(IBinder cb, int pid) {
1896            mCb = cb;
1897            mPid = pid;
1898        }
1899
1900        public void binderDied() {
1901            int newModeOwnerPid = 0;
1902            synchronized(mSetModeDeathHandlers) {
1903                Log.w(TAG, "setMode() client died");
1904                int index = mSetModeDeathHandlers.indexOf(this);
1905                if (index < 0) {
1906                    Log.w(TAG, "unregistered setMode() client died");
1907                } else {
1908                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
1909                }
1910            }
1911            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1912            // SCO connections not started by the application changing the mode
1913            if (newModeOwnerPid != 0) {
1914                final long ident = Binder.clearCallingIdentity();
1915                disconnectBluetoothSco(newModeOwnerPid);
1916                Binder.restoreCallingIdentity(ident);
1917            }
1918        }
1919
1920        public int getPid() {
1921            return mPid;
1922        }
1923
1924        public void setMode(int mode) {
1925            mMode = mode;
1926        }
1927
1928        public int getMode() {
1929            return mMode;
1930        }
1931
1932        public IBinder getBinder() {
1933            return mCb;
1934        }
1935    }
1936
1937    /** @see AudioManager#setMode(int) */
1938    public void setMode(int mode, IBinder cb, String callingPackage) {
1939        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
1940        if (!checkAudioSettingsPermission("setMode()")) {
1941            return;
1942        }
1943
1944        if ( (mode == AudioSystem.MODE_IN_CALL) &&
1945                (mContext.checkCallingOrSelfPermission(
1946                        android.Manifest.permission.MODIFY_PHONE_STATE)
1947                            != PackageManager.PERMISSION_GRANTED)) {
1948            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
1949                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1950            return;
1951        }
1952
1953        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1954            return;
1955        }
1956
1957        int newModeOwnerPid = 0;
1958        synchronized(mSetModeDeathHandlers) {
1959            if (mode == AudioSystem.MODE_CURRENT) {
1960                mode = mMode;
1961            }
1962            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
1963        }
1964        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1965        // SCO connections not started by the application changing the mode
1966        if (newModeOwnerPid != 0) {
1967             disconnectBluetoothSco(newModeOwnerPid);
1968        }
1969    }
1970
1971    // must be called synchronized on mSetModeDeathHandlers
1972    // setModeInt() returns a valid PID if the audio mode was successfully set to
1973    // any mode other than NORMAL.
1974    private int setModeInt(int mode, IBinder cb, int pid, String caller) {
1975        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
1976                + caller + ")"); }
1977        int newModeOwnerPid = 0;
1978        if (cb == null) {
1979            Log.e(TAG, "setModeInt() called with null binder");
1980            return newModeOwnerPid;
1981        }
1982
1983        SetModeDeathHandler hdlr = null;
1984        Iterator iter = mSetModeDeathHandlers.iterator();
1985        while (iter.hasNext()) {
1986            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1987            if (h.getPid() == pid) {
1988                hdlr = h;
1989                // Remove from client list so that it is re-inserted at top of list
1990                iter.remove();
1991                hdlr.getBinder().unlinkToDeath(hdlr, 0);
1992                break;
1993            }
1994        }
1995        int status = AudioSystem.AUDIO_STATUS_OK;
1996        do {
1997            if (mode == AudioSystem.MODE_NORMAL) {
1998                // get new mode from client at top the list if any
1999                if (!mSetModeDeathHandlers.isEmpty()) {
2000                    hdlr = mSetModeDeathHandlers.get(0);
2001                    cb = hdlr.getBinder();
2002                    mode = hdlr.getMode();
2003                    if (DEBUG_MODE) {
2004                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2005                                + hdlr.mPid);
2006                    }
2007                }
2008            } else {
2009                if (hdlr == null) {
2010                    hdlr = new SetModeDeathHandler(cb, pid);
2011                }
2012                // Register for client death notification
2013                try {
2014                    cb.linkToDeath(hdlr, 0);
2015                } catch (RemoteException e) {
2016                    // Client has died!
2017                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2018                }
2019
2020                // Last client to call setMode() is always at top of client list
2021                // as required by SetModeDeathHandler.binderDied()
2022                mSetModeDeathHandlers.add(0, hdlr);
2023                hdlr.setMode(mode);
2024            }
2025
2026            if (mode != mMode) {
2027                status = AudioSystem.setPhoneState(mode);
2028                if (status == AudioSystem.AUDIO_STATUS_OK) {
2029                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
2030                    mMode = mode;
2031                } else {
2032                    if (hdlr != null) {
2033                        mSetModeDeathHandlers.remove(hdlr);
2034                        cb.unlinkToDeath(hdlr, 0);
2035                    }
2036                    // force reading new top of mSetModeDeathHandlers stack
2037                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
2038                    mode = AudioSystem.MODE_NORMAL;
2039                }
2040            } else {
2041                status = AudioSystem.AUDIO_STATUS_OK;
2042            }
2043        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2044
2045        if (status == AudioSystem.AUDIO_STATUS_OK) {
2046            if (mode != AudioSystem.MODE_NORMAL) {
2047                if (mSetModeDeathHandlers.isEmpty()) {
2048                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2049                } else {
2050                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2051                }
2052            }
2053            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
2054            int device = getDeviceForStream(streamType);
2055            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2056            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
2057
2058            updateStreamVolumeAlias(true /*updateVolumes*/, caller);
2059        }
2060        return newModeOwnerPid;
2061    }
2062
2063    /** @see AudioManager#getMode() */
2064    public int getMode() {
2065        return mMode;
2066    }
2067
2068    //==========================================================================================
2069    // Sound Effects
2070    //==========================================================================================
2071
2072    private static final String TAG_AUDIO_ASSETS = "audio_assets";
2073    private static final String ATTR_VERSION = "version";
2074    private static final String TAG_GROUP = "group";
2075    private static final String ATTR_GROUP_NAME = "name";
2076    private static final String TAG_ASSET = "asset";
2077    private static final String ATTR_ASSET_ID = "id";
2078    private static final String ATTR_ASSET_FILE = "file";
2079
2080    private static final String ASSET_FILE_VERSION = "1.0";
2081    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2082
2083    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
2084
2085    class LoadSoundEffectReply {
2086        public int mStatus = 1;
2087    };
2088
2089    private void loadTouchSoundAssetDefaults() {
2090        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2091        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2092            SOUND_EFFECT_FILES_MAP[i][0] = 0;
2093            SOUND_EFFECT_FILES_MAP[i][1] = -1;
2094        }
2095    }
2096
2097    private void loadTouchSoundAssets() {
2098        XmlResourceParser parser = null;
2099
2100        // only load assets once.
2101        if (!SOUND_EFFECT_FILES.isEmpty()) {
2102            return;
2103        }
2104
2105        loadTouchSoundAssetDefaults();
2106
2107        try {
2108            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2109
2110            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2111            String version = parser.getAttributeValue(null, ATTR_VERSION);
2112            boolean inTouchSoundsGroup = false;
2113
2114            if (ASSET_FILE_VERSION.equals(version)) {
2115                while (true) {
2116                    XmlUtils.nextElement(parser);
2117                    String element = parser.getName();
2118                    if (element == null) {
2119                        break;
2120                    }
2121                    if (element.equals(TAG_GROUP)) {
2122                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2123                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
2124                            inTouchSoundsGroup = true;
2125                            break;
2126                        }
2127                    }
2128                }
2129                while (inTouchSoundsGroup) {
2130                    XmlUtils.nextElement(parser);
2131                    String element = parser.getName();
2132                    if (element == null) {
2133                        break;
2134                    }
2135                    if (element.equals(TAG_ASSET)) {
2136                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2137                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2138                        int fx;
2139
2140                        try {
2141                            Field field = AudioManager.class.getField(id);
2142                            fx = field.getInt(null);
2143                        } catch (Exception e) {
2144                            Log.w(TAG, "Invalid touch sound ID: "+id);
2145                            continue;
2146                        }
2147
2148                        int i = SOUND_EFFECT_FILES.indexOf(file);
2149                        if (i == -1) {
2150                            i = SOUND_EFFECT_FILES.size();
2151                            SOUND_EFFECT_FILES.add(file);
2152                        }
2153                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
2154                    } else {
2155                        break;
2156                    }
2157                }
2158            }
2159        } catch (Resources.NotFoundException e) {
2160            Log.w(TAG, "audio assets file not found", e);
2161        } catch (XmlPullParserException e) {
2162            Log.w(TAG, "XML parser exception reading touch sound assets", e);
2163        } catch (IOException e) {
2164            Log.w(TAG, "I/O exception reading touch sound assets", e);
2165        } finally {
2166            if (parser != null) {
2167                parser.close();
2168            }
2169        }
2170    }
2171
2172    /** @see AudioManager#playSoundEffect(int) */
2173    public void playSoundEffect(int effectType) {
2174        playSoundEffectVolume(effectType, -1.0f);
2175    }
2176
2177    /** @see AudioManager#playSoundEffect(int, float) */
2178    public void playSoundEffectVolume(int effectType, float volume) {
2179        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2180            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2181            return;
2182        }
2183
2184        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
2185                effectType, (int) (volume * 1000), null, 0);
2186    }
2187
2188    /**
2189     * Loads samples into the soundpool.
2190     * This method must be called at first when sound effects are enabled
2191     */
2192    public boolean loadSoundEffects() {
2193        int attempts = 3;
2194        LoadSoundEffectReply reply = new LoadSoundEffectReply();
2195
2196        synchronized (reply) {
2197            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2198            while ((reply.mStatus == 1) && (attempts-- > 0)) {
2199                try {
2200                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
2201                } catch (InterruptedException e) {
2202                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
2203                }
2204            }
2205        }
2206        return (reply.mStatus == 0);
2207    }
2208
2209    /**
2210     *  Unloads samples from the sound pool.
2211     *  This method can be called to free some memory when
2212     *  sound effects are disabled.
2213     */
2214    public void unloadSoundEffects() {
2215        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
2216    }
2217
2218    class SoundPoolListenerThread extends Thread {
2219        public SoundPoolListenerThread() {
2220            super("SoundPoolListenerThread");
2221        }
2222
2223        @Override
2224        public void run() {
2225
2226            Looper.prepare();
2227            mSoundPoolLooper = Looper.myLooper();
2228
2229            synchronized (mSoundEffectsLock) {
2230                if (mSoundPool != null) {
2231                    mSoundPoolCallBack = new SoundPoolCallback();
2232                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2233                }
2234                mSoundEffectsLock.notify();
2235            }
2236            Looper.loop();
2237        }
2238    }
2239
2240    private final class SoundPoolCallback implements
2241            android.media.SoundPool.OnLoadCompleteListener {
2242
2243        int mStatus = 1; // 1 means neither error nor last sample loaded yet
2244        List<Integer> mSamples = new ArrayList<Integer>();
2245
2246        public int status() {
2247            return mStatus;
2248        }
2249
2250        public void setSamples(int[] samples) {
2251            for (int i = 0; i < samples.length; i++) {
2252                // do not wait ack for samples rejected upfront by SoundPool
2253                if (samples[i] > 0) {
2254                    mSamples.add(samples[i]);
2255                }
2256            }
2257        }
2258
2259        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2260            synchronized (mSoundEffectsLock) {
2261                int i = mSamples.indexOf(sampleId);
2262                if (i >= 0) {
2263                    mSamples.remove(i);
2264                }
2265                if ((status != 0) || mSamples. isEmpty()) {
2266                    mStatus = status;
2267                    mSoundEffectsLock.notify();
2268                }
2269            }
2270        }
2271    }
2272
2273    /** @see AudioManager#reloadAudioSettings() */
2274    public void reloadAudioSettings() {
2275        readAudioSettings(false /*userSwitch*/);
2276    }
2277
2278    private void readAudioSettings(boolean userSwitch) {
2279        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2280        readPersistedSettings();
2281
2282        // restore volume settings
2283        int numStreamTypes = AudioSystem.getNumStreamTypes();
2284        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2285            VolumeStreamState streamState = mStreamStates[streamType];
2286
2287            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2288                continue;
2289            }
2290
2291            streamState.readSettings();
2292            synchronized (VolumeStreamState.class) {
2293                // unmute stream that was muted but is not affect by mute anymore
2294                if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
2295                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
2296                    streamState.mIsMuted = false;
2297                }
2298            }
2299        }
2300
2301        // apply new ringer mode before checking volume for alias streams so that streams
2302        // muted by ringer mode have the correct volume
2303        setRingerModeInt(getRingerModeInternal(), false);
2304
2305        checkAllFixedVolumeDevices();
2306        checkAllAliasStreamVolumes();
2307        checkMuteAffectedStreams();
2308
2309        synchronized (mSafeMediaVolumeState) {
2310            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2311                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2312                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
2313            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
2314                enforceSafeMediaVolume(TAG);
2315            }
2316        }
2317    }
2318
2319    /** @see AudioManager#setSpeakerphoneOn(boolean) */
2320    public void setSpeakerphoneOn(boolean on){
2321        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2322            return;
2323        }
2324
2325        if (on) {
2326            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2327                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2328                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2329            }
2330            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2331        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2332            mForcedUseForComm = AudioSystem.FORCE_NONE;
2333        }
2334
2335        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2336                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2337    }
2338
2339    /** @see AudioManager#isSpeakerphoneOn() */
2340    public boolean isSpeakerphoneOn() {
2341        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2342    }
2343
2344    /** @see AudioManager#setBluetoothScoOn(boolean) */
2345    public void setBluetoothScoOn(boolean on){
2346        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2347            return;
2348        }
2349
2350        if (on) {
2351            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2352        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2353            mForcedUseForComm = AudioSystem.FORCE_NONE;
2354        }
2355
2356        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2357                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2358        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2359                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2360    }
2361
2362    /** @see AudioManager#isBluetoothScoOn() */
2363    public boolean isBluetoothScoOn() {
2364        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2365    }
2366
2367    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
2368    public void setBluetoothA2dpOn(boolean on) {
2369        synchronized (mBluetoothA2dpEnabledLock) {
2370            mBluetoothA2dpEnabled = on;
2371            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2372                    AudioSystem.FOR_MEDIA,
2373                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2374                    null, 0);
2375        }
2376    }
2377
2378    /** @see AudioManager#isBluetoothA2dpOn() */
2379    public boolean isBluetoothA2dpOn() {
2380        synchronized (mBluetoothA2dpEnabledLock) {
2381            return mBluetoothA2dpEnabled;
2382        }
2383    }
2384
2385    /** @see AudioManager#startBluetoothSco() */
2386    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2387        int scoAudioMode =
2388                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2389                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
2390        startBluetoothScoInt(cb, scoAudioMode);
2391    }
2392
2393    /** @see AudioManager#startBluetoothScoVirtualCall() */
2394    public void startBluetoothScoVirtualCall(IBinder cb) {
2395        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2396    }
2397
2398    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
2399        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
2400                !mSystemReady) {
2401            return;
2402        }
2403        ScoClient client = getScoClient(cb, true);
2404        // The calling identity must be cleared before calling ScoClient.incCount().
2405        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2406        // and this must be done on behalf of system server to make sure permissions are granted.
2407        // The caller identity must be cleared after getScoClient() because it is needed if a new
2408        // client is created.
2409        final long ident = Binder.clearCallingIdentity();
2410        client.incCount(scoAudioMode);
2411        Binder.restoreCallingIdentity(ident);
2412    }
2413
2414    /** @see AudioManager#stopBluetoothSco() */
2415    public void stopBluetoothSco(IBinder cb){
2416        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
2417                !mSystemReady) {
2418            return;
2419        }
2420        ScoClient client = getScoClient(cb, false);
2421        // The calling identity must be cleared before calling ScoClient.decCount().
2422        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2423        // and this must be done on behalf of system server to make sure permissions are granted.
2424        final long ident = Binder.clearCallingIdentity();
2425        if (client != null) {
2426            client.decCount();
2427        }
2428        Binder.restoreCallingIdentity(ident);
2429    }
2430
2431
2432    private class ScoClient implements IBinder.DeathRecipient {
2433        private IBinder mCb; // To be notified of client's death
2434        private int mCreatorPid;
2435        private int mStartcount; // number of SCO connections started by this client
2436
2437        ScoClient(IBinder cb) {
2438            mCb = cb;
2439            mCreatorPid = Binder.getCallingPid();
2440            mStartcount = 0;
2441        }
2442
2443        public void binderDied() {
2444            synchronized(mScoClients) {
2445                Log.w(TAG, "SCO client died");
2446                int index = mScoClients.indexOf(this);
2447                if (index < 0) {
2448                    Log.w(TAG, "unregistered SCO client died");
2449                } else {
2450                    clearCount(true);
2451                    mScoClients.remove(this);
2452                }
2453            }
2454        }
2455
2456        public void incCount(int scoAudioMode) {
2457            synchronized(mScoClients) {
2458                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
2459                if (mStartcount == 0) {
2460                    try {
2461                        mCb.linkToDeath(this, 0);
2462                    } catch (RemoteException e) {
2463                        // client has already died!
2464                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
2465                    }
2466                }
2467                mStartcount++;
2468            }
2469        }
2470
2471        public void decCount() {
2472            synchronized(mScoClients) {
2473                if (mStartcount == 0) {
2474                    Log.w(TAG, "ScoClient.decCount() already 0");
2475                } else {
2476                    mStartcount--;
2477                    if (mStartcount == 0) {
2478                        try {
2479                            mCb.unlinkToDeath(this, 0);
2480                        } catch (NoSuchElementException e) {
2481                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2482                        }
2483                    }
2484                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2485                }
2486            }
2487        }
2488
2489        public void clearCount(boolean stopSco) {
2490            synchronized(mScoClients) {
2491                if (mStartcount != 0) {
2492                    try {
2493                        mCb.unlinkToDeath(this, 0);
2494                    } catch (NoSuchElementException e) {
2495                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2496                    }
2497                }
2498                mStartcount = 0;
2499                if (stopSco) {
2500                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2501                }
2502            }
2503        }
2504
2505        public int getCount() {
2506            return mStartcount;
2507        }
2508
2509        public IBinder getBinder() {
2510            return mCb;
2511        }
2512
2513        public int getPid() {
2514            return mCreatorPid;
2515        }
2516
2517        public int totalCount() {
2518            synchronized(mScoClients) {
2519                int count = 0;
2520                int size = mScoClients.size();
2521                for (int i = 0; i < size; i++) {
2522                    count += mScoClients.get(i).getCount();
2523                }
2524                return count;
2525            }
2526        }
2527
2528        private void requestScoState(int state, int scoAudioMode) {
2529            checkScoAudioState();
2530            if (totalCount() == 0) {
2531                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2532                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2533                    // the connection.
2534                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2535                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2536                    // currently controlled by the same client process.
2537                    synchronized(mSetModeDeathHandlers) {
2538                        if ((mSetModeDeathHandlers.isEmpty() ||
2539                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2540                                (mScoAudioState == SCO_STATE_INACTIVE ||
2541                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2542                            if (mScoAudioState == SCO_STATE_INACTIVE) {
2543                                mScoAudioMode = scoAudioMode;
2544                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
2545                                    if (mBluetoothHeadsetDevice != null) {
2546                                        mScoAudioMode = new Integer(Settings.Global.getInt(
2547                                                                mContentResolver,
2548                                                                "bluetooth_sco_channel_"+
2549                                                                mBluetoothHeadsetDevice.getAddress(),
2550                                                                SCO_MODE_VIRTUAL_CALL));
2551                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2552                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2553                                        }
2554                                    } else {
2555                                        mScoAudioMode = SCO_MODE_RAW;
2556                                    }
2557                                }
2558                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2559                                    boolean status = false;
2560                                    if (mScoAudioMode == SCO_MODE_RAW) {
2561                                        status = mBluetoothHeadset.connectAudio();
2562                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2563                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2564                                                                            mBluetoothHeadsetDevice);
2565                                    } else if (mScoAudioMode == SCO_MODE_VR) {
2566                                        status = mBluetoothHeadset.startVoiceRecognition(
2567                                                                           mBluetoothHeadsetDevice);
2568                                    }
2569
2570                                    if (status) {
2571                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2572                                    } else {
2573                                        broadcastScoConnectionState(
2574                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2575                                    }
2576                                } else if (getBluetoothHeadset()) {
2577                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2578                                }
2579                            } else {
2580                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2581                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2582                            }
2583                        } else {
2584                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2585                        }
2586                    }
2587                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2588                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2589                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2590                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2591                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2592                            boolean status = false;
2593                            if (mScoAudioMode == SCO_MODE_RAW) {
2594                                status = mBluetoothHeadset.disconnectAudio();
2595                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2596                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2597                                                                        mBluetoothHeadsetDevice);
2598                            } else if (mScoAudioMode == SCO_MODE_VR) {
2599                                        status = mBluetoothHeadset.stopVoiceRecognition(
2600                                                                      mBluetoothHeadsetDevice);
2601                            }
2602
2603                            if (!status) {
2604                                mScoAudioState = SCO_STATE_INACTIVE;
2605                                broadcastScoConnectionState(
2606                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2607                            }
2608                        } else if (getBluetoothHeadset()) {
2609                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2610                        }
2611                    } else {
2612                        mScoAudioState = SCO_STATE_INACTIVE;
2613                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2614                    }
2615                }
2616            }
2617        }
2618    }
2619
2620    private void checkScoAudioState() {
2621        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2622                mScoAudioState == SCO_STATE_INACTIVE &&
2623                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2624                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2625            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2626        }
2627    }
2628
2629    private ScoClient getScoClient(IBinder cb, boolean create) {
2630        synchronized(mScoClients) {
2631            ScoClient client = null;
2632            int size = mScoClients.size();
2633            for (int i = 0; i < size; i++) {
2634                client = mScoClients.get(i);
2635                if (client.getBinder() == cb)
2636                    return client;
2637            }
2638            if (create) {
2639                client = new ScoClient(cb);
2640                mScoClients.add(client);
2641            }
2642            return client;
2643        }
2644    }
2645
2646    public void clearAllScoClients(int exceptPid, boolean stopSco) {
2647        synchronized(mScoClients) {
2648            ScoClient savedClient = null;
2649            int size = mScoClients.size();
2650            for (int i = 0; i < size; i++) {
2651                ScoClient cl = mScoClients.get(i);
2652                if (cl.getPid() != exceptPid) {
2653                    cl.clearCount(stopSco);
2654                } else {
2655                    savedClient = cl;
2656                }
2657            }
2658            mScoClients.clear();
2659            if (savedClient != null) {
2660                mScoClients.add(savedClient);
2661            }
2662        }
2663    }
2664
2665    private boolean getBluetoothHeadset() {
2666        boolean result = false;
2667        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2668        if (adapter != null) {
2669            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2670                                    BluetoothProfile.HEADSET);
2671        }
2672        // If we could not get a bluetooth headset proxy, send a failure message
2673        // without delay to reset the SCO audio state and clear SCO clients.
2674        // If we could get a proxy, send a delayed failure message that will reset our state
2675        // in case we don't receive onServiceConnected().
2676        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2677                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2678        return result;
2679    }
2680
2681    private void disconnectBluetoothSco(int exceptPid) {
2682        synchronized(mScoClients) {
2683            checkScoAudioState();
2684            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2685                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2686                if (mBluetoothHeadsetDevice != null) {
2687                    if (mBluetoothHeadset != null) {
2688                        if (!mBluetoothHeadset.stopVoiceRecognition(
2689                                mBluetoothHeadsetDevice)) {
2690                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2691                                    SENDMSG_REPLACE, 0, 0, null, 0);
2692                        }
2693                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2694                            getBluetoothHeadset()) {
2695                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2696                    }
2697                }
2698            } else {
2699                clearAllScoClients(exceptPid, true);
2700            }
2701        }
2702    }
2703
2704    private void resetBluetoothSco() {
2705        synchronized(mScoClients) {
2706            clearAllScoClients(0, false);
2707            mScoAudioState = SCO_STATE_INACTIVE;
2708            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2709        }
2710    }
2711
2712    private void broadcastScoConnectionState(int state) {
2713        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2714                SENDMSG_QUEUE, state, 0, null, 0);
2715    }
2716
2717    private void onBroadcastScoConnectionState(int state) {
2718        if (state != mScoConnectionState) {
2719            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2720            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2721            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2722                    mScoConnectionState);
2723            sendStickyBroadcastToAll(newIntent);
2724            mScoConnectionState = state;
2725        }
2726    }
2727
2728    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2729        new BluetoothProfile.ServiceListener() {
2730        public void onServiceConnected(int profile, BluetoothProfile proxy) {
2731            BluetoothDevice btDevice;
2732            List<BluetoothDevice> deviceList;
2733            switch(profile) {
2734            case BluetoothProfile.A2DP:
2735                synchronized (mConnectedDevices) {
2736                    synchronized (mA2dpAvrcpLock) {
2737                        mA2dp = (BluetoothA2dp) proxy;
2738                        deviceList = mA2dp.getConnectedDevices();
2739                        if (deviceList.size() > 0) {
2740                            btDevice = deviceList.get(0);
2741                            int state = mA2dp.getConnectionState(btDevice);
2742                            int delay = checkSendBecomingNoisyIntent(
2743                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2744                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2745                            queueMsgUnderWakeLock(mAudioHandler,
2746                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
2747                                    state,
2748                                    0,
2749                                    btDevice,
2750                                    delay);
2751                        }
2752                    }
2753                }
2754                break;
2755
2756            case BluetoothProfile.A2DP_SINK:
2757                deviceList = proxy.getConnectedDevices();
2758                if (deviceList.size() > 0) {
2759                    btDevice = deviceList.get(0);
2760                    synchronized (mConnectedDevices) {
2761                        int state = proxy.getConnectionState(btDevice);
2762                        queueMsgUnderWakeLock(mAudioHandler,
2763                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
2764                                state,
2765                                0,
2766                                btDevice,
2767                                0 /* delay */);
2768                    }
2769                }
2770                break;
2771
2772            case BluetoothProfile.HEADSET:
2773                synchronized (mScoClients) {
2774                    // Discard timeout message
2775                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2776                    mBluetoothHeadset = (BluetoothHeadset) proxy;
2777                    deviceList = mBluetoothHeadset.getConnectedDevices();
2778                    if (deviceList.size() > 0) {
2779                        mBluetoothHeadsetDevice = deviceList.get(0);
2780                    } else {
2781                        mBluetoothHeadsetDevice = null;
2782                    }
2783                    // Refresh SCO audio state
2784                    checkScoAudioState();
2785                    // Continue pending action if any
2786                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2787                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2788                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2789                        boolean status = false;
2790                        if (mBluetoothHeadsetDevice != null) {
2791                            switch (mScoAudioState) {
2792                            case SCO_STATE_ACTIVATE_REQ:
2793                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2794                                if (mScoAudioMode == SCO_MODE_RAW) {
2795                                    status = mBluetoothHeadset.connectAudio();
2796                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2797                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2798                                                                        mBluetoothHeadsetDevice);
2799                                } else if (mScoAudioMode == SCO_MODE_VR) {
2800                                    status = mBluetoothHeadset.startVoiceRecognition(
2801                                                                      mBluetoothHeadsetDevice);
2802                                }
2803                                break;
2804                            case SCO_STATE_DEACTIVATE_REQ:
2805                                if (mScoAudioMode == SCO_MODE_RAW) {
2806                                    status = mBluetoothHeadset.disconnectAudio();
2807                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2808                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2809                                                                        mBluetoothHeadsetDevice);
2810                                } else if (mScoAudioMode == SCO_MODE_VR) {
2811                                    status = mBluetoothHeadset.stopVoiceRecognition(
2812                                                                      mBluetoothHeadsetDevice);
2813                                }
2814                                break;
2815                            case SCO_STATE_DEACTIVATE_EXT_REQ:
2816                                status = mBluetoothHeadset.stopVoiceRecognition(
2817                                        mBluetoothHeadsetDevice);
2818                            }
2819                        }
2820                        if (!status) {
2821                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2822                                    SENDMSG_REPLACE, 0, 0, null, 0);
2823                        }
2824                    }
2825                }
2826                break;
2827
2828            default:
2829                break;
2830            }
2831        }
2832        public void onServiceDisconnected(int profile) {
2833            switch (profile) {
2834            case BluetoothProfile.A2DP:
2835                synchronized (mConnectedDevices) {
2836                    synchronized (mA2dpAvrcpLock) {
2837                        // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
2838                        for(Map.Entry<String, DeviceListSpec> entry
2839                                : mConnectedDevices.entrySet()) {
2840                            DeviceListSpec deviceSpec = entry.getValue();
2841                            if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
2842                                makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
2843                            }
2844                        }
2845                    }
2846                }
2847                break;
2848
2849            case BluetoothProfile.A2DP_SINK:
2850                synchronized (mConnectedDevices) {
2851                    // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
2852                    for(Map.Entry<String, DeviceListSpec> entry
2853                            : mConnectedDevices.entrySet()) {
2854                        DeviceListSpec deviceSpec = entry.getValue();
2855                        if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
2856                            makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
2857                        }
2858                    }
2859                }
2860                break;
2861
2862            case BluetoothProfile.HEADSET:
2863                synchronized (mScoClients) {
2864                    mBluetoothHeadset = null;
2865                }
2866                break;
2867
2868            default:
2869                break;
2870            }
2871        }
2872    };
2873
2874    private void onCheckMusicActive(String caller) {
2875        synchronized (mSafeMediaVolumeState) {
2876            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2877                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2878
2879                if ((device & mSafeMediaVolumeDevices) != 0) {
2880                    sendMsg(mAudioHandler,
2881                            MSG_CHECK_MUSIC_ACTIVE,
2882                            SENDMSG_REPLACE,
2883                            0,
2884                            0,
2885                            caller,
2886                            MUSIC_ACTIVE_POLL_PERIOD_MS);
2887                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2888                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2889                            (index > mSafeMediaVolumeIndex)) {
2890                        // Approximate cumulative active music time
2891                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2892                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2893                            setSafeMediaVolumeEnabled(true, caller);
2894                            mMusicActiveMs = 0;
2895                        }
2896                        saveMusicActiveMs();
2897                    }
2898                }
2899            }
2900        }
2901    }
2902
2903    private void saveMusicActiveMs() {
2904        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2905    }
2906
2907    private void onConfigureSafeVolume(boolean force, String caller) {
2908        synchronized (mSafeMediaVolumeState) {
2909            int mcc = mContext.getResources().getConfiguration().mcc;
2910            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2911                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2912                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2913                boolean safeMediaVolumeEnabled =
2914                        SystemProperties.getBoolean("audio.safemedia.force", false)
2915                        || mContext.getResources().getBoolean(
2916                                com.android.internal.R.bool.config_safe_media_volume_enabled);
2917
2918                // The persisted state is either "disabled" or "active": this is the state applied
2919                // next time we boot and cannot be "inactive"
2920                int persistedState;
2921                if (safeMediaVolumeEnabled) {
2922                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2923                    // The state can already be "inactive" here if the user has forced it before
2924                    // the 30 seconds timeout for forced configuration. In this case we don't reset
2925                    // it to "active".
2926                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2927                        if (mMusicActiveMs == 0) {
2928                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2929                            enforceSafeMediaVolume(caller);
2930                        } else {
2931                            // We have existing playback time recorded, already confirmed.
2932                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2933                        }
2934                    }
2935                } else {
2936                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2937                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2938                }
2939                mMcc = mcc;
2940                sendMsg(mAudioHandler,
2941                        MSG_PERSIST_SAFE_VOLUME_STATE,
2942                        SENDMSG_QUEUE,
2943                        persistedState,
2944                        0,
2945                        null,
2946                        0);
2947            }
2948        }
2949    }
2950
2951    ///////////////////////////////////////////////////////////////////////////
2952    // Internal methods
2953    ///////////////////////////////////////////////////////////////////////////
2954
2955    /**
2956     * Checks if the adjustment should change ringer mode instead of just
2957     * adjusting volume. If so, this will set the proper ringer mode and volume
2958     * indices on the stream states.
2959     */
2960    private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
2961        final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
2962        int result = FLAG_ADJUST_VOLUME;
2963        int ringerMode = getRingerModeInternal();
2964
2965        switch (ringerMode) {
2966        case RINGER_MODE_NORMAL:
2967            if (direction == AudioManager.ADJUST_LOWER) {
2968                if (mHasVibrator) {
2969                    // "step" is the delta in internal index units corresponding to a
2970                    // change of 1 in UI index units.
2971                    // Because of rounding when rescaling from one stream index range to its alias
2972                    // index range, we cannot simply test oldIndex == step:
2973                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2974                    if (step <= oldIndex && oldIndex < 2 * step) {
2975                        ringerMode = RINGER_MODE_VIBRATE;
2976                        mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
2977                    }
2978                } else {
2979                    // (oldIndex < step) is equivalent to (old UI index == 0)
2980                    if ((oldIndex < step)
2981                            && mVolumePolicy.volumeDownToEnterSilent
2982                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2983                        ringerMode = RINGER_MODE_SILENT;
2984                    }
2985                }
2986            } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
2987                    || direction == AudioManager.ADJUST_MUTE)) {
2988                if (mHasVibrator) {
2989                    ringerMode = RINGER_MODE_VIBRATE;
2990                } else {
2991                    ringerMode = RINGER_MODE_SILENT;
2992                }
2993                // Setting the ringer mode will toggle mute
2994                result &= ~FLAG_ADJUST_VOLUME;
2995            }
2996            break;
2997        case RINGER_MODE_VIBRATE:
2998            if (!mHasVibrator) {
2999                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3000                        "but no vibrator is present");
3001                break;
3002            }
3003            if ((direction == AudioManager.ADJUST_LOWER)) {
3004                // This is the case we were muted with the volume turned up
3005                if (isTv && oldIndex >= 2 * step && isMuted) {
3006                    ringerMode = RINGER_MODE_NORMAL;
3007                } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
3008                    if (mVolumePolicy.volumeDownToEnterSilent) {
3009                        final long diff = SystemClock.uptimeMillis()
3010                                - mLoweredFromNormalToVibrateTime;
3011                        if (diff > mVolumePolicy.vibrateToSilentDebounce) {
3012                            ringerMode = RINGER_MODE_SILENT;
3013                        }
3014                    } else {
3015                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3016                    }
3017                }
3018            } else if (direction == AudioManager.ADJUST_RAISE
3019                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
3020                    || direction == AudioManager.ADJUST_UNMUTE) {
3021                ringerMode = RINGER_MODE_NORMAL;
3022            }
3023            result &= ~FLAG_ADJUST_VOLUME;
3024            break;
3025        case RINGER_MODE_SILENT:
3026            if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
3027                // This is the case we were muted with the volume turned up
3028                ringerMode = RINGER_MODE_NORMAL;
3029            } else if (direction == AudioManager.ADJUST_RAISE
3030                    || direction == AudioManager.ADJUST_TOGGLE_MUTE
3031                    || direction == AudioManager.ADJUST_UNMUTE) {
3032                if (!mVolumePolicy.volumeUpToExitSilent) {
3033                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
3034                } else {
3035                  if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
3036                      ringerMode = RINGER_MODE_VIBRATE;
3037                  } else {
3038                      // If we don't have a vibrator or they were toggling mute
3039                      // go straight back to normal.
3040                      ringerMode = RINGER_MODE_NORMAL;
3041                  }
3042                }
3043            }
3044            result &= ~FLAG_ADJUST_VOLUME;
3045            break;
3046        default:
3047            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3048            break;
3049        }
3050
3051        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
3052
3053        mPrevVolDirection = direction;
3054
3055        return result;
3056    }
3057
3058    @Override
3059    public boolean isStreamAffectedByRingerMode(int streamType) {
3060        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
3061    }
3062
3063    private boolean isStreamMutedByRingerMode(int streamType) {
3064        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3065    }
3066
3067    boolean updateRingerModeAffectedStreams() {
3068        int ringerModeAffectedStreams;
3069        // make sure settings for ringer mode are consistent with device type: non voice capable
3070        // devices (tablets) include media stream in silent mode whereas phones don't.
3071        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3072                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3073                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3074                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3075                 UserHandle.USER_CURRENT);
3076
3077        // ringtone, notification and system streams are always affected by ringer mode
3078        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3079                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
3080                                        (1 << AudioSystem.STREAM_SYSTEM);
3081
3082        switch (mPlatformType) {
3083            case AudioSystem.PLATFORM_TELEVISION:
3084                ringerModeAffectedStreams = 0;
3085                break;
3086            default:
3087                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3088                break;
3089        }
3090
3091        synchronized (mCameraSoundForced) {
3092            if (mCameraSoundForced) {
3093                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3094            } else {
3095                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3096            }
3097        }
3098        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3099            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3100        } else {
3101            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3102        }
3103
3104        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3105            Settings.System.putIntForUser(mContentResolver,
3106                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3107                    ringerModeAffectedStreams,
3108                    UserHandle.USER_CURRENT);
3109            mRingerModeAffectedStreams = ringerModeAffectedStreams;
3110            return true;
3111        }
3112        return false;
3113    }
3114
3115    @Override
3116    public boolean isStreamAffectedByMute(int streamType) {
3117        return (mMuteAffectedStreams & (1 << streamType)) != 0;
3118    }
3119
3120    private void ensureValidDirection(int direction) {
3121        switch (direction) {
3122            case AudioManager.ADJUST_LOWER:
3123            case AudioManager.ADJUST_RAISE:
3124            case AudioManager.ADJUST_SAME:
3125            case AudioManager.ADJUST_MUTE:
3126            case AudioManager.ADJUST_UNMUTE:
3127            case AudioManager.ADJUST_TOGGLE_MUTE:
3128                break;
3129            default:
3130                throw new IllegalArgumentException("Bad direction " + direction);
3131        }
3132    }
3133
3134    private void ensureValidSteps(int steps) {
3135        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3136            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3137        }
3138    }
3139
3140    private void ensureValidStreamType(int streamType) {
3141        if (streamType < 0 || streamType >= mStreamStates.length) {
3142            throw new IllegalArgumentException("Bad stream type " + streamType);
3143        }
3144    }
3145
3146    private boolean isMuteAdjust(int adjust) {
3147        return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3148                || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3149    }
3150
3151    private boolean isInCommunication() {
3152        boolean IsInCall = false;
3153
3154        TelecomManager telecomManager =
3155                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
3156
3157        final long ident = Binder.clearCallingIdentity();
3158        IsInCall = telecomManager.isInCall();
3159        Binder.restoreCallingIdentity(ident);
3160
3161        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
3162    }
3163
3164    /**
3165     * For code clarity for getActiveStreamType(int)
3166     * @param delay_ms max time since last STREAM_MUSIC activity to consider
3167     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3168     *     in the last "delay_ms" ms.
3169     */
3170    private boolean isAfMusicActiveRecently(int delay_ms) {
3171        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3172                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3173    }
3174
3175    private int getActiveStreamType(int suggestedStreamType) {
3176        switch (mPlatformType) {
3177        case AudioSystem.PLATFORM_VOICE:
3178            if (isInCommunication()) {
3179                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3180                        == AudioSystem.FORCE_BT_SCO) {
3181                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3182                    return AudioSystem.STREAM_BLUETOOTH_SCO;
3183                } else {
3184                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3185                    return AudioSystem.STREAM_VOICE_CALL;
3186                }
3187            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3188                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
3189                    if (DEBUG_VOL)
3190                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3191                    return AudioSystem.STREAM_MUSIC;
3192                    } else {
3193                        if (DEBUG_VOL)
3194                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3195                        return AudioSystem.STREAM_RING;
3196                }
3197            } else if (isAfMusicActiveRecently(0)) {
3198                if (DEBUG_VOL)
3199                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3200                return AudioSystem.STREAM_MUSIC;
3201            }
3202            break;
3203        case AudioSystem.PLATFORM_TELEVISION:
3204            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3205                    // TV always defaults to STREAM_MUSIC
3206                    return AudioSystem.STREAM_MUSIC;
3207            }
3208            break;
3209        default:
3210            if (isInCommunication()) {
3211                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3212                        == AudioSystem.FORCE_BT_SCO) {
3213                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
3214                    return AudioSystem.STREAM_BLUETOOTH_SCO;
3215                } else {
3216                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
3217                    return AudioSystem.STREAM_VOICE_CALL;
3218                }
3219            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
3220                    StreamOverride.sDelayMs) ||
3221                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
3222                            StreamOverride.sDelayMs)) {
3223                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
3224                return AudioSystem.STREAM_NOTIFICATION;
3225            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3226                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
3227                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3228                    return AudioSystem.STREAM_MUSIC;
3229                } else {
3230                    if (DEBUG_VOL) Log.v(TAG,
3231                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
3232                    return AudioSystem.STREAM_NOTIFICATION;
3233                }
3234            }
3235            break;
3236        }
3237        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3238                + suggestedStreamType);
3239        return suggestedStreamType;
3240    }
3241
3242    private void broadcastRingerMode(String action, int ringerMode) {
3243        // Send sticky broadcast
3244        Intent broadcast = new Intent(action);
3245        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
3246        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3247                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
3248        sendStickyBroadcastToAll(broadcast);
3249    }
3250
3251    private void broadcastVibrateSetting(int vibrateType) {
3252        // Send broadcast
3253        if (ActivityManagerNative.isSystemReady()) {
3254            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3255            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3256            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
3257            sendBroadcastToAll(broadcast);
3258        }
3259    }
3260
3261    // Message helper methods
3262    /**
3263     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3264     * Note that the wake lock needs to be released after the message has been handled.
3265     */
3266    private void queueMsgUnderWakeLock(Handler handler, int msg,
3267            int arg1, int arg2, Object obj, int delay) {
3268        final long ident = Binder.clearCallingIdentity();
3269        // Always acquire the wake lock as AudioService because it is released by the
3270        // message handler.
3271        mAudioEventWakeLock.acquire();
3272        Binder.restoreCallingIdentity(ident);
3273        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3274    }
3275
3276    private static void sendMsg(Handler handler, int msg,
3277            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
3278
3279        if (existingMsgPolicy == SENDMSG_REPLACE) {
3280            handler.removeMessages(msg);
3281        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3282            return;
3283        }
3284        synchronized (mLastDeviceConnectMsgTime) {
3285            long time = SystemClock.uptimeMillis() + delay;
3286            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3287            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3288                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3289                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3290                mLastDeviceConnectMsgTime = time;
3291            }
3292        }
3293    }
3294
3295    boolean checkAudioSettingsPermission(String method) {
3296        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
3297                == PackageManager.PERMISSION_GRANTED) {
3298            return true;
3299        }
3300        String msg = "Audio Settings Permission Denial: " + method + " from pid="
3301                + Binder.getCallingPid()
3302                + ", uid=" + Binder.getCallingUid();
3303        Log.w(TAG, msg);
3304        return false;
3305    }
3306
3307    private int getDeviceForStream(int stream) {
3308        int device = AudioSystem.getDevicesForStream(stream);
3309        if ((device & (device - 1)) != 0) {
3310            // Multiple device selection is either:
3311            //  - speaker + one other device: give priority to speaker in this case.
3312            //  - one A2DP device + another device: happens with duplicated output. In this case
3313            // retain the device on the A2DP output as the other must not correspond to an active
3314            // selection if not the speaker.
3315            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
3316            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3317                device = AudioSystem.DEVICE_OUT_SPEAKER;
3318            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3319                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3320            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3321                device = AudioSystem.DEVICE_OUT_SPDIF;
3322            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3323                device = AudioSystem.DEVICE_OUT_AUX_LINE;
3324            } else {
3325                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3326            }
3327        }
3328        return device;
3329    }
3330
3331    /*
3332     * A class just for packaging up a set of connection parameters.
3333     */
3334    private class WiredDeviceConnectionState {
3335        public final int mType;
3336        public final int mState;
3337        public final String mAddress;
3338        public final String mName;
3339        public final String mCaller;
3340
3341        public WiredDeviceConnectionState(int type, int state, String address, String name,
3342                String caller) {
3343            mType = type;
3344            mState = state;
3345            mAddress = address;
3346            mName = name;
3347            mCaller = caller;
3348        }
3349    }
3350
3351    public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3352            String caller) {
3353        synchronized (mConnectedDevices) {
3354            if (DEBUG_DEVICES) {
3355                Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3356                        + address + ")");
3357            }
3358            int delay = checkSendBecomingNoisyIntent(type, state);
3359            queueMsgUnderWakeLock(mAudioHandler,
3360                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
3361                    0,
3362                    0,
3363                    new WiredDeviceConnectionState(type, state, address, name, caller),
3364                    delay);
3365        }
3366    }
3367
3368    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
3369    {
3370        int delay;
3371        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3372            throw new IllegalArgumentException("invalid profile " + profile);
3373        }
3374        synchronized (mConnectedDevices) {
3375            if (profile == BluetoothProfile.A2DP) {
3376                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3377                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3378            } else {
3379                delay = 0;
3380            }
3381            queueMsgUnderWakeLock(mAudioHandler,
3382                    (profile == BluetoothProfile.A2DP ?
3383                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
3384                    state,
3385                    0,
3386                    device,
3387                    delay);
3388        }
3389        return delay;
3390    }
3391
3392    ///////////////////////////////////////////////////////////////////////////
3393    // Inner classes
3394    ///////////////////////////////////////////////////////////////////////////
3395
3396    // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3397    //  1 mScoclient OR mSafeMediaVolumeState
3398    //  2   mSetModeDeathHandlers
3399    //  3     mSettingsLock
3400    //  4       VolumeStreamState.class
3401    //  5         mCameraSoundForced
3402    public class VolumeStreamState {
3403        private final int mStreamType;
3404        private final int mIndexMin;
3405        private final int mIndexMax;
3406
3407        private boolean mIsMuted;
3408        private String mVolumeIndexSettingName;
3409
3410        private final SparseIntArray mIndexMap = new SparseIntArray(8);
3411        private final Intent mVolumeChanged;
3412
3413        private VolumeStreamState(String settingName, int streamType) {
3414
3415            mVolumeIndexSettingName = settingName;
3416
3417            mStreamType = streamType;
3418            mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3419            mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3420            AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
3421
3422            readSettings();
3423            mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3424            mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3425        }
3426
3427        public String getSettingNameForDevice(int device) {
3428            String name = mVolumeIndexSettingName;
3429            String suffix = AudioSystem.getOutputDeviceName(device);
3430            if (suffix.isEmpty()) {
3431                return name;
3432            }
3433            return name + "_" + suffix;
3434        }
3435
3436        public void readSettings() {
3437            synchronized (VolumeStreamState.class) {
3438                // force maximum volume on all streams if fixed volume property is set
3439                if (mUseFixedVolume) {
3440                    mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3441                    return;
3442                }
3443                // do not read system stream volume from settings: this stream is always aliased
3444                // to another stream type and its volume is never persisted. Values in settings can
3445                // only be stale values
3446                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3447                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3448                    int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
3449                    synchronized (mCameraSoundForced) {
3450                        if (mCameraSoundForced) {
3451                            index = mIndexMax;
3452                        }
3453                    }
3454                    mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3455                    return;
3456                }
3457
3458                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3459
3460                for (int i = 0; remainingDevices != 0; i++) {
3461                    int device = (1 << i);
3462                    if ((device & remainingDevices) == 0) {
3463                        continue;
3464                    }
3465                    remainingDevices &= ~device;
3466
3467                    // retrieve current volume for device
3468                    String name = getSettingNameForDevice(device);
3469                    // if no volume stored for current stream and device, use default volume if default
3470                    // device, continue otherwise
3471                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3472                            AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3473                    int index = Settings.System.getIntForUser(
3474                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3475                    if (index == -1) {
3476                        continue;
3477                    }
3478
3479                    mIndexMap.put(device, getValidIndex(10 * index));
3480                }
3481            }
3482        }
3483
3484        // must be called while synchronized VolumeStreamState.class
3485        public void applyDeviceVolume_syncVSS(int device) {
3486            int index;
3487            if (mIsMuted) {
3488                index = 0;
3489            } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3490                    || ((device & mFullVolumeDevices) != 0)) {
3491                index = (mIndexMax + 5)/10;
3492            } else {
3493                index = (getIndex(device) + 5)/10;
3494            }
3495            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
3496        }
3497
3498        public void applyAllVolumes() {
3499            synchronized (VolumeStreamState.class) {
3500                // apply default volume first: by convention this will reset all
3501                // devices volumes in audio policy manager to the supplied value
3502                int index;
3503                if (mIsMuted) {
3504                    index = 0;
3505                } else {
3506                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3507                }
3508                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3509                // then apply device specific volumes
3510                for (int i = 0; i < mIndexMap.size(); i++) {
3511                    int device = mIndexMap.keyAt(i);
3512                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3513                        if (mIsMuted) {
3514                            index = 0;
3515                        } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3516                                mAvrcpAbsVolSupported)
3517                                    || ((device & mFullVolumeDevices) != 0))
3518                        {
3519                            index = (mIndexMax + 5)/10;
3520                        } else {
3521                            index = (mIndexMap.valueAt(i) + 5)/10;
3522                        }
3523                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
3524                    }
3525                }
3526            }
3527        }
3528
3529        public boolean adjustIndex(int deltaIndex, int device, String caller) {
3530            return setIndex(getIndex(device) + deltaIndex, device, caller);
3531        }
3532
3533        public boolean setIndex(int index, int device, String caller) {
3534            boolean changed = false;
3535            int oldIndex;
3536            synchronized (VolumeStreamState.class) {
3537                oldIndex = getIndex(device);
3538                index = getValidIndex(index);
3539                synchronized (mCameraSoundForced) {
3540                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3541                        index = mIndexMax;
3542                    }
3543                }
3544                mIndexMap.put(device, index);
3545
3546                changed = oldIndex != index;
3547                if (changed) {
3548                    // Apply change to all streams using this one as alias
3549                    // if changing volume of current device, also change volume of current
3550                    // device on aliased stream
3551                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3552                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3553                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3554                        if (streamType != mStreamType &&
3555                                mStreamVolumeAlias[streamType] == mStreamType) {
3556                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3557                            mStreamStates[streamType].setIndex(scaledIndex, device, caller);
3558                            if (currentDevice) {
3559                                mStreamStates[streamType].setIndex(scaledIndex,
3560                                        getDeviceForStream(streamType), caller);
3561                            }
3562                        }
3563                    }
3564                }
3565            }
3566            if (changed) {
3567                oldIndex = (oldIndex + 5) / 10;
3568                index = (index + 5) / 10;
3569                // log base stream changes to the event log
3570                if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3571                    if (caller == null) {
3572                        Log.w(TAG, "No caller for volume_changed event", new Throwable());
3573                    }
3574                    EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
3575                            caller);
3576                }
3577                // fire changed intents for all streams
3578                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3579                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
3580                sendBroadcastToAll(mVolumeChanged);
3581            }
3582            return changed;
3583        }
3584
3585        public int getIndex(int device) {
3586            synchronized (VolumeStreamState.class) {
3587                int index = mIndexMap.get(device, -1);
3588                if (index == -1) {
3589                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3590                    index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
3591                }
3592                return index;
3593            }
3594        }
3595
3596        public int getMaxIndex() {
3597            return mIndexMax;
3598        }
3599
3600        public int getMinIndex() {
3601            return mIndexMin;
3602        }
3603
3604        public void setAllIndexes(VolumeStreamState srcStream, String caller) {
3605            synchronized (VolumeStreamState.class) {
3606                int srcStreamType = srcStream.getStreamType();
3607                // apply default device volume from source stream to all devices first in case
3608                // some devices are present in this stream state but not in source stream state
3609                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
3610                index = rescaleIndex(index, srcStreamType, mStreamType);
3611                for (int i = 0; i < mIndexMap.size(); i++) {
3612                    mIndexMap.put(mIndexMap.keyAt(i), index);
3613                }
3614                // Now apply actual volume for devices in source stream state
3615                SparseIntArray srcMap = srcStream.mIndexMap;
3616                for (int i = 0; i < srcMap.size(); i++) {
3617                    int device = srcMap.keyAt(i);
3618                    index = srcMap.valueAt(i);
3619                    index = rescaleIndex(index, srcStreamType, mStreamType);
3620
3621                    setIndex(index, device, caller);
3622                }
3623            }
3624        }
3625
3626        public void setAllIndexesToMax() {
3627            synchronized (VolumeStreamState.class) {
3628                for (int i = 0; i < mIndexMap.size(); i++) {
3629                    mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
3630                }
3631            }
3632        }
3633
3634        public void mute(boolean state) {
3635            boolean changed = false;
3636            synchronized (VolumeStreamState.class) {
3637                if (state != mIsMuted) {
3638                    changed = true;
3639                    mIsMuted = state;
3640
3641                    // Set the new mute volume. This propagates the values to
3642                    // the audio system, otherwise the volume won't be changed
3643                    // at the lower level.
3644                    sendMsg(mAudioHandler,
3645                            MSG_SET_ALL_VOLUMES,
3646                            SENDMSG_QUEUE,
3647                            0,
3648                            0,
3649                            this, 0);
3650                }
3651            }
3652            if (changed) {
3653                // Stream mute changed, fire the intent.
3654                Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3655                intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3656                intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3657                sendBroadcastToAll(intent);
3658            }
3659        }
3660
3661        public int getStreamType() {
3662            return mStreamType;
3663        }
3664
3665        public void checkFixedVolumeDevices() {
3666            synchronized (VolumeStreamState.class) {
3667                // ignore settings for fixed volume devices: volume should always be at max or 0
3668                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3669                    for (int i = 0; i < mIndexMap.size(); i++) {
3670                        int device = mIndexMap.keyAt(i);
3671                        int index = mIndexMap.valueAt(i);
3672                        if (((device & mFullVolumeDevices) != 0)
3673                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
3674                            mIndexMap.put(device, mIndexMax);
3675                        }
3676                        applyDeviceVolume_syncVSS(device);
3677                    }
3678                }
3679            }
3680        }
3681
3682        private int getValidIndex(int index) {
3683            if (index < mIndexMin) {
3684                return mIndexMin;
3685            } else if (mUseFixedVolume || index > mIndexMax) {
3686                return mIndexMax;
3687            }
3688
3689            return index;
3690        }
3691
3692        private void dump(PrintWriter pw) {
3693            pw.print("   Muted: ");
3694            pw.println(mIsMuted);
3695            pw.print("   Min: ");
3696            pw.println((mIndexMin + 5) / 10);
3697            pw.print("   Max: ");
3698            pw.println((mIndexMax + 5) / 10);
3699            pw.print("   Current: ");
3700            for (int i = 0; i < mIndexMap.size(); i++) {
3701                if (i > 0) {
3702                    pw.print(", ");
3703                }
3704                final int device = mIndexMap.keyAt(i);
3705                pw.print(Integer.toHexString(device));
3706                final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3707                        : AudioSystem.getOutputDeviceName(device);
3708                if (!deviceName.isEmpty()) {
3709                    pw.print(" (");
3710                    pw.print(deviceName);
3711                    pw.print(")");
3712                }
3713                pw.print(": ");
3714                final int index = (mIndexMap.valueAt(i) + 5) / 10;
3715                pw.print(index);
3716            }
3717            pw.println();
3718            pw.print("   Devices: ");
3719            final int devices = AudioSystem.getDevicesForStream(mStreamType);
3720            int device, i = 0, n = 0;
3721            // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
3722            // (the default device is not returned by getDevicesForStream)
3723            while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
3724                if ((devices & device) != 0) {
3725                    if (n++ > 0) {
3726                        pw.print(", ");
3727                    }
3728                    pw.print(AudioSystem.getOutputDeviceName(device));
3729                }
3730                i++;
3731            }
3732        }
3733    }
3734
3735    /** Thread that handles native AudioSystem control. */
3736    private class AudioSystemThread extends Thread {
3737        AudioSystemThread() {
3738            super("AudioService");
3739        }
3740
3741        @Override
3742        public void run() {
3743            // Set this thread up so the handler will work on it
3744            Looper.prepare();
3745
3746            synchronized(AudioService.this) {
3747                mAudioHandler = new AudioHandler();
3748
3749                // Notify that the handler has been created
3750                AudioService.this.notify();
3751            }
3752
3753            // Listen for volume change requests that are set by VolumePanel
3754            Looper.loop();
3755        }
3756    }
3757
3758    /** Handles internal volume messages in separate volume thread. */
3759    private class AudioHandler extends Handler {
3760
3761        private void setDeviceVolume(VolumeStreamState streamState, int device) {
3762
3763            synchronized (VolumeStreamState.class) {
3764                // Apply volume
3765                streamState.applyDeviceVolume_syncVSS(device);
3766
3767                // Apply change to all streams using this one as alias
3768                int numStreamTypes = AudioSystem.getNumStreamTypes();
3769                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3770                    if (streamType != streamState.mStreamType &&
3771                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3772                        // Make sure volume is also maxed out on A2DP device for aliased stream
3773                        // that may have a different device selected
3774                        int streamDevice = getDeviceForStream(streamType);
3775                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3776                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3777                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3778                        }
3779                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
3780                    }
3781                }
3782            }
3783            // Post a persist volume msg
3784            sendMsg(mAudioHandler,
3785                    MSG_PERSIST_VOLUME,
3786                    SENDMSG_QUEUE,
3787                    device,
3788                    0,
3789                    streamState,
3790                    PERSIST_DELAY);
3791
3792        }
3793
3794        private void setAllVolumes(VolumeStreamState streamState) {
3795
3796            // Apply volume
3797            streamState.applyAllVolumes();
3798
3799            // Apply change to all streams using this one as alias
3800            int numStreamTypes = AudioSystem.getNumStreamTypes();
3801            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3802                if (streamType != streamState.mStreamType &&
3803                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3804                    mStreamStates[streamType].applyAllVolumes();
3805                }
3806            }
3807        }
3808
3809        private void persistVolume(VolumeStreamState streamState, int device) {
3810            if (mUseFixedVolume) {
3811                return;
3812            }
3813            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3814                return;
3815            }
3816            System.putIntForUser(mContentResolver,
3817                      streamState.getSettingNameForDevice(device),
3818                      (streamState.getIndex(device) + 5)/ 10,
3819                      UserHandle.USER_CURRENT);
3820        }
3821
3822        private void persistRingerMode(int ringerMode) {
3823            if (mUseFixedVolume) {
3824                return;
3825            }
3826            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
3827        }
3828
3829        private boolean onLoadSoundEffects() {
3830            int status;
3831
3832            synchronized (mSoundEffectsLock) {
3833                if (!mSystemReady) {
3834                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3835                    return false;
3836                }
3837
3838                if (mSoundPool != null) {
3839                    return true;
3840                }
3841
3842                loadTouchSoundAssets();
3843
3844                mSoundPool = new SoundPool.Builder()
3845                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3846                        .setAudioAttributes(new AudioAttributes.Builder()
3847                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3848                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3849                            .build())
3850                        .build();
3851                mSoundPoolCallBack = null;
3852                mSoundPoolListenerThread = new SoundPoolListenerThread();
3853                mSoundPoolListenerThread.start();
3854                int attempts = 3;
3855                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3856                    try {
3857                        // Wait for mSoundPoolCallBack to be set by the other thread
3858                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
3859                    } catch (InterruptedException e) {
3860                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3861                    }
3862                }
3863
3864                if (mSoundPoolCallBack == null) {
3865                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3866                    if (mSoundPoolLooper != null) {
3867                        mSoundPoolLooper.quit();
3868                        mSoundPoolLooper = null;
3869                    }
3870                    mSoundPoolListenerThread = null;
3871                    mSoundPool.release();
3872                    mSoundPool = null;
3873                    return false;
3874                }
3875                /*
3876                 * poolId table: The value -1 in this table indicates that corresponding
3877                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3878                 * Once loaded, the value in poolId is the sample ID and the same
3879                 * sample can be reused for another effect using the same file.
3880                 */
3881                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3882                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3883                    poolId[fileIdx] = -1;
3884                }
3885                /*
3886                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3887                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3888                 * this indicates we have a valid sample loaded for this effect.
3889                 */
3890
3891                int numSamples = 0;
3892                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3893                    // Do not load sample if this effect uses the MediaPlayer
3894                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3895                        continue;
3896                    }
3897                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3898                        String filePath = Environment.getRootDirectory()
3899                                + SOUND_EFFECTS_PATH
3900                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3901                        int sampleId = mSoundPool.load(filePath, 0);
3902                        if (sampleId <= 0) {
3903                            Log.w(TAG, "Soundpool could not load file: "+filePath);
3904                        } else {
3905                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3906                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3907                            numSamples++;
3908                        }
3909                    } else {
3910                        SOUND_EFFECT_FILES_MAP[effect][1] =
3911                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3912                    }
3913                }
3914                // wait for all samples to be loaded
3915                if (numSamples > 0) {
3916                    mSoundPoolCallBack.setSamples(poolId);
3917
3918                    attempts = 3;
3919                    status = 1;
3920                    while ((status == 1) && (attempts-- > 0)) {
3921                        try {
3922                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
3923                            status = mSoundPoolCallBack.status();
3924                        } catch (InterruptedException e) {
3925                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
3926                        }
3927                    }
3928                } else {
3929                    status = -1;
3930                }
3931
3932                if (mSoundPoolLooper != null) {
3933                    mSoundPoolLooper.quit();
3934                    mSoundPoolLooper = null;
3935                }
3936                mSoundPoolListenerThread = null;
3937                if (status != 0) {
3938                    Log.w(TAG,
3939                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
3940                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3941                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3942                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3943                        }
3944                    }
3945
3946                    mSoundPool.release();
3947                    mSoundPool = null;
3948                }
3949            }
3950            return (status == 0);
3951        }
3952
3953        /**
3954         *  Unloads samples from the sound pool.
3955         *  This method can be called to free some memory when
3956         *  sound effects are disabled.
3957         */
3958        private void onUnloadSoundEffects() {
3959            synchronized (mSoundEffectsLock) {
3960                if (mSoundPool == null) {
3961                    return;
3962                }
3963
3964                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3965                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3966                    poolId[fileIdx] = 0;
3967                }
3968
3969                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3970                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3971                        continue;
3972                    }
3973                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3974                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3975                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3976                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3977                    }
3978                }
3979                mSoundPool.release();
3980                mSoundPool = null;
3981            }
3982        }
3983
3984        private void onPlaySoundEffect(int effectType, int volume) {
3985            synchronized (mSoundEffectsLock) {
3986
3987                onLoadSoundEffects();
3988
3989                if (mSoundPool == null) {
3990                    return;
3991                }
3992                float volFloat;
3993                // use default if volume is not specified by caller
3994                if (volume < 0) {
3995                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3996                } else {
3997                    volFloat = volume / 1000.0f;
3998                }
3999
4000                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
4001                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4002                                        volFloat, volFloat, 0, 0, 1.0f);
4003                } else {
4004                    MediaPlayer mediaPlayer = new MediaPlayer();
4005                    try {
4006                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4007                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
4008                        mediaPlayer.setDataSource(filePath);
4009                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4010                        mediaPlayer.prepare();
4011                        mediaPlayer.setVolume(volFloat);
4012                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4013                            public void onCompletion(MediaPlayer mp) {
4014                                cleanupPlayer(mp);
4015                            }
4016                        });
4017                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
4018                            public boolean onError(MediaPlayer mp, int what, int extra) {
4019                                cleanupPlayer(mp);
4020                                return true;
4021                            }
4022                        });
4023                        mediaPlayer.start();
4024                    } catch (IOException ex) {
4025                        Log.w(TAG, "MediaPlayer IOException: "+ex);
4026                    } catch (IllegalArgumentException ex) {
4027                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4028                    } catch (IllegalStateException ex) {
4029                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4030                    }
4031                }
4032            }
4033        }
4034
4035        private void cleanupPlayer(MediaPlayer mp) {
4036            if (mp != null) {
4037                try {
4038                    mp.stop();
4039                    mp.release();
4040                } catch (IllegalStateException ex) {
4041                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4042                }
4043            }
4044        }
4045
4046        private void setForceUse(int usage, int config) {
4047            synchronized (mConnectedDevices) {
4048                setForceUseInt_SyncDevices(usage, config);
4049            }
4050        }
4051
4052        private void onPersistSafeVolumeState(int state) {
4053            Settings.Global.putInt(mContentResolver,
4054                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4055                    state);
4056        }
4057
4058        @Override
4059        public void handleMessage(Message msg) {
4060            switch (msg.what) {
4061
4062                case MSG_SET_DEVICE_VOLUME:
4063                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4064                    break;
4065
4066                case MSG_SET_ALL_VOLUMES:
4067                    setAllVolumes((VolumeStreamState) msg.obj);
4068                    break;
4069
4070                case MSG_PERSIST_VOLUME:
4071                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
4072                    break;
4073
4074                case MSG_PERSIST_MASTER_VOLUME_MUTE:
4075                    if (mUseFixedVolume) {
4076                        return;
4077                    }
4078                    Settings.System.putIntForUser(mContentResolver,
4079                                                 Settings.System.VOLUME_MASTER_MUTE,
4080                                                 msg.arg1,
4081                                                 msg.arg2);
4082                    break;
4083
4084                case MSG_PERSIST_RINGER_MODE:
4085                    // note that the value persisted is the current ringer mode, not the
4086                    // value of ringer mode as of the time the request was made to persist
4087                    persistRingerMode(getRingerModeInternal());
4088                    break;
4089
4090                case MSG_MEDIA_SERVER_DIED:
4091                    if (!mSystemReady ||
4092                            (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
4093                        Log.e(TAG, "Media server died.");
4094                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
4095                                null, 500);
4096                        break;
4097                    }
4098                    Log.e(TAG, "Media server started.");
4099
4100                    // indicate to audio HAL that we start the reconfiguration phase after a media
4101                    // server crash
4102                    // Note that we only execute this when the media server
4103                    // process restarts after a crash, not the first time it is started.
4104                    AudioSystem.setParameters("restarting=true");
4105
4106                    readAndSetLowRamDevice();
4107
4108                    // Restore device connection states
4109                    synchronized (mConnectedDevices) {
4110                        Set set = mConnectedDevices.entrySet();
4111                        Iterator i = set.iterator();
4112                        while (i.hasNext()) {
4113                            Map.Entry device = (Map.Entry)i.next();
4114                            DeviceListSpec spec = (DeviceListSpec)device.getValue();
4115                            AudioSystem.setDeviceConnectionState(
4116                                                            spec.mDeviceType,
4117                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
4118                                                            spec.mDeviceAddress,
4119                                                            spec.mDeviceName);
4120                        }
4121                    }
4122                    // Restore call state
4123                    AudioSystem.setPhoneState(mMode);
4124
4125                    // Restore forced usage for communcations and record
4126                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
4127                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
4128                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4129                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
4130
4131                    // Restore stream volumes
4132                    int numStreamTypes = AudioSystem.getNumStreamTypes();
4133                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4134                        VolumeStreamState streamState = mStreamStates[streamType];
4135                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
4136
4137                        streamState.applyAllVolumes();
4138                    }
4139
4140                    // Restore ringer mode
4141                    setRingerModeInt(getRingerModeInternal(), false);
4142
4143                    // Reset device orientation (if monitored for this device)
4144                    if (mMonitorOrientation) {
4145                        setOrientationForAudioSystem();
4146                    }
4147                    if (mMonitorRotation) {
4148                        setRotationForAudioSystem();
4149                    }
4150
4151                    synchronized (mBluetoothA2dpEnabledLock) {
4152                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4153                                mBluetoothA2dpEnabled ?
4154                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4155                    }
4156
4157                    synchronized (mSettingsLock) {
4158                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4159                                mDockAudioMediaEnabled ?
4160                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4161                    }
4162                    if (mHdmiManager != null) {
4163                        synchronized (mHdmiManager) {
4164                            if (mHdmiTvClient != null) {
4165                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4166                            }
4167                        }
4168                    }
4169
4170                    synchronized (mAudioPolicies) {
4171                        for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4172                            policy.connectMixes();
4173                        }
4174                    }
4175
4176                    // indicate the end of reconfiguration phase to audio HAL
4177                    AudioSystem.setParameters("restarting=false");
4178                    break;
4179
4180                case MSG_UNLOAD_SOUND_EFFECTS:
4181                    onUnloadSoundEffects();
4182                    break;
4183
4184                case MSG_LOAD_SOUND_EFFECTS:
4185                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4186                    // can take several dozens of milliseconds to complete
4187                    boolean loaded = onLoadSoundEffects();
4188                    if (msg.obj != null) {
4189                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4190                        synchronized (reply) {
4191                            reply.mStatus = loaded ? 0 : -1;
4192                            reply.notify();
4193                        }
4194                    }
4195                    break;
4196
4197                case MSG_PLAY_SOUND_EFFECT:
4198                    onPlaySoundEffect(msg.arg1, msg.arg2);
4199                    break;
4200
4201                case MSG_BTA2DP_DOCK_TIMEOUT:
4202                    // msg.obj  == address of BTA2DP device
4203                    synchronized (mConnectedDevices) {
4204                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
4205                    }
4206                    break;
4207
4208                case MSG_SET_FORCE_USE:
4209                case MSG_SET_FORCE_BT_A2DP_USE:
4210                    setForceUse(msg.arg1, msg.arg2);
4211                    break;
4212
4213                case MSG_BT_HEADSET_CNCT_FAILED:
4214                    resetBluetoothSco();
4215                    break;
4216
4217                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4218                    {   WiredDeviceConnectionState connectState =
4219                            (WiredDeviceConnectionState)msg.obj;
4220                        onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4221                                connectState.mAddress, connectState.mName, connectState.mCaller);
4222                        mAudioEventWakeLock.release();
4223                    }
4224                    break;
4225
4226                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4227                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4228                    mAudioEventWakeLock.release();
4229                    break;
4230
4231                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4232                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4233                    mAudioEventWakeLock.release();
4234                    break;
4235
4236                case MSG_REPORT_NEW_ROUTES: {
4237                    int N = mRoutesObservers.beginBroadcast();
4238                    if (N > 0) {
4239                        AudioRoutesInfo routes;
4240                        synchronized (mCurAudioRoutes) {
4241                            routes = new AudioRoutesInfo(mCurAudioRoutes);
4242                        }
4243                        while (N > 0) {
4244                            N--;
4245                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4246                            try {
4247                                obs.dispatchAudioRoutesChanged(routes);
4248                            } catch (RemoteException e) {
4249                            }
4250                        }
4251                    }
4252                    mRoutesObservers.finishBroadcast();
4253                    break;
4254                }
4255
4256                case MSG_CHECK_MUSIC_ACTIVE:
4257                    onCheckMusicActive((String) msg.obj);
4258                    break;
4259
4260                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4261                    onSendBecomingNoisyIntent();
4262                    break;
4263
4264                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4265                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4266                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4267                            (String) msg.obj);
4268                    break;
4269                case MSG_PERSIST_SAFE_VOLUME_STATE:
4270                    onPersistSafeVolumeState(msg.arg1);
4271                    break;
4272
4273                case MSG_BROADCAST_BT_CONNECTION_STATE:
4274                    onBroadcastScoConnectionState(msg.arg1);
4275                    break;
4276
4277                case MSG_SYSTEM_READY:
4278                    onSystemReady();
4279                    break;
4280
4281                case MSG_PERSIST_MUSIC_ACTIVE_MS:
4282                    final int musicActiveMs = msg.arg1;
4283                    Settings.Secure.putIntForUser(mContentResolver,
4284                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4285                            UserHandle.USER_CURRENT);
4286                    break;
4287                case MSG_PERSIST_MICROPHONE_MUTE:
4288                    Settings.System.putIntForUser(mContentResolver,
4289                                                 Settings.System.MICROPHONE_MUTE,
4290                                                 msg.arg1,
4291                                                 msg.arg2);
4292                    break;
4293                case MSG_UNMUTE_STREAM:
4294                    onUnmuteStream(msg.arg1, msg.arg2);
4295                    break;
4296            }
4297        }
4298    }
4299
4300    private class SettingsObserver extends ContentObserver {
4301
4302        SettingsObserver() {
4303            super(new Handler());
4304            mContentResolver.registerContentObserver(Settings.System.getUriFor(
4305                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
4306            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4307                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
4308        }
4309
4310        @Override
4311        public void onChange(boolean selfChange) {
4312            super.onChange(selfChange);
4313            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4314            //       However there appear to be some missing locks around mRingerModeMutedStreams
4315            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
4316            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
4317            synchronized (mSettingsLock) {
4318                if (updateRingerModeAffectedStreams()) {
4319                    /*
4320                     * Ensure all stream types that should be affected by ringer mode
4321                     * are in the proper state.
4322                     */
4323                    setRingerModeInt(getRingerModeInternal(), false);
4324                }
4325                readDockAudioSettings(mContentResolver);
4326            }
4327        }
4328    }
4329
4330    // must be called synchronized on mConnectedDevices
4331    private void makeA2dpDeviceAvailable(String address) {
4332        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4333        // audio policy manager
4334        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4335        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4336                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
4337        setBluetoothA2dpOnInt(true);
4338        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4339                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
4340        // Reset A2DP suspend state each time a new sink is connected
4341        AudioSystem.setParameters("A2dpSuspended=false");
4342        mConnectedDevices.put(
4343                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
4344                new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
4345                                   address));
4346    }
4347
4348    private void onSendBecomingNoisyIntent() {
4349        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
4350    }
4351
4352    // must be called synchronized on mConnectedDevices
4353    private void makeA2dpDeviceUnavailableNow(String address) {
4354        synchronized (mA2dpAvrcpLock) {
4355            mAvrcpAbsVolSupported = false;
4356        }
4357        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4358                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
4359        mConnectedDevices.remove(
4360                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
4361        synchronized (mCurAudioRoutes) {
4362            // Remove A2DP routes as well
4363            if (mCurAudioRoutes.bluetoothName != null) {
4364                mCurAudioRoutes.bluetoothName = null;
4365                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4366                        SENDMSG_NOOP, 0, 0, null, 0);
4367            }
4368        }
4369    }
4370
4371    // must be called synchronized on mConnectedDevices
4372    private void makeA2dpDeviceUnavailableLater(String address) {
4373        // prevent any activity on the A2DP audio output to avoid unwanted
4374        // reconnection of the sink.
4375        AudioSystem.setParameters("A2dpSuspended=true");
4376        // the device will be made unavailable later, so consider it disconnected right away
4377        mConnectedDevices.remove(
4378                makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
4379        // send the delayed message to make the device unavailable later
4380        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4381        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4382
4383    }
4384
4385    // must be called synchronized on mConnectedDevices
4386    private void makeA2dpSrcAvailable(String address) {
4387        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4388                AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
4389        mConnectedDevices.put(
4390                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
4391                new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
4392                                   address));
4393    }
4394
4395    // must be called synchronized on mConnectedDevices
4396    private void makeA2dpSrcUnavailable(String address) {
4397        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4398                AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
4399        mConnectedDevices.remove(
4400                makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
4401    }
4402
4403    // must be called synchronized on mConnectedDevices
4404    private void cancelA2dpDeviceTimeout() {
4405        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4406    }
4407
4408    // must be called synchronized on mConnectedDevices
4409    private boolean hasScheduledA2dpDockTimeout() {
4410        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4411    }
4412
4413    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
4414    {
4415        if (DEBUG_VOL) {
4416            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4417        }
4418        if (btDevice == null) {
4419            return;
4420        }
4421        String address = btDevice.getAddress();
4422        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4423            address = "";
4424        }
4425
4426        synchronized (mConnectedDevices) {
4427            String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4428                                           btDevice.getAddress());
4429            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4430            boolean isConnected = deviceSpec != null;
4431
4432            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4433                if (btDevice.isBluetoothDock()) {
4434                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
4435                        // introduction of a delay for transient disconnections of docks when
4436                        // power is rapidly turned off/on, this message will be canceled if
4437                        // we reconnect the dock under a preset delay
4438                        makeA2dpDeviceUnavailableLater(address);
4439                        // the next time isConnected is evaluated, it will be false for the dock
4440                    }
4441                } else {
4442                    makeA2dpDeviceUnavailableNow(address);
4443                }
4444                synchronized (mCurAudioRoutes) {
4445                    if (mCurAudioRoutes.bluetoothName != null) {
4446                        mCurAudioRoutes.bluetoothName = null;
4447                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4448                                SENDMSG_NOOP, 0, 0, null, 0);
4449                    }
4450                }
4451            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4452                if (btDevice.isBluetoothDock()) {
4453                    // this could be a reconnection after a transient disconnection
4454                    cancelA2dpDeviceTimeout();
4455                    mDockAddress = address;
4456                } else {
4457                    // this could be a connection of another A2DP device before the timeout of
4458                    // a dock: cancel the dock timeout, and make the dock unavailable now
4459                    if(hasScheduledA2dpDockTimeout()) {
4460                        cancelA2dpDeviceTimeout();
4461                        makeA2dpDeviceUnavailableNow(mDockAddress);
4462                    }
4463                }
4464                makeA2dpDeviceAvailable(address);
4465                synchronized (mCurAudioRoutes) {
4466                    String name = btDevice.getAliasName();
4467                    if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4468                        mCurAudioRoutes.bluetoothName = name;
4469                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4470                                SENDMSG_NOOP, 0, 0, null, 0);
4471                    }
4472                }
4473            }
4474        }
4475    }
4476
4477    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4478    {
4479        if (DEBUG_VOL) {
4480            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4481        }
4482        if (btDevice == null) {
4483            return;
4484        }
4485        String address = btDevice.getAddress();
4486        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4487            address = "";
4488        }
4489
4490        synchronized (mConnectedDevices) {
4491            String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4492            DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4493            boolean isConnected = deviceSpec != null;
4494
4495            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4496                makeA2dpSrcUnavailable(address);
4497            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4498                makeA2dpSrcAvailable(address);
4499            }
4500        }
4501    }
4502
4503    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4504        // address is not used for now, but may be used when multiple a2dp devices are supported
4505        synchronized (mA2dpAvrcpLock) {
4506            mAvrcpAbsVolSupported = support;
4507            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4508                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4509                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4510            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4511                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4512                    mStreamStates[AudioSystem.STREAM_RING], 0);
4513        }
4514    }
4515
4516    private boolean handleDeviceConnection(boolean connect, int device, String address,
4517            String deviceName) {
4518        if (DEBUG_DEVICES) {
4519            Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4520                    + " address:" + address + " name:" + deviceName + ")");
4521        }
4522        synchronized (mConnectedDevices) {
4523            String deviceKey = makeDeviceListKey(device, address);
4524            if (DEBUG_DEVICES) {
4525                Slog.i(TAG, "deviceKey:" + deviceKey);
4526            }
4527            DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4528            boolean isConnected = deviceSpec != null;
4529            if (DEBUG_DEVICES) {
4530                Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4531            }
4532            if (connect && !isConnected) {
4533                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
4534                        address, deviceName);
4535                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4536                return true;
4537            } else if (!connect && isConnected) {
4538                AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
4539                        address, deviceName);
4540                mConnectedDevices.remove(deviceKey);
4541                return true;
4542            }
4543        }
4544        return false;
4545    }
4546
4547    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4548    // sent if none of these devices is connected.
4549    // Access synchronized on mConnectedDevices
4550    int mBecomingNoisyIntentDevices =
4551            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4552            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4553            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4554            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
4555
4556    // must be called before removing the device from mConnectedDevices
4557    // Called synchronized on mConnectedDevices
4558    private int checkSendBecomingNoisyIntent(int device, int state) {
4559        int delay = 0;
4560        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4561            int devices = 0;
4562            for (String key : mConnectedDevices.keySet()) {
4563                int dev = mConnectedDevices.get(key).mDeviceType;
4564                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4565                        && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4566                    devices |= dev;
4567                }
4568            }
4569            if (devices == device) {
4570                sendMsg(mAudioHandler,
4571                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4572                        SENDMSG_REPLACE,
4573                        0,
4574                        0,
4575                        null,
4576                        0);
4577                delay = 1000;
4578            }
4579        }
4580
4581        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4582                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4583                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4584            synchronized (mLastDeviceConnectMsgTime) {
4585                long time = SystemClock.uptimeMillis();
4586                if (mLastDeviceConnectMsgTime > time) {
4587                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
4588                }
4589            }
4590        }
4591        return delay;
4592    }
4593
4594    private void sendDeviceConnectionIntent(int device, int state, String address,
4595            String deviceName) {
4596        if (DEBUG_DEVICES) {
4597            Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4598                    " state:0x" + Integer.toHexString(state) + " address:" + address +
4599                    " name:" + deviceName + ");");
4600        }
4601        Intent intent = new Intent();
4602
4603        intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4604        intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4605        intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4606
4607        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4608
4609        int connType = 0;
4610
4611        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4612            connType = AudioRoutesInfo.MAIN_HEADSET;
4613            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4614            intent.putExtra("microphone", 1);
4615        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4616                   device == AudioSystem.DEVICE_OUT_LINE) {
4617            /*do apps care about line-out vs headphones?*/
4618            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4619            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4620            intent.putExtra("microphone", 0);
4621        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4622                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
4623            connType = AudioRoutesInfo.MAIN_HDMI;
4624            configureHdmiPlugIntent(intent, state);
4625        } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4626            connType = AudioRoutesInfo.MAIN_USB;
4627        }
4628
4629        synchronized (mCurAudioRoutes) {
4630            if (connType != 0) {
4631                int newConn = mCurAudioRoutes.mainType;
4632                if (state != 0) {
4633                    newConn |= connType;
4634                } else {
4635                    newConn &= ~connType;
4636                }
4637                if (newConn != mCurAudioRoutes.mainType) {
4638                    mCurAudioRoutes.mainType = newConn;
4639                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4640                            SENDMSG_NOOP, 0, 0, null, 0);
4641                }
4642            }
4643        }
4644
4645        final long ident = Binder.clearCallingIdentity();
4646        try {
4647            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4648        } finally {
4649            Binder.restoreCallingIdentity(ident);
4650        }
4651    }
4652
4653    private void onSetWiredDeviceConnectionState(int device, int state, String address,
4654            String deviceName, String caller) {
4655        if (DEBUG_DEVICES) {
4656            Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4657                    + " state:" + Integer.toHexString(state)
4658                    + " address:" + address
4659                    + " deviceName:" + deviceName
4660                    + " caller: " + caller + ");");
4661        }
4662
4663        synchronized (mConnectedDevices) {
4664            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4665                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4666                    (device == AudioSystem.DEVICE_OUT_LINE))) {
4667                setBluetoothA2dpOnInt(true);
4668            }
4669            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4670                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4671                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4672            handleDeviceConnection(state == 1, device, address, deviceName);
4673            if (state != 0) {
4674                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4675                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4676                    (device == AudioSystem.DEVICE_OUT_LINE)) {
4677                    setBluetoothA2dpOnInt(false);
4678                }
4679                if ((device & mSafeMediaVolumeDevices) != 0) {
4680                    sendMsg(mAudioHandler,
4681                            MSG_CHECK_MUSIC_ACTIVE,
4682                            SENDMSG_REPLACE,
4683                            0,
4684                            0,
4685                            caller,
4686                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4687                }
4688                // Television devices without CEC service apply software volume on HDMI output
4689                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4690                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4691                    checkAllFixedVolumeDevices();
4692                    if (mHdmiManager != null) {
4693                        synchronized (mHdmiManager) {
4694                            if (mHdmiPlaybackClient != null) {
4695                                mHdmiCecSink = false;
4696                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4697                            }
4698                        }
4699                    }
4700                }
4701            } else {
4702                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4703                    if (mHdmiManager != null) {
4704                        synchronized (mHdmiManager) {
4705                            mHdmiCecSink = false;
4706                        }
4707                    }
4708                }
4709            }
4710            if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4711                sendDeviceConnectionIntent(device, state, address, deviceName);
4712            }
4713        }
4714    }
4715
4716    private void configureHdmiPlugIntent(Intent intent, int state) {
4717        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4718        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
4719        if (state == 1) {
4720            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4721            int[] portGeneration = new int[1];
4722            int status = AudioSystem.listAudioPorts(ports, portGeneration);
4723            if (status == AudioManager.SUCCESS) {
4724                for (AudioPort port : ports) {
4725                    if (port instanceof AudioDevicePort) {
4726                        final AudioDevicePort devicePort = (AudioDevicePort) port;
4727                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4728                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
4729                            // format the list of supported encodings
4730                            int[] formats = devicePort.formats();
4731                            if (formats.length > 0) {
4732                                ArrayList<Integer> encodingList = new ArrayList(1);
4733                                for (int format : formats) {
4734                                    // a format in the list can be 0, skip it
4735                                    if (format != AudioFormat.ENCODING_INVALID) {
4736                                        encodingList.add(format);
4737                                    }
4738                                }
4739                                int[] encodingArray = new int[encodingList.size()];
4740                                for (int i = 0 ; i < encodingArray.length ; i++) {
4741                                    encodingArray[i] = encodingList.get(i);
4742                                }
4743                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
4744                            }
4745                            // find the maximum supported number of channels
4746                            int maxChannels = 0;
4747                            for (int mask : devicePort.channelMasks()) {
4748                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4749                                if (channelCount > maxChannels) {
4750                                    maxChannels = channelCount;
4751                                }
4752                            }
4753                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
4754                        }
4755                    }
4756                }
4757            }
4758        }
4759    }
4760
4761    /* cache of the address of the last dock the device was connected to */
4762    private String mDockAddress;
4763
4764    /**
4765     * Receiver for misc intent broadcasts the Phone app cares about.
4766     */
4767    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4768        @Override
4769        public void onReceive(Context context, Intent intent) {
4770            String action = intent.getAction();
4771            int outDevice;
4772            int inDevice;
4773            int state;
4774
4775            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4776                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4777                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4778                int config;
4779                switch (dockState) {
4780                    case Intent.EXTRA_DOCK_STATE_DESK:
4781                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4782                        break;
4783                    case Intent.EXTRA_DOCK_STATE_CAR:
4784                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4785                        break;
4786                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
4787                        config = AudioSystem.FORCE_ANALOG_DOCK;
4788                        break;
4789                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
4790                        config = AudioSystem.FORCE_DIGITAL_DOCK;
4791                        break;
4792                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4793                    default:
4794                        config = AudioSystem.FORCE_NONE;
4795                }
4796                // Low end docks have a menu to enable or disable audio
4797                // (see mDockAudioMediaEnabled)
4798                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4799                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4800                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4801                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4802                }
4803                mDockState = dockState;
4804            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
4805                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
4806                                               BluetoothProfile.STATE_DISCONNECTED);
4807                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4808                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
4809                String address = null;
4810
4811                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4812                if (btDevice == null) {
4813                    return;
4814                }
4815
4816                address = btDevice.getAddress();
4817                BluetoothClass btClass = btDevice.getBluetoothClass();
4818                if (btClass != null) {
4819                    switch (btClass.getDeviceClass()) {
4820                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4821                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4822                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4823                        break;
4824                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4825                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4826                        break;
4827                    }
4828                }
4829
4830                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4831                    address = "";
4832                }
4833
4834                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4835                boolean success =
4836                    handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4837                    handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
4838                if (success) {
4839                    synchronized (mScoClients) {
4840                        if (connected) {
4841                            mBluetoothHeadsetDevice = btDevice;
4842                        } else {
4843                            mBluetoothHeadsetDevice = null;
4844                            resetBluetoothSco();
4845                        }
4846                    }
4847                }
4848            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
4849                boolean broadcast = false;
4850                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
4851                synchronized (mScoClients) {
4852                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4853                    // broadcast intent if the connection was initated by AudioService
4854                    if (!mScoClients.isEmpty() &&
4855                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4856                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4857                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
4858                        broadcast = true;
4859                    }
4860                    switch (btState) {
4861                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
4862                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4863                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4864                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4865                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4866                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4867                        }
4868                        break;
4869                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
4870                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
4871                        mScoAudioState = SCO_STATE_INACTIVE;
4872                        clearAllScoClients(0, false);
4873                        break;
4874                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4875                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4876                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4877                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4878                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4879                        }
4880                    default:
4881                        // do not broadcast CONNECTING or invalid state
4882                        broadcast = false;
4883                        break;
4884                    }
4885                }
4886                if (broadcast) {
4887                    broadcastScoConnectionState(scoAudioState);
4888                    //FIXME: this is to maintain compatibility with deprecated intent
4889                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4890                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4891                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
4892                    sendStickyBroadcastToAll(newIntent);
4893                }
4894            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4895                if (mMonitorRotation) {
4896                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4897                    mOrientationListener.enable();
4898                }
4899                AudioSystem.setParameters("screen_state=on");
4900            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4901                if (mMonitorRotation) {
4902                    //reduce wakeups (save current) by only listening when display is on
4903                    mOrientationListener.disable();
4904                }
4905                AudioSystem.setParameters("screen_state=off");
4906            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4907                handleConfigurationChanged(context);
4908            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4909                // attempt to stop music playback for background user
4910                sendMsg(mAudioHandler,
4911                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4912                        SENDMSG_REPLACE,
4913                        0,
4914                        0,
4915                        null,
4916                        0);
4917                // the current audio focus owner is no longer valid
4918                mMediaFocusControl.discardAudioFocusOwner();
4919
4920                // load volume settings for new user
4921                readAudioSettings(true /*userSwitch*/);
4922                // preserve STREAM_MUSIC volume from one user to the next.
4923                sendMsg(mAudioHandler,
4924                        MSG_SET_ALL_VOLUMES,
4925                        SENDMSG_QUEUE,
4926                        0,
4927                        0,
4928                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4929            }
4930        }
4931    } // end class AudioServiceBroadcastReceiver
4932
4933    //==========================================================================================
4934    // RemoteControlDisplay / RemoteControlClient / Remote info
4935    //==========================================================================================
4936    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4937            ComponentName listenerComp) {
4938        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4939    }
4940
4941    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4942        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4943    }
4944
4945    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4946        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4947    }
4948
4949    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4950        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4951    }
4952
4953    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4954            boolean wantsSync) {
4955        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4956    }
4957
4958    @Override
4959    public void setRemoteStreamVolume(int index) {
4960        enforceVolumeController("set the remote stream volume");
4961        mMediaFocusControl.setRemoteStreamVolume(index);
4962    }
4963
4964    //==========================================================================================
4965    // Audio Focus
4966    //==========================================================================================
4967    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
4968            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
4969            IAudioPolicyCallback pcb) {
4970        // permission checks
4971        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
4972            if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
4973                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
4974                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
4975                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
4976                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4977                }
4978            } else {
4979                // only a registered audio policy can be used to lock focus
4980                synchronized (mAudioPolicies) {
4981                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
4982                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
4983                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4984                    }
4985                }
4986            }
4987        }
4988
4989        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
4990                clientId, callingPackageName, flags);
4991    }
4992
4993    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
4994        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
4995    }
4996
4997    public void unregisterAudioFocusClient(String clientId) {
4998        mMediaFocusControl.unregisterAudioFocusClient(clientId);
4999    }
5000
5001    public int getCurrentAudioFocus() {
5002        return mMediaFocusControl.getCurrentAudioFocus();
5003    }
5004
5005    private boolean readCameraSoundForced() {
5006        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5007                mContext.getResources().getBoolean(
5008                        com.android.internal.R.bool.config_camera_sound_forced);
5009    }
5010
5011    //==========================================================================================
5012    // Device orientation
5013    //==========================================================================================
5014    /**
5015     * Handles device configuration changes that may map to a change in the orientation
5016     * or orientation.
5017     * Monitoring orientation and rotation is optional, and is defined by the definition and value
5018     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
5019     */
5020    private void handleConfigurationChanged(Context context) {
5021        try {
5022            // reading new orientation "safely" (i.e. under try catch) in case anything
5023            // goes wrong when obtaining resources and configuration
5024            Configuration config = context.getResources().getConfiguration();
5025            // TODO merge rotation and orientation
5026            if (mMonitorOrientation) {
5027                int newOrientation = config.orientation;
5028                if (newOrientation != mDeviceOrientation) {
5029                    mDeviceOrientation = newOrientation;
5030                    setOrientationForAudioSystem();
5031                }
5032            }
5033            sendMsg(mAudioHandler,
5034                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5035                    SENDMSG_REPLACE,
5036                    0,
5037                    0,
5038                    TAG,
5039                    0);
5040
5041            boolean cameraSoundForced = readCameraSoundForced();
5042            synchronized (mSettingsLock) {
5043                boolean cameraSoundForcedChanged = false;
5044                synchronized (mCameraSoundForced) {
5045                    if (cameraSoundForced != mCameraSoundForced) {
5046                        mCameraSoundForced = cameraSoundForced;
5047                        cameraSoundForcedChanged = true;
5048                    }
5049                }
5050                if (cameraSoundForcedChanged) {
5051                    if (!isPlatformTelevision()) {
5052                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5053                        if (cameraSoundForced) {
5054                            s.setAllIndexesToMax();
5055                            mRingerModeAffectedStreams &=
5056                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5057                        } else {
5058                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
5059                            mRingerModeAffectedStreams |=
5060                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5061                        }
5062                        // take new state into account for streams muted by ringer mode
5063                        setRingerModeInt(getRingerModeInternal(), false);
5064                    }
5065
5066                    sendMsg(mAudioHandler,
5067                            MSG_SET_FORCE_USE,
5068                            SENDMSG_QUEUE,
5069                            AudioSystem.FOR_SYSTEM,
5070                            cameraSoundForced ?
5071                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5072                            null,
5073                            0);
5074
5075                    sendMsg(mAudioHandler,
5076                            MSG_SET_ALL_VOLUMES,
5077                            SENDMSG_QUEUE,
5078                            0,
5079                            0,
5080                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5081                }
5082            }
5083            mVolumeController.setLayoutDirection(config.getLayoutDirection());
5084        } catch (Exception e) {
5085            Log.e(TAG, "Error handling configuration change: ", e);
5086        }
5087    }
5088
5089    private void setOrientationForAudioSystem() {
5090        switch (mDeviceOrientation) {
5091            case Configuration.ORIENTATION_LANDSCAPE:
5092                //Log.i(TAG, "orientation is landscape");
5093                AudioSystem.setParameters("orientation=landscape");
5094                break;
5095            case Configuration.ORIENTATION_PORTRAIT:
5096                //Log.i(TAG, "orientation is portrait");
5097                AudioSystem.setParameters("orientation=portrait");
5098                break;
5099            case Configuration.ORIENTATION_SQUARE:
5100                //Log.i(TAG, "orientation is square");
5101                AudioSystem.setParameters("orientation=square");
5102                break;
5103            case Configuration.ORIENTATION_UNDEFINED:
5104                //Log.i(TAG, "orientation is undefined");
5105                AudioSystem.setParameters("orientation=undefined");
5106                break;
5107            default:
5108                Log.e(TAG, "Unknown orientation");
5109        }
5110    }
5111
5112    private void setRotationForAudioSystem() {
5113        switch (mDeviceRotation) {
5114            case Surface.ROTATION_0:
5115                AudioSystem.setParameters("rotation=0");
5116                break;
5117            case Surface.ROTATION_90:
5118                AudioSystem.setParameters("rotation=90");
5119                break;
5120            case Surface.ROTATION_180:
5121                AudioSystem.setParameters("rotation=180");
5122                break;
5123            case Surface.ROTATION_270:
5124                AudioSystem.setParameters("rotation=270");
5125                break;
5126            default:
5127                Log.e(TAG, "Unknown device rotation");
5128        }
5129    }
5130
5131
5132    // Handles request to override default use of A2DP for media.
5133    // Must be called synchronized on mConnectedDevices
5134    public void setBluetoothA2dpOnInt(boolean on) {
5135        synchronized (mBluetoothA2dpEnabledLock) {
5136            mBluetoothA2dpEnabled = on;
5137            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5138            setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
5139                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5140        }
5141    }
5142
5143    // Must be called synchronized on mConnectedDevices
5144    private void setForceUseInt_SyncDevices(int usage, int config) {
5145        switch (usage) {
5146            case AudioSystem.FOR_MEDIA:
5147                if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5148                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5149                } else { // config == AudioSystem.FORCE_NONE
5150                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5151                }
5152                break;
5153            case AudioSystem.FOR_DOCK:
5154                if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5155                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5156                } else { // config == AudioSystem.FORCE_NONE
5157                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5158                }
5159                break;
5160            default:
5161                // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5162        }
5163        AudioSystem.setForceUse(usage, config);
5164    }
5165
5166    @Override
5167    public void setRingtonePlayer(IRingtonePlayer player) {
5168        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5169        mRingtonePlayer = player;
5170    }
5171
5172    @Override
5173    public IRingtonePlayer getRingtonePlayer() {
5174        return mRingtonePlayer;
5175    }
5176
5177    @Override
5178    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5179        synchronized (mCurAudioRoutes) {
5180            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5181            mRoutesObservers.register(observer);
5182            return routes;
5183        }
5184    }
5185
5186
5187    //==========================================================================================
5188    // Safe media volume management.
5189    // MUSIC stream volume level is limited when headphones are connected according to safety
5190    // regulation. When the user attempts to raise the volume above the limit, a warning is
5191    // displayed and the user has to acknowlegde before the volume is actually changed.
5192    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5193    // property. Platforms with a different limit must set this property accordingly in their
5194    // overlay.
5195    //==========================================================================================
5196
5197    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5198    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5199    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5200    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5201    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5202    // (when user opts out).
5203    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5204    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5205    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
5206    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
5207    private Integer mSafeMediaVolumeState;
5208
5209    private int mMcc = 0;
5210    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
5211    private int mSafeMediaVolumeIndex;
5212    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5213    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5214                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5215    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5216    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5217    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5218    private int mMusicActiveMs;
5219    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5220    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
5221    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
5222
5223    private void setSafeMediaVolumeEnabled(boolean on, String caller) {
5224        synchronized (mSafeMediaVolumeState) {
5225            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5226                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5227                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5228                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5229                    enforceSafeMediaVolume(caller);
5230                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5231                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
5232                    mMusicActiveMs = 1;  // nonzero = confirmed
5233                    saveMusicActiveMs();
5234                    sendMsg(mAudioHandler,
5235                            MSG_CHECK_MUSIC_ACTIVE,
5236                            SENDMSG_REPLACE,
5237                            0,
5238                            0,
5239                            caller,
5240                            MUSIC_ACTIVE_POLL_PERIOD_MS);
5241                }
5242            }
5243        }
5244    }
5245
5246    private void enforceSafeMediaVolume(String caller) {
5247        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5248        int devices = mSafeMediaVolumeDevices;
5249        int i = 0;
5250
5251        while (devices != 0) {
5252            int device = 1 << i++;
5253            if ((device & devices) == 0) {
5254                continue;
5255            }
5256            int index = streamState.getIndex(device);
5257            if (index > mSafeMediaVolumeIndex) {
5258                streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
5259                sendMsg(mAudioHandler,
5260                        MSG_SET_DEVICE_VOLUME,
5261                        SENDMSG_QUEUE,
5262                        device,
5263                        0,
5264                        streamState,
5265                        0);
5266            }
5267            devices &= ~device;
5268        }
5269    }
5270
5271    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
5272        synchronized (mSafeMediaVolumeState) {
5273            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
5274                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5275                    ((device & mSafeMediaVolumeDevices) != 0) &&
5276                    (index > mSafeMediaVolumeIndex)) {
5277                return false;
5278            }
5279            return true;
5280        }
5281    }
5282
5283    @Override
5284    public void disableSafeMediaVolume(String callingPackage) {
5285        enforceVolumeController("disable the safe media volume");
5286        synchronized (mSafeMediaVolumeState) {
5287            setSafeMediaVolumeEnabled(false, callingPackage);
5288            if (mPendingVolumeCommand != null) {
5289                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5290                                  mPendingVolumeCommand.mIndex,
5291                                  mPendingVolumeCommand.mFlags,
5292                                  mPendingVolumeCommand.mDevice,
5293                                  callingPackage);
5294                mPendingVolumeCommand = null;
5295            }
5296        }
5297    }
5298
5299    //==========================================================================================
5300    // Hdmi Cec system audio mode.
5301    // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5302    // to HdmiControlService so that the audio receiver can handle it.
5303    //==========================================================================================
5304
5305    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5306        public void onComplete(int status) {
5307            if (mHdmiManager != null) {
5308                synchronized (mHdmiManager) {
5309                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5310                    // Television devices without CEC service apply software volume on HDMI output
5311                    if (isPlatformTelevision() && !mHdmiCecSink) {
5312                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5313                    }
5314                    checkAllFixedVolumeDevices();
5315                }
5316            }
5317        }
5318    };
5319
5320    // If HDMI-CEC system audio is supported
5321    private boolean mHdmiSystemAudioSupported = false;
5322    // Set only when device is tv.
5323    private HdmiTvClient mHdmiTvClient;
5324    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
5325    // cached HdmiControlManager interface
5326    private HdmiControlManager mHdmiManager;
5327    // Set only when device is a set-top box.
5328    private HdmiPlaybackClient mHdmiPlaybackClient;
5329    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5330    private boolean mHdmiCecSink;
5331
5332    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
5333
5334    @Override
5335    public int setHdmiSystemAudioSupported(boolean on) {
5336        int device = AudioSystem.DEVICE_NONE;
5337        if (mHdmiManager != null) {
5338            synchronized (mHdmiManager) {
5339                if (mHdmiTvClient == null) {
5340                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5341                    return device;
5342                }
5343
5344                synchronized (mHdmiTvClient) {
5345                    if (mHdmiSystemAudioSupported != on) {
5346                        mHdmiSystemAudioSupported = on;
5347                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5348                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5349                                     AudioSystem.FORCE_NONE);
5350                    }
5351                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5352                }
5353            }
5354        }
5355        return device;
5356    }
5357
5358    @Override
5359    public boolean isHdmiSystemAudioSupported() {
5360        return mHdmiSystemAudioSupported;
5361    }
5362
5363    //==========================================================================================
5364    // Accessibility: taking touch exploration into account for selecting the default
5365    //   stream override timeout when adjusting volume
5366    //==========================================================================================
5367    private static class StreamOverride
5368            implements AccessibilityManager.TouchExplorationStateChangeListener {
5369
5370        // AudioService.getActiveStreamType() will return:
5371        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5372        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5373        // stopped
5374        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5375        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5376
5377        static int sDelayMs;
5378
5379        static void init(Context ctxt) {
5380            AccessibilityManager accessibilityManager =
5381                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5382            updateDefaultStreamOverrideDelay(
5383                    accessibilityManager.isTouchExplorationEnabled());
5384            accessibilityManager.addTouchExplorationStateChangeListener(
5385                    new StreamOverride());
5386        }
5387
5388        @Override
5389        public void onTouchExplorationStateChanged(boolean enabled) {
5390            updateDefaultStreamOverrideDelay(enabled);
5391        }
5392
5393        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5394            if (touchExploreEnabled) {
5395                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5396            } else {
5397                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5398            }
5399            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5400                    + " stream override delay is now " + sDelayMs + " ms");
5401        }
5402    }
5403
5404    //==========================================================================================
5405    // Camera shutter sound policy.
5406    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5407    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5408    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5409    //==========================================================================================
5410
5411    // cached value of com.android.internal.R.bool.config_camera_sound_forced
5412    private Boolean mCameraSoundForced;
5413
5414    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5415    public boolean isCameraSoundForced() {
5416        synchronized (mCameraSoundForced) {
5417            return mCameraSoundForced;
5418        }
5419    }
5420
5421    private static final String[] RINGER_MODE_NAMES = new String[] {
5422            "SILENT",
5423            "VIBRATE",
5424            "NORMAL"
5425    };
5426
5427    private void dumpRingerMode(PrintWriter pw) {
5428        pw.println("\nRinger mode: ");
5429        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5430        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
5431        pw.print("- ringer mode affected streams = 0x");
5432        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5433        pw.print("- ringer mode muted streams = 0x");
5434        pw.println(Integer.toHexString(mRingerModeMutedStreams));
5435        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
5436    }
5437
5438    @Override
5439    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5440        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5441
5442        mMediaFocusControl.dump(pw);
5443        dumpStreamStates(pw);
5444        dumpRingerMode(pw);
5445        pw.println("\nAudio routes:");
5446        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5447        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
5448
5449        pw.println("\nOther state:");
5450        pw.print("  mVolumeController="); pw.println(mVolumeController);
5451        pw.print("  mSafeMediaVolumeState=");
5452        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5453        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5454        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5455        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
5456        pw.print("  mMcc="); pw.println(mMcc);
5457        pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
5458        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
5459        pw.print("  mControllerService="); pw.println(mControllerService);
5460        pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
5461
5462        dumpAudioPolicies(pw);
5463    }
5464
5465    private static String safeMediaVolumeStateToString(Integer state) {
5466        switch(state) {
5467            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5468            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5469            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5470            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5471        }
5472        return null;
5473    }
5474
5475    // Inform AudioFlinger of our device's low RAM attribute
5476    private static void readAndSetLowRamDevice()
5477    {
5478        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5479        if (status != 0) {
5480            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5481        }
5482    }
5483
5484    private void enforceVolumeController(String action) {
5485        if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5486            return;
5487        }
5488        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5489                "Only SystemUI can " + action);
5490    }
5491
5492    @Override
5493    public void setVolumeController(final IVolumeController controller) {
5494        enforceVolumeController("set the volume controller");
5495
5496        // return early if things are not actually changing
5497        if (mVolumeController.isSameBinder(controller)) {
5498            return;
5499        }
5500
5501        // dismiss the old volume controller
5502        mVolumeController.postDismiss();
5503        if (controller != null) {
5504            // we are about to register a new controller, listen for its death
5505            try {
5506                controller.asBinder().linkToDeath(new DeathRecipient() {
5507                    @Override
5508                    public void binderDied() {
5509                        if (mVolumeController.isSameBinder(controller)) {
5510                            Log.w(TAG, "Current remote volume controller died, unregistering");
5511                            setVolumeController(null);
5512                        }
5513                    }
5514                }, 0);
5515            } catch (RemoteException e) {
5516                // noop
5517            }
5518        }
5519        mVolumeController.setController(controller);
5520        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5521    }
5522
5523    @Override
5524    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5525        enforceVolumeController("notify about volume controller visibility");
5526
5527        // return early if the controller is not current
5528        if (!mVolumeController.isSameBinder(controller)) {
5529            return;
5530        }
5531
5532        mVolumeController.setVisible(visible);
5533        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
5534    }
5535
5536    @Override
5537    public void setVolumePolicy(VolumePolicy policy) {
5538        enforceVolumeController("set volume policy");
5539        if (policy != null) {
5540            mVolumePolicy = policy;
5541        }
5542    }
5543
5544    public static class VolumeController {
5545        private static final String TAG = "VolumeController";
5546
5547        private IVolumeController mController;
5548        private boolean mVisible;
5549        private long mNextLongPress;
5550        private int mLongPressTimeout;
5551
5552        public void setController(IVolumeController controller) {
5553            mController = controller;
5554            mVisible = false;
5555        }
5556
5557        public void loadSettings(ContentResolver cr) {
5558            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5559                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5560        }
5561
5562        public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5563            if (isMute) {
5564                return false;
5565            }
5566            boolean suppress = false;
5567            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5568                final long now = SystemClock.uptimeMillis();
5569                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5570                    // ui will become visible
5571                    if (mNextLongPress < now) {
5572                        mNextLongPress = now + mLongPressTimeout;
5573                    }
5574                    suppress = true;
5575                } else if (mNextLongPress > 0) {  // in a long-press
5576                    if (now > mNextLongPress) {
5577                        // long press triggered, no more suppression
5578                        mNextLongPress = 0;
5579                    } else {
5580                        // keep suppressing until the long press triggers
5581                        suppress = true;
5582                    }
5583                }
5584            }
5585            return suppress;
5586        }
5587
5588        public void setVisible(boolean visible) {
5589            mVisible = visible;
5590        }
5591
5592        public boolean isSameBinder(IVolumeController controller) {
5593            return Objects.equals(asBinder(), binder(controller));
5594        }
5595
5596        public IBinder asBinder() {
5597            return binder(mController);
5598        }
5599
5600        private static IBinder binder(IVolumeController controller) {
5601            return controller == null ? null : controller.asBinder();
5602        }
5603
5604        @Override
5605        public String toString() {
5606            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
5607        }
5608
5609        public void postDisplaySafeVolumeWarning(int flags) {
5610            if (mController == null)
5611                return;
5612            try {
5613                mController.displaySafeVolumeWarning(flags);
5614            } catch (RemoteException e) {
5615                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5616            }
5617        }
5618
5619        public void postVolumeChanged(int streamType, int flags) {
5620            if (mController == null)
5621                return;
5622            try {
5623                mController.volumeChanged(streamType, flags);
5624            } catch (RemoteException e) {
5625                Log.w(TAG, "Error calling volumeChanged", e);
5626            }
5627        }
5628
5629        public void postMasterMuteChanged(int flags) {
5630            if (mController == null)
5631                return;
5632            try {
5633                mController.masterMuteChanged(flags);
5634            } catch (RemoteException e) {
5635                Log.w(TAG, "Error calling masterMuteChanged", e);
5636            }
5637        }
5638
5639        public void setLayoutDirection(int layoutDirection) {
5640            if (mController == null)
5641                return;
5642            try {
5643                mController.setLayoutDirection(layoutDirection);
5644            } catch (RemoteException e) {
5645                Log.w(TAG, "Error calling setLayoutDirection", e);
5646            }
5647        }
5648
5649        public void postDismiss() {
5650            if (mController == null)
5651                return;
5652            try {
5653                mController.dismiss();
5654            } catch (RemoteException e) {
5655                Log.w(TAG, "Error calling dismiss", e);
5656            }
5657        }
5658    }
5659
5660    /**
5661     * Interface for system components to get some extra functionality through
5662     * LocalServices.
5663     */
5664    final class AudioServiceInternal extends AudioManagerInternal {
5665        @Override
5666        public void setRingerModeDelegate(RingerModeDelegate delegate) {
5667            mRingerModeDelegate = delegate;
5668            if (mRingerModeDelegate != null) {
5669                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5670            }
5671        }
5672
5673        @Override
5674        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5675                String callingPackage, int uid) {
5676            // direction and stream type swap here because the public
5677            // adjustSuggested has a different order than the other methods.
5678            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
5679                    callingPackage, uid);
5680        }
5681
5682        @Override
5683        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5684                String callingPackage, int uid) {
5685            adjustStreamVolume(streamType, direction, flags, callingPackage,
5686                    callingPackage, uid);
5687        }
5688
5689        @Override
5690        public void setStreamVolumeForUid(int streamType, int direction, int flags,
5691                String callingPackage, int uid) {
5692            setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
5693        }
5694
5695        @Override
5696        public int getRingerModeInternal() {
5697            return AudioService.this.getRingerModeInternal();
5698        }
5699
5700        @Override
5701        public void setRingerModeInternal(int ringerMode, String caller) {
5702            AudioService.this.setRingerModeInternal(ringerMode, caller);
5703        }
5704
5705        @Override
5706        public int getVolumeControllerUid() {
5707            return mControllerService.mUid;
5708        }
5709    }
5710
5711    //==========================================================================================
5712    // Audio policy management
5713    //==========================================================================================
5714    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5715            boolean hasFocusListener) {
5716        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5717                + " with config:" + policyConfig);
5718        String regId = null;
5719        // error handling
5720        boolean hasPermissionForPolicy =
5721                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5722                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5723        if (!hasPermissionForPolicy) {
5724            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5725                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5726            return null;
5727        }
5728
5729        synchronized (mAudioPolicies) {
5730            try {
5731                if (mAudioPolicies.containsKey(pcb.asBinder())) {
5732                    Slog.e(TAG, "Cannot re-register policy");
5733                    return null;
5734                }
5735                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5736                pcb.asBinder().linkToDeath(app, 0/*flags*/);
5737                regId = app.getRegistrationId();
5738                mAudioPolicies.put(pcb.asBinder(), app);
5739            } catch (RemoteException e) {
5740                // audio policy owner has already died!
5741                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
5742                        " binder death", e);
5743                return null;
5744            }
5745        }
5746        return regId;
5747    }
5748
5749    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5750        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
5751        synchronized (mAudioPolicies) {
5752            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
5753            if (app == null) {
5754                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5755                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5756                return;
5757            } else {
5758                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
5759            }
5760            app.release();
5761        }
5762        // TODO implement clearing mix attribute matching info in native audio policy
5763    }
5764
5765    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5766        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5767                + " policy " +  pcb.asBinder());
5768        // error handling
5769        boolean hasPermissionForPolicy =
5770                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5771                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5772        if (!hasPermissionForPolicy) {
5773            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5774                    + Binder.getCallingPid() + " / uid "
5775                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5776            return AudioManager.ERROR;
5777        }
5778
5779        synchronized (mAudioPolicies) {
5780            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5781                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5782                return AudioManager.ERROR;
5783            }
5784            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5785            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5786                // is there already one policy managing ducking?
5787                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5788                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5789                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5790                        return AudioManager.ERROR;
5791                    }
5792                }
5793            }
5794            app.mFocusDuckBehavior = duckingBehavior;
5795            mMediaFocusControl.setDuckingInExtPolicyAvailable(
5796                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5797        }
5798        return AudioManager.SUCCESS;
5799    }
5800
5801    private void dumpAudioPolicies(PrintWriter pw) {
5802        pw.println("\nAudio policies:");
5803        synchronized (mAudioPolicies) {
5804            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5805                pw.println(policy.toLogFriendlyString());
5806            }
5807        }
5808    }
5809
5810    //======================
5811    // Audio policy proxy
5812    //======================
5813    /**
5814     * This internal class inherits from AudioPolicyConfig, each instance contains all the
5815     * mixes of an AudioPolicy and their configurations.
5816     */
5817    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
5818        private static final String TAG = "AudioPolicyProxy";
5819        AudioPolicyConfig mConfig;
5820        IAudioPolicyCallback mPolicyToken;
5821        boolean mHasFocusListener;
5822        /**
5823         * Audio focus ducking behavior for an audio policy.
5824         * This variable reflects the value that was successfully set in
5825         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5826         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5827         * is handling ducking for audio focus.
5828         */
5829        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5830
5831        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5832                boolean hasFocusListener) {
5833            super(config);
5834            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
5835            mPolicyToken = token;
5836            mHasFocusListener = hasFocusListener;
5837            if (mHasFocusListener) {
5838                mMediaFocusControl.addFocusFollower(mPolicyToken);
5839            }
5840            connectMixes();
5841        }
5842
5843        public void binderDied() {
5844            synchronized (mAudioPolicies) {
5845                Log.i(TAG, "audio policy " + mPolicyToken + " died");
5846                release();
5847                mAudioPolicies.remove(mPolicyToken.asBinder());
5848            }
5849        }
5850
5851        String getRegistrationId() {
5852            return getRegistration();
5853        }
5854
5855        void release() {
5856            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5857                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5858            }
5859            if (mHasFocusListener) {
5860                mMediaFocusControl.removeFocusFollower(mPolicyToken);
5861            }
5862            AudioSystem.registerPolicyMixes(mMixes, false);
5863        }
5864
5865        void connectMixes() {
5866            AudioSystem.registerPolicyMixes(mMixes, true);
5867        }
5868    };
5869
5870    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5871            new HashMap<IBinder, AudioPolicyProxy>();
5872    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
5873
5874    private class ControllerService extends ContentObserver {
5875        private int mUid;
5876        private ComponentName mComponent;
5877
5878        public ControllerService() {
5879            super(null);
5880        }
5881
5882        @Override
5883        public String toString() {
5884            return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5885        }
5886
5887        public void init() {
5888            onChange(true);
5889            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5890                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5891        }
5892
5893        @Override
5894        public void onChange(boolean selfChange) {
5895            mUid = 0;
5896            mComponent = null;
5897            final String setting = Settings.Secure.getString(mContentResolver,
5898                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5899            if (setting == null) return;
5900            try {
5901                mComponent = ComponentName.unflattenFromString(setting);
5902                if (mComponent == null) return;
5903                mUid = mContext.getPackageManager()
5904                        .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5905            } catch (Exception e) {
5906                Log.w(TAG, "Error loading controller service", e);
5907            }
5908            if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5909        }
5910    }
5911}
5912