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