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