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