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                final int res = AudioSystem.setDeviceConnectionState(device,
4734                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
4735                if (res != AudioSystem.AUDIO_STATUS_OK) {
4736                    Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
4737                            " due to command error " + res );
4738                    return false;
4739                }
4740                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4741                return true;
4742            } else if (!connect && isConnected) {
4743                AudioSystem.setDeviceConnectionState(device,
4744                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
4745                // always remove even if disconnection failed
4746                mConnectedDevices.remove(deviceKey);
4747                return true;
4748            }
4749        }
4750        return false;
4751    }
4752
4753    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4754    // sent if none of these devices is connected.
4755    // Access synchronized on mConnectedDevices
4756    int mBecomingNoisyIntentDevices =
4757            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4758            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4759            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4760            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
4761
4762    // must be called before removing the device from mConnectedDevices
4763    // Called synchronized on mConnectedDevices
4764    private int checkSendBecomingNoisyIntent(int device, int state) {
4765        int delay = 0;
4766        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4767            int devices = 0;
4768            for (int i = 0; i < mConnectedDevices.size(); i++) {
4769                int dev = mConnectedDevices.valueAt(i).mDeviceType;
4770                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4771                        && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4772                    devices |= dev;
4773                }
4774            }
4775            if (devices == device) {
4776                sendMsg(mAudioHandler,
4777                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4778                        SENDMSG_REPLACE,
4779                        0,
4780                        0,
4781                        null,
4782                        0);
4783                delay = 1000;
4784            }
4785        }
4786
4787        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4788                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4789                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4790            synchronized (mLastDeviceConnectMsgTime) {
4791                long time = SystemClock.uptimeMillis();
4792                if (mLastDeviceConnectMsgTime > time) {
4793                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
4794                }
4795            }
4796        }
4797        return delay;
4798    }
4799
4800    private void sendDeviceConnectionIntent(int device, int state, String address,
4801            String deviceName) {
4802        if (DEBUG_DEVICES) {
4803            Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4804                    " state:0x" + Integer.toHexString(state) + " address:" + address +
4805                    " name:" + deviceName + ");");
4806        }
4807        Intent intent = new Intent();
4808
4809        intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4810        intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4811        intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4812
4813        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4814
4815        int connType = 0;
4816
4817        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4818            connType = AudioRoutesInfo.MAIN_HEADSET;
4819            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4820            intent.putExtra("microphone", 1);
4821        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4822                   device == AudioSystem.DEVICE_OUT_LINE) {
4823            /*do apps care about line-out vs headphones?*/
4824            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4825            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4826            intent.putExtra("microphone", 0);
4827        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4828                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
4829            connType = AudioRoutesInfo.MAIN_HDMI;
4830            configureHdmiPlugIntent(intent, state);
4831        } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4832            connType = AudioRoutesInfo.MAIN_USB;
4833        }
4834
4835        synchronized (mCurAudioRoutes) {
4836            if (connType != 0) {
4837                int newConn = mCurAudioRoutes.mainType;
4838                if (state != 0) {
4839                    newConn |= connType;
4840                } else {
4841                    newConn &= ~connType;
4842                }
4843                if (newConn != mCurAudioRoutes.mainType) {
4844                    mCurAudioRoutes.mainType = newConn;
4845                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4846                            SENDMSG_NOOP, 0, 0, null, 0);
4847                }
4848            }
4849        }
4850
4851        final long ident = Binder.clearCallingIdentity();
4852        try {
4853            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4854        } finally {
4855            Binder.restoreCallingIdentity(ident);
4856        }
4857    }
4858
4859    private void onSetWiredDeviceConnectionState(int device, int state, String address,
4860            String deviceName, String caller) {
4861        if (DEBUG_DEVICES) {
4862            Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4863                    + " state:" + Integer.toHexString(state)
4864                    + " address:" + address
4865                    + " deviceName:" + deviceName
4866                    + " caller: " + caller + ");");
4867        }
4868
4869        synchronized (mConnectedDevices) {
4870            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4871                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4872                    (device == AudioSystem.DEVICE_OUT_LINE))) {
4873                setBluetoothA2dpOnInt(true);
4874            }
4875            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4876                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4877                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4878            if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
4879                // change of connection state failed, bailout
4880                return;
4881            }
4882            if (state != 0) {
4883                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4884                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4885                    (device == AudioSystem.DEVICE_OUT_LINE)) {
4886                    setBluetoothA2dpOnInt(false);
4887                }
4888                if ((device & mSafeMediaVolumeDevices) != 0) {
4889                    sendMsg(mAudioHandler,
4890                            MSG_CHECK_MUSIC_ACTIVE,
4891                            SENDMSG_REPLACE,
4892                            0,
4893                            0,
4894                            caller,
4895                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4896                }
4897                // Television devices without CEC service apply software volume on HDMI output
4898                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4899                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4900                    checkAllFixedVolumeDevices();
4901                    if (mHdmiManager != null) {
4902                        synchronized (mHdmiManager) {
4903                            if (mHdmiPlaybackClient != null) {
4904                                mHdmiCecSink = false;
4905                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4906                            }
4907                        }
4908                    }
4909                }
4910            } else {
4911                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4912                    if (mHdmiManager != null) {
4913                        synchronized (mHdmiManager) {
4914                            mHdmiCecSink = false;
4915                        }
4916                    }
4917                }
4918            }
4919            if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4920                sendDeviceConnectionIntent(device, state, address, deviceName);
4921            }
4922        }
4923    }
4924
4925    private void configureHdmiPlugIntent(Intent intent, int state) {
4926        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4927        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
4928        if (state == 1) {
4929            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4930            int[] portGeneration = new int[1];
4931            int status = AudioSystem.listAudioPorts(ports, portGeneration);
4932            if (status == AudioManager.SUCCESS) {
4933                for (AudioPort port : ports) {
4934                    if (port instanceof AudioDevicePort) {
4935                        final AudioDevicePort devicePort = (AudioDevicePort) port;
4936                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4937                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
4938                            // format the list of supported encodings
4939                            int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
4940                            if (formats.length > 0) {
4941                                ArrayList<Integer> encodingList = new ArrayList(1);
4942                                for (int format : formats) {
4943                                    // a format in the list can be 0, skip it
4944                                    if (format != AudioFormat.ENCODING_INVALID) {
4945                                        encodingList.add(format);
4946                                    }
4947                                }
4948                                int[] encodingArray = new int[encodingList.size()];
4949                                for (int i = 0 ; i < encodingArray.length ; i++) {
4950                                    encodingArray[i] = encodingList.get(i);
4951                                }
4952                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
4953                            }
4954                            // find the maximum supported number of channels
4955                            int maxChannels = 0;
4956                            for (int mask : devicePort.channelMasks()) {
4957                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4958                                if (channelCount > maxChannels) {
4959                                    maxChannels = channelCount;
4960                                }
4961                            }
4962                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
4963                        }
4964                    }
4965                }
4966            }
4967        }
4968    }
4969
4970    /* cache of the address of the last dock the device was connected to */
4971    private String mDockAddress;
4972
4973    /**
4974     * Receiver for misc intent broadcasts the Phone app cares about.
4975     */
4976    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4977        @Override
4978        public void onReceive(Context context, Intent intent) {
4979            String action = intent.getAction();
4980            int outDevice;
4981            int inDevice;
4982            int state;
4983
4984            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4985                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4986                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4987                int config;
4988                switch (dockState) {
4989                    case Intent.EXTRA_DOCK_STATE_DESK:
4990                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4991                        break;
4992                    case Intent.EXTRA_DOCK_STATE_CAR:
4993                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4994                        break;
4995                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
4996                        config = AudioSystem.FORCE_ANALOG_DOCK;
4997                        break;
4998                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
4999                        config = AudioSystem.FORCE_DIGITAL_DOCK;
5000                        break;
5001                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5002                    default:
5003                        config = AudioSystem.FORCE_NONE;
5004                }
5005                // Low end docks have a menu to enable or disable audio
5006                // (see mDockAudioMediaEnabled)
5007                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5008                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5009                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5010                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5011                }
5012                mDockState = dockState;
5013            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
5014                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
5015                                               BluetoothProfile.STATE_DISCONNECTED);
5016                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
5017
5018                setBtScoDeviceConnectionState(btDevice, state);
5019            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
5020                boolean broadcast = false;
5021                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
5022                synchronized (mScoClients) {
5023                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
5024                    // broadcast intent if the connection was initated by AudioService
5025                    if (!mScoClients.isEmpty() &&
5026                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5027                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5028                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
5029                        broadcast = true;
5030                    }
5031                    switch (btState) {
5032                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
5033                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
5034                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5035                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5036                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
5037                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
5038                        }
5039                        break;
5040                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
5041                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
5042                        mScoAudioState = SCO_STATE_INACTIVE;
5043                        clearAllScoClients(0, false);
5044                        break;
5045                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
5046                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5047                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5048                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
5049                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
5050                        }
5051                    default:
5052                        // do not broadcast CONNECTING or invalid state
5053                        broadcast = false;
5054                        break;
5055                    }
5056                }
5057                if (broadcast) {
5058                    broadcastScoConnectionState(scoAudioState);
5059                    //FIXME: this is to maintain compatibility with deprecated intent
5060                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
5061                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
5062                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
5063                    sendStickyBroadcastToAll(newIntent);
5064                }
5065            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
5066                if (mMonitorRotation) {
5067                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
5068                    mOrientationListener.enable();
5069                }
5070                AudioSystem.setParameters("screen_state=on");
5071            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
5072                if (mMonitorRotation) {
5073                    //reduce wakeups (save current) by only listening when display is on
5074                    mOrientationListener.disable();
5075                }
5076                AudioSystem.setParameters("screen_state=off");
5077            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
5078                handleConfigurationChanged(context);
5079            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
5080                // attempt to stop music playback for background user
5081                sendMsg(mAudioHandler,
5082                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5083                        SENDMSG_REPLACE,
5084                        0,
5085                        0,
5086                        null,
5087                        0);
5088                // the current audio focus owner is no longer valid
5089                mMediaFocusControl.discardAudioFocusOwner();
5090
5091                // load volume settings for new user
5092                readAudioSettings(true /*userSwitch*/);
5093                // preserve STREAM_MUSIC volume from one user to the next.
5094                sendMsg(mAudioHandler,
5095                        MSG_SET_ALL_VOLUMES,
5096                        SENDMSG_QUEUE,
5097                        0,
5098                        0,
5099                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5100            } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5101                // Disable audio recording for the background user/profile
5102                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5103                if (userId >= 0) {
5104                    // TODO Kill recording streams instead of killing processes holding permission
5105                    UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5106                    killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5107                }
5108                UserManagerService.getInstance().setSystemControlledUserRestriction(
5109                        UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5110            } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5111                // Enable audio recording for foreground user/profile
5112                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5113                UserManagerService.getInstance().setSystemControlledUserRestriction(
5114                        UserManager.DISALLOW_RECORD_AUDIO, false, userId);
5115            }
5116        }
5117    } // end class AudioServiceBroadcastReceiver
5118
5119    private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5120        PackageManager pm = mContext.getPackageManager();
5121        // Find the home activity of the user. It should not be killed to avoid expensive restart,
5122        // when the user switches back. For managed profiles, we should kill all recording apps
5123        ComponentName homeActivityName = null;
5124        if (!oldUser.isManagedProfile()) {
5125            homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5126                    .getHomeActivityForUser(oldUser.id);
5127        }
5128        final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5129        List<PackageInfo> packages;
5130        try {
5131            packages = AppGlobals.getPackageManager()
5132                    .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5133        } catch (RemoteException e) {
5134            throw new AndroidRuntimeException(e);
5135        }
5136        for (int j = packages.size() - 1; j >= 0; j--) {
5137            PackageInfo pkg = packages.get(j);
5138            // Skip system processes
5139            if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5140                continue;
5141            }
5142            // Skip packages that have permission to interact across users
5143            if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5144                    == PackageManager.PERMISSION_GRANTED) {
5145                continue;
5146            }
5147            if (homeActivityName != null
5148                    && pkg.packageName.equals(homeActivityName.getPackageName())
5149                    && pkg.applicationInfo.isSystemApp()) {
5150                continue;
5151            }
5152            try {
5153                final int uid = pkg.applicationInfo.uid;
5154                ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5155                        UserHandle.getUserId(uid),
5156                        "killBackgroundUserProcessesWithAudioRecordPermission");
5157            } catch (RemoteException e) {
5158                Log.w(TAG, "Error calling killUid", e);
5159            }
5160        }
5161    }
5162
5163    //==========================================================================================
5164    // RemoteControlDisplay / RemoteControlClient / Remote info
5165    //==========================================================================================
5166    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5167            ComponentName listenerComp) {
5168        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5169    }
5170
5171    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
5172        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
5173    }
5174
5175    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
5176        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
5177    }
5178
5179    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
5180        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
5181    }
5182
5183    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5184            boolean wantsSync) {
5185        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5186    }
5187
5188    @Override
5189    public void setRemoteStreamVolume(int index) {
5190        enforceVolumeController("set the remote stream volume");
5191        mMediaFocusControl.setRemoteStreamVolume(index);
5192    }
5193
5194    //==========================================================================================
5195    // Audio Focus
5196    //==========================================================================================
5197    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
5198            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
5199            IAudioPolicyCallback pcb) {
5200        // permission checks
5201        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
5202            if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
5203                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5204                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
5205                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5206                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5207                }
5208            } else {
5209                // only a registered audio policy can be used to lock focus
5210                synchronized (mAudioPolicies) {
5211                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5212                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
5213                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5214                    }
5215                }
5216            }
5217        }
5218
5219        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5220                clientId, callingPackageName, flags);
5221    }
5222
5223    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5224        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
5225    }
5226
5227    public void unregisterAudioFocusClient(String clientId) {
5228        mMediaFocusControl.unregisterAudioFocusClient(clientId);
5229    }
5230
5231    public int getCurrentAudioFocus() {
5232        return mMediaFocusControl.getCurrentAudioFocus();
5233    }
5234
5235    private boolean readCameraSoundForced() {
5236        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5237                mContext.getResources().getBoolean(
5238                        com.android.internal.R.bool.config_camera_sound_forced);
5239    }
5240
5241    //==========================================================================================
5242    // Device orientation
5243    //==========================================================================================
5244    /**
5245     * Handles device configuration changes that may map to a change in the orientation
5246     * or orientation.
5247     * Monitoring orientation and rotation is optional, and is defined by the definition and value
5248     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
5249     */
5250    private void handleConfigurationChanged(Context context) {
5251        try {
5252            // reading new orientation "safely" (i.e. under try catch) in case anything
5253            // goes wrong when obtaining resources and configuration
5254            Configuration config = context.getResources().getConfiguration();
5255            // TODO merge rotation and orientation
5256            if (mMonitorOrientation) {
5257                int newOrientation = config.orientation;
5258                if (newOrientation != mDeviceOrientation) {
5259                    mDeviceOrientation = newOrientation;
5260                    setOrientationForAudioSystem();
5261                }
5262            }
5263            sendMsg(mAudioHandler,
5264                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5265                    SENDMSG_REPLACE,
5266                    0,
5267                    0,
5268                    TAG,
5269                    0);
5270
5271            boolean cameraSoundForced = readCameraSoundForced();
5272            synchronized (mSettingsLock) {
5273                boolean cameraSoundForcedChanged = false;
5274                synchronized (mCameraSoundForced) {
5275                    if (cameraSoundForced != mCameraSoundForced) {
5276                        mCameraSoundForced = cameraSoundForced;
5277                        cameraSoundForcedChanged = true;
5278                    }
5279                }
5280                if (cameraSoundForcedChanged) {
5281                    if (!isPlatformTelevision()) {
5282                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5283                        if (cameraSoundForced) {
5284                            s.setAllIndexesToMax();
5285                            mRingerModeAffectedStreams &=
5286                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5287                        } else {
5288                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
5289                            mRingerModeAffectedStreams |=
5290                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5291                        }
5292                        // take new state into account for streams muted by ringer mode
5293                        setRingerModeInt(getRingerModeInternal(), false);
5294                    }
5295
5296                    sendMsg(mAudioHandler,
5297                            MSG_SET_FORCE_USE,
5298                            SENDMSG_QUEUE,
5299                            AudioSystem.FOR_SYSTEM,
5300                            cameraSoundForced ?
5301                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5302                            null,
5303                            0);
5304
5305                    sendMsg(mAudioHandler,
5306                            MSG_SET_ALL_VOLUMES,
5307                            SENDMSG_QUEUE,
5308                            0,
5309                            0,
5310                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5311                }
5312            }
5313            mVolumeController.setLayoutDirection(config.getLayoutDirection());
5314        } catch (Exception e) {
5315            Log.e(TAG, "Error handling configuration change: ", e);
5316        }
5317    }
5318
5319    private void setOrientationForAudioSystem() {
5320        switch (mDeviceOrientation) {
5321            case Configuration.ORIENTATION_LANDSCAPE:
5322                //Log.i(TAG, "orientation is landscape");
5323                AudioSystem.setParameters("orientation=landscape");
5324                break;
5325            case Configuration.ORIENTATION_PORTRAIT:
5326                //Log.i(TAG, "orientation is portrait");
5327                AudioSystem.setParameters("orientation=portrait");
5328                break;
5329            case Configuration.ORIENTATION_SQUARE:
5330                //Log.i(TAG, "orientation is square");
5331                AudioSystem.setParameters("orientation=square");
5332                break;
5333            case Configuration.ORIENTATION_UNDEFINED:
5334                //Log.i(TAG, "orientation is undefined");
5335                AudioSystem.setParameters("orientation=undefined");
5336                break;
5337            default:
5338                Log.e(TAG, "Unknown orientation");
5339        }
5340    }
5341
5342    private void setRotationForAudioSystem() {
5343        switch (mDeviceRotation) {
5344            case Surface.ROTATION_0:
5345                AudioSystem.setParameters("rotation=0");
5346                break;
5347            case Surface.ROTATION_90:
5348                AudioSystem.setParameters("rotation=90");
5349                break;
5350            case Surface.ROTATION_180:
5351                AudioSystem.setParameters("rotation=180");
5352                break;
5353            case Surface.ROTATION_270:
5354                AudioSystem.setParameters("rotation=270");
5355                break;
5356            default:
5357                Log.e(TAG, "Unknown device rotation");
5358        }
5359    }
5360
5361
5362    // Handles request to override default use of A2DP for media.
5363    // Must be called synchronized on mConnectedDevices
5364    public void setBluetoothA2dpOnInt(boolean on) {
5365        synchronized (mBluetoothA2dpEnabledLock) {
5366            mBluetoothA2dpEnabled = on;
5367            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5368            setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
5369                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5370        }
5371    }
5372
5373    // Must be called synchronized on mConnectedDevices
5374    private void setForceUseInt_SyncDevices(int usage, int config) {
5375        switch (usage) {
5376            case AudioSystem.FOR_MEDIA:
5377                if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5378                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5379                } else { // config == AudioSystem.FORCE_NONE
5380                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5381                }
5382                break;
5383            case AudioSystem.FOR_DOCK:
5384                if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5385                    mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5386                } else { // config == AudioSystem.FORCE_NONE
5387                    mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5388                }
5389                break;
5390            default:
5391                // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5392        }
5393        AudioSystem.setForceUse(usage, config);
5394    }
5395
5396    @Override
5397    public void setRingtonePlayer(IRingtonePlayer player) {
5398        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5399        mRingtonePlayer = player;
5400    }
5401
5402    @Override
5403    public IRingtonePlayer getRingtonePlayer() {
5404        return mRingtonePlayer;
5405    }
5406
5407    @Override
5408    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5409        synchronized (mCurAudioRoutes) {
5410            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5411            mRoutesObservers.register(observer);
5412            return routes;
5413        }
5414    }
5415
5416
5417    //==========================================================================================
5418    // Safe media volume management.
5419    // MUSIC stream volume level is limited when headphones are connected according to safety
5420    // regulation. When the user attempts to raise the volume above the limit, a warning is
5421    // displayed and the user has to acknowlegde before the volume is actually changed.
5422    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5423    // property. Platforms with a different limit must set this property accordingly in their
5424    // overlay.
5425    //==========================================================================================
5426
5427    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5428    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5429    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5430    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5431    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5432    // (when user opts out).
5433    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5434    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5435    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
5436    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
5437    private Integer mSafeMediaVolumeState;
5438
5439    private int mMcc = 0;
5440    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
5441    private int mSafeMediaVolumeIndex;
5442    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5443    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5444                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5445    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5446    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5447    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5448    private int mMusicActiveMs;
5449    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5450    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
5451    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
5452
5453    private void setSafeMediaVolumeEnabled(boolean on, String caller) {
5454        synchronized (mSafeMediaVolumeState) {
5455            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5456                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5457                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5458                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5459                    enforceSafeMediaVolume(caller);
5460                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5461                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
5462                    mMusicActiveMs = 1;  // nonzero = confirmed
5463                    saveMusicActiveMs();
5464                    sendMsg(mAudioHandler,
5465                            MSG_CHECK_MUSIC_ACTIVE,
5466                            SENDMSG_REPLACE,
5467                            0,
5468                            0,
5469                            caller,
5470                            MUSIC_ACTIVE_POLL_PERIOD_MS);
5471                }
5472            }
5473        }
5474    }
5475
5476    private void enforceSafeMediaVolume(String caller) {
5477        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5478        int devices = mSafeMediaVolumeDevices;
5479        int i = 0;
5480
5481        while (devices != 0) {
5482            int device = 1 << i++;
5483            if ((device & devices) == 0) {
5484                continue;
5485            }
5486            int index = streamState.getIndex(device);
5487            if (index > mSafeMediaVolumeIndex) {
5488                streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
5489                sendMsg(mAudioHandler,
5490                        MSG_SET_DEVICE_VOLUME,
5491                        SENDMSG_QUEUE,
5492                        device,
5493                        0,
5494                        streamState,
5495                        0);
5496            }
5497            devices &= ~device;
5498        }
5499    }
5500
5501    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
5502        synchronized (mSafeMediaVolumeState) {
5503            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
5504                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5505                    ((device & mSafeMediaVolumeDevices) != 0) &&
5506                    (index > mSafeMediaVolumeIndex)) {
5507                return false;
5508            }
5509            return true;
5510        }
5511    }
5512
5513    @Override
5514    public void disableSafeMediaVolume(String callingPackage) {
5515        enforceVolumeController("disable the safe media volume");
5516        synchronized (mSafeMediaVolumeState) {
5517            setSafeMediaVolumeEnabled(false, callingPackage);
5518            if (mPendingVolumeCommand != null) {
5519                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5520                                  mPendingVolumeCommand.mIndex,
5521                                  mPendingVolumeCommand.mFlags,
5522                                  mPendingVolumeCommand.mDevice,
5523                                  callingPackage);
5524                mPendingVolumeCommand = null;
5525            }
5526        }
5527    }
5528
5529    //==========================================================================================
5530    // Hdmi Cec system audio mode.
5531    // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5532    // to HdmiControlService so that the audio receiver can handle it.
5533    //==========================================================================================
5534
5535    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5536        public void onComplete(int status) {
5537            if (mHdmiManager != null) {
5538                synchronized (mHdmiManager) {
5539                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5540                    // Television devices without CEC service apply software volume on HDMI output
5541                    if (isPlatformTelevision() && !mHdmiCecSink) {
5542                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5543                    }
5544                    checkAllFixedVolumeDevices();
5545                }
5546            }
5547        }
5548    };
5549
5550    // If HDMI-CEC system audio is supported
5551    private boolean mHdmiSystemAudioSupported = false;
5552    // Set only when device is tv.
5553    private HdmiTvClient mHdmiTvClient;
5554    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
5555    // cached HdmiControlManager interface
5556    private HdmiControlManager mHdmiManager;
5557    // Set only when device is a set-top box.
5558    private HdmiPlaybackClient mHdmiPlaybackClient;
5559    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5560    private boolean mHdmiCecSink;
5561
5562    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
5563
5564    @Override
5565    public int setHdmiSystemAudioSupported(boolean on) {
5566        int device = AudioSystem.DEVICE_NONE;
5567        if (mHdmiManager != null) {
5568            synchronized (mHdmiManager) {
5569                if (mHdmiTvClient == null) {
5570                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5571                    return device;
5572                }
5573
5574                synchronized (mHdmiTvClient) {
5575                    if (mHdmiSystemAudioSupported != on) {
5576                        mHdmiSystemAudioSupported = on;
5577                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5578                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5579                                     AudioSystem.FORCE_NONE);
5580                    }
5581                    device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
5582                }
5583            }
5584        }
5585        return device;
5586    }
5587
5588    @Override
5589    public boolean isHdmiSystemAudioSupported() {
5590        return mHdmiSystemAudioSupported;
5591    }
5592
5593    //==========================================================================================
5594    // Accessibility: taking touch exploration into account for selecting the default
5595    //   stream override timeout when adjusting volume
5596    //==========================================================================================
5597    private static class StreamOverride
5598            implements AccessibilityManager.TouchExplorationStateChangeListener {
5599
5600        // AudioService.getActiveStreamType() will return:
5601        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5602        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5603        // stopped
5604        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
5605        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5606
5607        static int sDelayMs;
5608
5609        static void init(Context ctxt) {
5610            AccessibilityManager accessibilityManager =
5611                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5612            updateDefaultStreamOverrideDelay(
5613                    accessibilityManager.isTouchExplorationEnabled());
5614            accessibilityManager.addTouchExplorationStateChangeListener(
5615                    new StreamOverride());
5616        }
5617
5618        @Override
5619        public void onTouchExplorationStateChanged(boolean enabled) {
5620            updateDefaultStreamOverrideDelay(enabled);
5621        }
5622
5623        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5624            if (touchExploreEnabled) {
5625                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5626            } else {
5627                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5628            }
5629            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5630                    + " stream override delay is now " + sDelayMs + " ms");
5631        }
5632    }
5633
5634    //==========================================================================================
5635    // Camera shutter sound policy.
5636    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5637    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5638    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5639    //==========================================================================================
5640
5641    // cached value of com.android.internal.R.bool.config_camera_sound_forced
5642    private Boolean mCameraSoundForced;
5643
5644    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5645    public boolean isCameraSoundForced() {
5646        synchronized (mCameraSoundForced) {
5647            return mCameraSoundForced;
5648        }
5649    }
5650
5651    private static final String[] RINGER_MODE_NAMES = new String[] {
5652            "SILENT",
5653            "VIBRATE",
5654            "NORMAL"
5655    };
5656
5657    private void dumpRingerMode(PrintWriter pw) {
5658        pw.println("\nRinger mode: ");
5659        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5660        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
5661        dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5662        dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
5663        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
5664    }
5665
5666    private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5667        pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5668        pw.print(Integer.toHexString(streams));
5669        if (streams != 0) {
5670            pw.print(" (");
5671            boolean first = true;
5672            for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5673                final int stream = (1 << i);
5674                if ((streams & stream) != 0) {
5675                    if (!first) pw.print(',');
5676                    pw.print(AudioSystem.STREAM_NAMES[i]);
5677                    streams &= ~stream;
5678                    first = false;
5679                }
5680            }
5681            if (streams != 0) {
5682                if (!first) pw.print(',');
5683                pw.print(streams);
5684            }
5685            pw.print(')');
5686        }
5687        pw.println();
5688    }
5689
5690    @Override
5691    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5692        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5693
5694        mMediaFocusControl.dump(pw);
5695        dumpStreamStates(pw);
5696        dumpRingerMode(pw);
5697        pw.println("\nAudio routes:");
5698        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5699        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
5700
5701        pw.println("\nOther state:");
5702        pw.print("  mVolumeController="); pw.println(mVolumeController);
5703        pw.print("  mSafeMediaVolumeState=");
5704        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5705        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5706        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5707        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
5708        pw.print("  mMcc="); pw.println(mMcc);
5709        pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
5710        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
5711        pw.print("  mControllerService="); pw.println(mControllerService);
5712        pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
5713
5714        dumpAudioPolicies(pw);
5715    }
5716
5717    private static String safeMediaVolumeStateToString(Integer state) {
5718        switch(state) {
5719            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5720            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5721            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5722            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5723        }
5724        return null;
5725    }
5726
5727    // Inform AudioFlinger of our device's low RAM attribute
5728    private static void readAndSetLowRamDevice()
5729    {
5730        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5731        if (status != 0) {
5732            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5733        }
5734    }
5735
5736    private void enforceVolumeController(String action) {
5737        if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5738            return;
5739        }
5740        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5741                "Only SystemUI can " + action);
5742    }
5743
5744    @Override
5745    public void setVolumeController(final IVolumeController controller) {
5746        enforceVolumeController("set the volume controller");
5747
5748        // return early if things are not actually changing
5749        if (mVolumeController.isSameBinder(controller)) {
5750            return;
5751        }
5752
5753        // dismiss the old volume controller
5754        mVolumeController.postDismiss();
5755        if (controller != null) {
5756            // we are about to register a new controller, listen for its death
5757            try {
5758                controller.asBinder().linkToDeath(new DeathRecipient() {
5759                    @Override
5760                    public void binderDied() {
5761                        if (mVolumeController.isSameBinder(controller)) {
5762                            Log.w(TAG, "Current remote volume controller died, unregistering");
5763                            setVolumeController(null);
5764                        }
5765                    }
5766                }, 0);
5767            } catch (RemoteException e) {
5768                // noop
5769            }
5770        }
5771        mVolumeController.setController(controller);
5772        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5773    }
5774
5775    @Override
5776    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5777        enforceVolumeController("notify about volume controller visibility");
5778
5779        // return early if the controller is not current
5780        if (!mVolumeController.isSameBinder(controller)) {
5781            return;
5782        }
5783
5784        mVolumeController.setVisible(visible);
5785        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
5786    }
5787
5788    @Override
5789    public void setVolumePolicy(VolumePolicy policy) {
5790        enforceVolumeController("set volume policy");
5791        if (policy != null && !policy.equals(mVolumePolicy)) {
5792            mVolumePolicy = policy;
5793            if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
5794        }
5795    }
5796
5797    public static class VolumeController {
5798        private static final String TAG = "VolumeController";
5799
5800        private IVolumeController mController;
5801        private boolean mVisible;
5802        private long mNextLongPress;
5803        private int mLongPressTimeout;
5804
5805        public void setController(IVolumeController controller) {
5806            mController = controller;
5807            mVisible = false;
5808        }
5809
5810        public void loadSettings(ContentResolver cr) {
5811            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5812                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5813        }
5814
5815        public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5816            if (isMute) {
5817                return false;
5818            }
5819            boolean suppress = false;
5820            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5821                final long now = SystemClock.uptimeMillis();
5822                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5823                    // ui will become visible
5824                    if (mNextLongPress < now) {
5825                        mNextLongPress = now + mLongPressTimeout;
5826                    }
5827                    suppress = true;
5828                } else if (mNextLongPress > 0) {  // in a long-press
5829                    if (now > mNextLongPress) {
5830                        // long press triggered, no more suppression
5831                        mNextLongPress = 0;
5832                    } else {
5833                        // keep suppressing until the long press triggers
5834                        suppress = true;
5835                    }
5836                }
5837            }
5838            return suppress;
5839        }
5840
5841        public void setVisible(boolean visible) {
5842            mVisible = visible;
5843        }
5844
5845        public boolean isSameBinder(IVolumeController controller) {
5846            return Objects.equals(asBinder(), binder(controller));
5847        }
5848
5849        public IBinder asBinder() {
5850            return binder(mController);
5851        }
5852
5853        private static IBinder binder(IVolumeController controller) {
5854            return controller == null ? null : controller.asBinder();
5855        }
5856
5857        @Override
5858        public String toString() {
5859            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
5860        }
5861
5862        public void postDisplaySafeVolumeWarning(int flags) {
5863            if (mController == null)
5864                return;
5865            try {
5866                mController.displaySafeVolumeWarning(flags);
5867            } catch (RemoteException e) {
5868                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5869            }
5870        }
5871
5872        public void postVolumeChanged(int streamType, int flags) {
5873            if (mController == null)
5874                return;
5875            try {
5876                mController.volumeChanged(streamType, flags);
5877            } catch (RemoteException e) {
5878                Log.w(TAG, "Error calling volumeChanged", e);
5879            }
5880        }
5881
5882        public void postMasterMuteChanged(int flags) {
5883            if (mController == null)
5884                return;
5885            try {
5886                mController.masterMuteChanged(flags);
5887            } catch (RemoteException e) {
5888                Log.w(TAG, "Error calling masterMuteChanged", e);
5889            }
5890        }
5891
5892        public void setLayoutDirection(int layoutDirection) {
5893            if (mController == null)
5894                return;
5895            try {
5896                mController.setLayoutDirection(layoutDirection);
5897            } catch (RemoteException e) {
5898                Log.w(TAG, "Error calling setLayoutDirection", e);
5899            }
5900        }
5901
5902        public void postDismiss() {
5903            if (mController == null)
5904                return;
5905            try {
5906                mController.dismiss();
5907            } catch (RemoteException e) {
5908                Log.w(TAG, "Error calling dismiss", e);
5909            }
5910        }
5911    }
5912
5913    /**
5914     * Interface for system components to get some extra functionality through
5915     * LocalServices.
5916     */
5917    final class AudioServiceInternal extends AudioManagerInternal {
5918        @Override
5919        public void setRingerModeDelegate(RingerModeDelegate delegate) {
5920            mRingerModeDelegate = delegate;
5921            if (mRingerModeDelegate != null) {
5922                updateRingerModeAffectedStreams();
5923                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5924            }
5925        }
5926
5927        @Override
5928        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5929                String callingPackage, int uid) {
5930            // direction and stream type swap here because the public
5931            // adjustSuggested has a different order than the other methods.
5932            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
5933                    callingPackage, uid);
5934        }
5935
5936        @Override
5937        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5938                String callingPackage, int uid) {
5939            adjustStreamVolume(streamType, direction, flags, callingPackage,
5940                    callingPackage, uid);
5941        }
5942
5943        @Override
5944        public void setStreamVolumeForUid(int streamType, int direction, int flags,
5945                String callingPackage, int uid) {
5946            setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
5947        }
5948
5949        @Override
5950        public int getRingerModeInternal() {
5951            return AudioService.this.getRingerModeInternal();
5952        }
5953
5954        @Override
5955        public void setRingerModeInternal(int ringerMode, String caller) {
5956            AudioService.this.setRingerModeInternal(ringerMode, caller);
5957        }
5958
5959        @Override
5960        public int getVolumeControllerUid() {
5961            return mControllerService.mUid;
5962        }
5963
5964        @Override
5965        public void updateRingerModeAffectedStreamsInternal() {
5966            synchronized (mSettingsLock) {
5967                if (updateRingerModeAffectedStreams()) {
5968                    setRingerModeInt(getRingerModeInternal(), false);
5969                }
5970            }
5971        }
5972    }
5973
5974    //==========================================================================================
5975    // Audio policy management
5976    //==========================================================================================
5977    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5978            boolean hasFocusListener) {
5979        AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
5980
5981        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5982                + " with config:" + policyConfig);
5983        String regId = null;
5984        // error handling
5985        boolean hasPermissionForPolicy =
5986                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5987                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5988        if (!hasPermissionForPolicy) {
5989            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5990                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5991            return null;
5992        }
5993
5994        synchronized (mAudioPolicies) {
5995            try {
5996                if (mAudioPolicies.containsKey(pcb.asBinder())) {
5997                    Slog.e(TAG, "Cannot re-register policy");
5998                    return null;
5999                }
6000                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6001                pcb.asBinder().linkToDeath(app, 0/*flags*/);
6002                regId = app.getRegistrationId();
6003                mAudioPolicies.put(pcb.asBinder(), app);
6004            } catch (RemoteException e) {
6005                // audio policy owner has already died!
6006                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
6007                        " binder death", e);
6008                return null;
6009            }
6010        }
6011        return regId;
6012    }
6013
6014    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6015        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
6016        synchronized (mAudioPolicies) {
6017            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
6018            if (app == null) {
6019                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6020                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
6021                return;
6022            } else {
6023                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
6024            }
6025            app.release();
6026        }
6027        // TODO implement clearing mix attribute matching info in native audio policy
6028    }
6029
6030    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6031        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6032                + " policy " +  pcb.asBinder());
6033        // error handling
6034        boolean hasPermissionForPolicy =
6035                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6036                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6037        if (!hasPermissionForPolicy) {
6038            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6039                    + Binder.getCallingPid() + " / uid "
6040                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6041            return AudioManager.ERROR;
6042        }
6043
6044        synchronized (mAudioPolicies) {
6045            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6046                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6047                return AudioManager.ERROR;
6048            }
6049            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6050            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6051                // is there already one policy managing ducking?
6052                for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6053                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6054                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6055                        return AudioManager.ERROR;
6056                    }
6057                }
6058            }
6059            app.mFocusDuckBehavior = duckingBehavior;
6060            mMediaFocusControl.setDuckingInExtPolicyAvailable(
6061                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6062        }
6063        return AudioManager.SUCCESS;
6064    }
6065
6066    private void dumpAudioPolicies(PrintWriter pw) {
6067        pw.println("\nAudio policies:");
6068        synchronized (mAudioPolicies) {
6069            for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6070                pw.println(policy.toLogFriendlyString());
6071            }
6072        }
6073    }
6074
6075    //======================
6076    // Audio policy callback from AudioSystem
6077    //======================
6078    private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6079            new AudioSystem.DynamicPolicyCallback() {
6080        public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6081            if (!TextUtils.isEmpty(regId)) {
6082                sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6083                        state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6084            }
6085        }
6086    };
6087
6088    private void onDynPolicyMixStateUpdate(String regId, int state) {
6089        if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6090        synchronized (mAudioPolicies) {
6091            for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6092                for (AudioMix mix : policy.getMixes()) {
6093                    if (mix.getRegistration().equals(regId)) {
6094                        try {
6095                            policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6096                        } catch (RemoteException e) {
6097                            Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6098                                    + policy.mPolicyCallback.asBinder(), e);
6099                        }
6100                        return;
6101                    }
6102                }
6103            }
6104        }
6105
6106    }
6107
6108    //======================
6109    // Audio policy proxy
6110    //======================
6111    /**
6112     * This internal class inherits from AudioPolicyConfig, each instance contains all the
6113     * mixes of an AudioPolicy and their configurations.
6114     */
6115    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
6116        private static final String TAG = "AudioPolicyProxy";
6117        IAudioPolicyCallback mPolicyCallback;
6118        boolean mHasFocusListener;
6119        /**
6120         * Audio focus ducking behavior for an audio policy.
6121         * This variable reflects the value that was successfully set in
6122         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6123         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6124         * is handling ducking for audio focus.
6125         */
6126        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6127
6128        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6129                boolean hasFocusListener) {
6130            super(config);
6131            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
6132            mPolicyCallback = token;
6133            mHasFocusListener = hasFocusListener;
6134            if (mHasFocusListener) {
6135                mMediaFocusControl.addFocusFollower(mPolicyCallback);
6136            }
6137            connectMixes();
6138        }
6139
6140        public void binderDied() {
6141            synchronized (mAudioPolicies) {
6142                Log.i(TAG, "audio policy " + mPolicyCallback + " died");
6143                release();
6144                mAudioPolicies.remove(mPolicyCallback.asBinder());
6145            }
6146        }
6147
6148        String getRegistrationId() {
6149            return getRegistration();
6150        }
6151
6152        void release() {
6153            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6154                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6155            }
6156            if (mHasFocusListener) {
6157                mMediaFocusControl.removeFocusFollower(mPolicyCallback);
6158            }
6159            AudioSystem.registerPolicyMixes(mMixes, false);
6160        }
6161
6162        void connectMixes() {
6163            AudioSystem.registerPolicyMixes(mMixes, true);
6164        }
6165    };
6166
6167    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6168            new HashMap<IBinder, AudioPolicyProxy>();
6169    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
6170
6171    private class ControllerService extends ContentObserver {
6172        private int mUid;
6173        private ComponentName mComponent;
6174
6175        public ControllerService() {
6176            super(null);
6177        }
6178
6179        @Override
6180        public String toString() {
6181            return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6182        }
6183
6184        public void init() {
6185            onChange(true);
6186            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6187                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6188        }
6189
6190        @Override
6191        public void onChange(boolean selfChange) {
6192            mUid = 0;
6193            mComponent = null;
6194            final String setting = Settings.Secure.getString(mContentResolver,
6195                    Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6196            if (setting == null) return;
6197            try {
6198                mComponent = ComponentName.unflattenFromString(setting);
6199                if (mComponent == null) return;
6200                mUid = mContext.getPackageManager()
6201                        .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6202            } catch (Exception e) {
6203                Log.w(TAG, "Error loading controller service", e);
6204            }
6205            if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6206        }
6207    }
6208}
6209