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