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