AudioService.java revision 0a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98
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 android.media;
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.app.PendingIntent;
29import android.bluetooth.BluetoothA2dp;
30import android.bluetooth.BluetoothAdapter;
31import android.bluetooth.BluetoothClass;
32import android.bluetooth.BluetoothDevice;
33import android.bluetooth.BluetoothHeadset;
34import android.bluetooth.BluetoothProfile;
35import android.content.BroadcastReceiver;
36import android.content.ComponentName;
37import android.content.ContentResolver;
38import android.content.Context;
39import android.content.Intent;
40import android.content.IntentFilter;
41import android.content.pm.PackageManager;
42import android.content.res.Configuration;
43import android.content.res.Resources;
44import android.content.res.XmlResourceParser;
45import android.database.ContentObserver;
46import android.hardware.usb.UsbManager;
47import android.media.MediaPlayer.OnCompletionListener;
48import android.media.MediaPlayer.OnErrorListener;
49import android.media.session.MediaSessionLegacyHelper;
50import android.os.Binder;
51import android.os.Build;
52import android.os.Environment;
53import android.os.Handler;
54import android.os.IBinder;
55import android.os.Looper;
56import android.os.Message;
57import android.os.PowerManager;
58import android.os.RemoteCallbackList;
59import android.os.RemoteException;
60import android.os.ServiceManager;
61import android.os.SystemProperties;
62import android.os.UserHandle;
63import android.os.Vibrator;
64import android.provider.Settings;
65import android.provider.Settings.System;
66import android.text.TextUtils;
67import android.util.Log;
68import android.view.KeyEvent;
69import android.view.Surface;
70import android.view.WindowManager;
71
72import com.android.internal.telephony.ITelephony;
73import com.android.internal.util.XmlUtils;
74
75import org.xmlpull.v1.XmlPullParserException;
76
77import java.io.FileDescriptor;
78import java.io.IOException;
79import java.io.PrintWriter;
80import java.lang.reflect.Field;
81import java.util.ArrayList;
82import java.util.concurrent.ConcurrentHashMap;
83import java.util.HashMap;
84import java.util.Iterator;
85import java.util.List;
86import java.util.Map;
87import java.util.NoSuchElementException;
88import java.util.Set;
89
90/**
91 * The implementation of the volume manager service.
92 * <p>
93 * This implementation focuses on delivering a responsive UI. Most methods are
94 * asynchronous to external calls. For example, the task of setting a volume
95 * will update our internal state, but in a separate thread will set the system
96 * volume and later persist to the database. Similarly, setting the ringer mode
97 * will update the state and broadcast a change and in a separate thread later
98 * persist the ringer mode.
99 *
100 * @hide
101 */
102public class AudioService extends IAudioService.Stub {
103
104    private static final String TAG = "AudioService";
105
106    /** Debug remote control client/display feature */
107    protected static final boolean DEBUG_RC = false;
108    /** Debug volumes */
109    protected static final boolean DEBUG_VOL = false;
110
111    /** Reroute calls to media session apis */
112    private static final boolean USE_SESSIONS = true;
113    private static final boolean DEBUG_SESSIONS = true;
114
115    /** Allow volume changes to set ringer mode to silent? */
116    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
117
118    /** How long to delay before persisting a change in volume/ringer mode. */
119    private static final int PERSIST_DELAY = 500;
120
121    /**
122     * The delay before playing a sound. This small period exists so the user
123     * can press another key (non-volume keys, too) to have it NOT be audible.
124     * <p>
125     * PhoneWindow will implement this part.
126     */
127    public static final int PLAY_SOUND_DELAY = 300;
128
129    private final Context mContext;
130    private final ContentResolver mContentResolver;
131    private final AppOpsManager mAppOps;
132    private final boolean mVoiceCapable;
133
134    /** The controller for the volume UI. */
135    private final VolumeController mVolumeController = new VolumeController();
136
137    // sendMsg() flags
138    /** If the msg is already queued, replace it with this one. */
139    private static final int SENDMSG_REPLACE = 0;
140    /** If the msg is already queued, ignore this one and leave the old. */
141    private static final int SENDMSG_NOOP = 1;
142    /** If the msg is already queued, queue this one and leave the old. */
143    private static final int SENDMSG_QUEUE = 2;
144
145    // AudioHandler messages
146    private static final int MSG_SET_DEVICE_VOLUME = 0;
147    private static final int MSG_PERSIST_VOLUME = 1;
148    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
149    private static final int MSG_PERSIST_RINGER_MODE = 3;
150    private static final int MSG_MEDIA_SERVER_DIED = 4;
151    private static final int MSG_PLAY_SOUND_EFFECT = 5;
152    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
153    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
154    private static final int MSG_SET_FORCE_USE = 8;
155    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
156    private static final int MSG_SET_ALL_VOLUMES = 10;
157    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
158    private static final int MSG_REPORT_NEW_ROUTES = 12;
159    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
160    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
161    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
162    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
163    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
164    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
165    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
166    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
167    private static final int MSG_SYSTEM_READY = 21;
168    // start of messages handled under wakelock
169    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
170    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
171    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
172    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
173    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
174    // end of messages handled under wakelock
175
176    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
177    // Timeout for connection to bluetooth headset service
178    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
179
180    /** @see AudioSystemThread */
181    private AudioSystemThread mAudioSystemThread;
182    /** @see AudioHandler */
183    private AudioHandler mAudioHandler;
184    /** @see VolumeStreamState */
185    private VolumeStreamState[] mStreamStates;
186    private SettingsObserver mSettingsObserver;
187
188    private int mMode = AudioSystem.MODE_NORMAL;
189    // protects mRingerMode
190    private final Object mSettingsLock = new Object();
191
192    private SoundPool mSoundPool;
193    private final Object mSoundEffectsLock = new Object();
194    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
195
196    // Internally master volume is a float in the 0.0 - 1.0 range,
197    // but to support integer based AudioManager API we translate it to 0 - 100
198    private static final int MAX_MASTER_VOLUME = 100;
199
200    // Maximum volume adjust steps allowed in a single batch call.
201    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
202
203    /* Sound effect file names  */
204    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
205    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
206
207    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
208     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
209     * uses soundpool (second column) */
210    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
211
212   /** @hide Maximum volume index values for audio streams */
213    private static final int[] MAX_STREAM_VOLUME = new int[] {
214        5,  // STREAM_VOICE_CALL
215        7,  // STREAM_SYSTEM
216        7,  // STREAM_RING
217        15, // STREAM_MUSIC
218        7,  // STREAM_ALARM
219        7,  // STREAM_NOTIFICATION
220        15, // STREAM_BLUETOOTH_SCO
221        7,  // STREAM_SYSTEM_ENFORCED
222        15, // STREAM_DTMF
223        15  // STREAM_TTS
224    };
225    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
226     * of another stream: This avoids multiplying the volume settings for hidden
227     * stream types that follow other stream behavior for volume settings
228     * NOTE: do not create loops in aliases!
229     * Some streams alias to different streams according to device category (phone or tablet) or
230     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
231     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
232     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
233    private final int[] STREAM_VOLUME_ALIAS = new int[] {
234        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
235        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
236        AudioSystem.STREAM_RING,            // STREAM_RING
237        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
238        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
239        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
240        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
241        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
242        AudioSystem.STREAM_RING,            // STREAM_DTMF
243        AudioSystem.STREAM_MUSIC            // STREAM_TTS
244    };
245    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
246        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
247        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
248        AudioSystem.STREAM_RING,            // STREAM_RING
249        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
250        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
251        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
252        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
253        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
254        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
255        AudioSystem.STREAM_MUSIC            // STREAM_TTS
256    };
257    private int[] mStreamVolumeAlias;
258
259    /**
260     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
261     * after mapping through mStreamVolumeAlias.
262     */
263    private static final int[] STEAM_VOLUME_OPS = new int[] {
264        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
265        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
266        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
267        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
268        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
269        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
270        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
271        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
272        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
273        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
274    };
275
276    private final boolean mUseFixedVolume;
277
278    // stream names used by dumpStreamStates()
279    private static final String[] STREAM_NAMES = new String[] {
280            "STREAM_VOICE_CALL",
281            "STREAM_SYSTEM",
282            "STREAM_RING",
283            "STREAM_MUSIC",
284            "STREAM_ALARM",
285            "STREAM_NOTIFICATION",
286            "STREAM_BLUETOOTH_SCO",
287            "STREAM_SYSTEM_ENFORCED",
288            "STREAM_DTMF",
289            "STREAM_TTS"
290    };
291
292    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
293        public void onError(int error) {
294            switch (error) {
295            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
296                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
297                        SENDMSG_NOOP, 0, 0, null, 0);
298                break;
299            default:
300                break;
301            }
302        }
303    };
304
305    /**
306     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
307     * {@link AudioManager#RINGER_MODE_SILENT}, or
308     * {@link AudioManager#RINGER_MODE_VIBRATE}.
309     */
310    // protected by mSettingsLock
311    private int mRingerMode;
312
313    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
314    private int mRingerModeAffectedStreams = 0;
315
316    // Streams currently muted by ringer mode
317    private int mRingerModeMutedStreams;
318
319    /** @see System#MUTE_STREAMS_AFFECTED */
320    private int mMuteAffectedStreams;
321
322    /**
323     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
324     * mVibrateSetting is just maintained during deprecation period but vibration policy is
325     * now only controlled by mHasVibrator and mRingerMode
326     */
327    private int mVibrateSetting;
328
329    // Is there a vibrator
330    private final boolean mHasVibrator;
331
332    // Broadcast receiver for device connections intent broadcasts
333    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
334
335    // Devices currently connected
336    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
337
338    // Forced device usage for communications
339    private int mForcedUseForComm;
340
341    // True if we have master volume support
342    private final boolean mUseMasterVolume;
343
344    private final int[] mMasterVolumeRamp;
345
346    // List of binder death handlers for setMode() client processes.
347    // The last process to have called setMode() is at the top of the list.
348    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
349
350    // List of clients having issued a SCO start request
351    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
352
353    // BluetoothHeadset API to control SCO connection
354    private BluetoothHeadset mBluetoothHeadset;
355
356    // Bluetooth headset device
357    private BluetoothDevice mBluetoothHeadsetDevice;
358
359    // Indicate if SCO audio connection is currently active and if the initiator is
360    // audio service (internal) or bluetooth headset (external)
361    private int mScoAudioState;
362    // SCO audio state is not active
363    private static final int SCO_STATE_INACTIVE = 0;
364    // SCO audio activation request waiting for headset service to connect
365    private static final int SCO_STATE_ACTIVATE_REQ = 1;
366    // SCO audio state is active or starting due to a request from AudioManager API
367    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
368    // SCO audio deactivation request waiting for headset service to connect
369    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
370
371    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
372    // in call audio)
373    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
374    // Deactivation request for all SCO connections (initiated by audio mode change)
375    // waiting for headset service to connect
376    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
377
378    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
379    // originated from an app targeting an API version before JB MR2 and raw audio after that.
380    private int mScoAudioMode;
381    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
382    private static final int SCO_MODE_VIRTUAL_CALL = 0;
383    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
384    private static final int SCO_MODE_RAW = 1;
385
386    // Current connection state indicated by bluetooth headset
387    private int mScoConnectionState;
388
389    // true if boot sequence has been completed
390    private boolean mSystemReady;
391    // listener for SoundPool sample load completion indication
392    private SoundPoolCallback mSoundPoolCallBack;
393    // thread for SoundPool listener
394    private SoundPoolListenerThread mSoundPoolListenerThread;
395    // message looper for SoundPool listener
396    private Looper mSoundPoolLooper = null;
397    // volume applied to sound played with playSoundEffect()
398    private static int sSoundEffectVolumeDb;
399    // getActiveStreamType() will return:
400    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
401    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
402    // stopped
403    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
404    // previous volume adjustment direction received by checkForRingerModeChange()
405    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
406    // Keyguard manager proxy
407    private KeyguardManager mKeyguardManager;
408    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
409    // is controlled by Vol keys.
410    private int  mVolumeControlStream = -1;
411    private final Object mForceControlStreamLock = new Object();
412    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
413    // server process so in theory it is not necessary to monitor the client death.
414    // However it is good to be ready for future evolutions.
415    private ForceControlStreamClient mForceControlStreamClient = null;
416    // Used to play ringtones outside system_server
417    private volatile IRingtonePlayer mRingtonePlayer;
418
419    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
420    private int mDeviceRotation = Surface.ROTATION_0;
421
422    // Request to override default use of A2DP for media.
423    private boolean mBluetoothA2dpEnabled;
424    private final Object mBluetoothA2dpEnabledLock = new Object();
425
426    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
427    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
428    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
429            = new RemoteCallbackList<IAudioRoutesObserver>();
430
431    /**
432     * A fake stream type to match the notion of remote media playback
433     */
434    public final static int STREAM_REMOTE_MUSIC = -200;
435
436    // Devices for which the volume is fixed and VolumePanel slider should be disabled
437    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
438            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
439            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
440            AudioSystem.DEVICE_OUT_ALL_USB;
441
442    // TODO merge orientation and rotation
443    private final boolean mMonitorOrientation;
444    private final boolean mMonitorRotation;
445
446    private boolean mDockAudioMediaEnabled = true;
447
448    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
449
450    // Used when safe volume warning message display is requested by setStreamVolume(). In this
451    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
452    // and used later when/if disableSafeMediaVolume() is called.
453    private StreamVolumeCommand mPendingVolumeCommand;
454
455    private PowerManager.WakeLock mAudioEventWakeLock;
456
457    private final MediaFocusControl mMediaFocusControl;
458
459    // Reference to BluetoothA2dp to query for AbsoluteVolume.
460    private BluetoothA2dp mA2dp;
461    private final Object mA2dpAvrcpLock = new Object();
462    // If absolute volume is supported in AVRCP device
463    private boolean mAvrcpAbsVolSupported = false;
464
465    ///////////////////////////////////////////////////////////////////////////
466    // Construction
467    ///////////////////////////////////////////////////////////////////////////
468
469    /** @hide */
470    public AudioService(Context context) {
471        mContext = context;
472        mContentResolver = context.getContentResolver();
473        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
474        mVoiceCapable = mContext.getResources().getBoolean(
475                com.android.internal.R.bool.config_voice_capable);
476
477        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
478        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
479
480        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
481        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
482
483       // Intialized volume
484        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
485            "ro.config.vc_call_vol_steps",
486           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
487
488        sSoundEffectVolumeDb = context.getResources().getInteger(
489                com.android.internal.R.integer.config_soundEffectVolumeDb);
490
491        mForcedUseForComm = AudioSystem.FORCE_NONE;
492
493        createAudioSystemThread();
494
495        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
496                mContext, mVolumeController, this);
497
498        AudioSystem.setErrorCallback(mAudioSystemCallback);
499
500        boolean cameraSoundForced = mContext.getResources().getBoolean(
501                com.android.internal.R.bool.config_camera_sound_forced);
502        mCameraSoundForced = new Boolean(cameraSoundForced);
503        sendMsg(mAudioHandler,
504                MSG_SET_FORCE_USE,
505                SENDMSG_QUEUE,
506                AudioSystem.FOR_SYSTEM,
507                cameraSoundForced ?
508                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
509                null,
510                0);
511
512        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
513                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
514                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
515        // The default safe volume index read here will be replaced by the actual value when
516        // the mcc is read by onConfigureSafeVolume()
517        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
518                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
519
520        mUseFixedVolume = mContext.getResources().getBoolean(
521                com.android.internal.R.bool.config_useFixedVolume);
522
523        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
524        // array initialized by updateStreamVolumeAlias()
525        updateStreamVolumeAlias(false /*updateVolumes*/);
526        readPersistedSettings();
527        mSettingsObserver = new SettingsObserver();
528        createStreamStates();
529
530        readAndSetLowRamDevice();
531
532        // Call setRingerModeInt() to apply correct mute
533        // state on streams affected by ringer mode.
534        mRingerModeMutedStreams = 0;
535        setRingerModeInt(getRingerMode(), false);
536
537        // Register for device connection intent broadcasts.
538        IntentFilter intentFilter =
539                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
540        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
541        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
542        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
543        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
544        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
545        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
546        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
547        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
548
549        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
550        // TODO merge orientation and rotation
551        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
552        if (mMonitorOrientation) {
553            Log.v(TAG, "monitoring device orientation");
554            // initialize orientation in AudioSystem
555            setOrientationForAudioSystem();
556        }
557        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
558        if (mMonitorRotation) {
559            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
560                    .getDefaultDisplay().getRotation();
561            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
562            // initialize rotation in AudioSystem
563            setRotationForAudioSystem();
564        }
565
566        context.registerReceiver(mReceiver, intentFilter);
567
568        mUseMasterVolume = context.getResources().getBoolean(
569                com.android.internal.R.bool.config_useMasterVolume);
570        restoreMasterVolume();
571
572        mMasterVolumeRamp = context.getResources().getIntArray(
573                com.android.internal.R.array.config_masterVolumeRamp);
574
575    }
576
577    public void systemReady() {
578        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
579                0, 0, null, 0);
580    }
581
582    public void onSystemReady() {
583        mSystemReady = true;
584        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
585                0, 0, null, 0);
586
587        mKeyguardManager =
588                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
589        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
590        resetBluetoothSco();
591        getBluetoothHeadset();
592        //FIXME: this is to maintain compatibility with deprecated intent
593        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
594        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
595        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
596                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
597        sendStickyBroadcastToAll(newIntent);
598
599        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
600        if (adapter != null) {
601            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
602                                    BluetoothProfile.A2DP);
603        }
604
605        sendMsg(mAudioHandler,
606                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
607                SENDMSG_REPLACE,
608                0,
609                0,
610                null,
611                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
612    }
613
614    private void createAudioSystemThread() {
615        mAudioSystemThread = new AudioSystemThread();
616        mAudioSystemThread.start();
617        waitForAudioHandlerCreation();
618    }
619
620    /** Waits for the volume handler to be created by the other thread. */
621    private void waitForAudioHandlerCreation() {
622        synchronized(this) {
623            while (mAudioHandler == null) {
624                try {
625                    // Wait for mAudioHandler to be set by the other thread
626                    wait();
627                } catch (InterruptedException e) {
628                    Log.e(TAG, "Interrupted while waiting on volume handler.");
629                }
630            }
631        }
632    }
633
634    private void checkAllAliasStreamVolumes() {
635        int numStreamTypes = AudioSystem.getNumStreamTypes();
636        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
637            if (streamType != mStreamVolumeAlias[streamType]) {
638                mStreamStates[streamType].
639                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
640            }
641            // apply stream volume
642            if (!mStreamStates[streamType].isMuted()) {
643                mStreamStates[streamType].applyAllVolumes();
644            }
645        }
646    }
647
648    private void createStreamStates() {
649        int numStreamTypes = AudioSystem.getNumStreamTypes();
650        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
651
652        for (int i = 0; i < numStreamTypes; i++) {
653            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
654        }
655
656        checkAllAliasStreamVolumes();
657    }
658
659    private void dumpStreamStates(PrintWriter pw) {
660        pw.println("\nStream volumes (device: index)");
661        int numStreamTypes = AudioSystem.getNumStreamTypes();
662        for (int i = 0; i < numStreamTypes; i++) {
663            pw.println("- "+STREAM_NAMES[i]+":");
664            mStreamStates[i].dump(pw);
665            pw.println("");
666        }
667        pw.print("\n- mute affected streams = 0x");
668        pw.println(Integer.toHexString(mMuteAffectedStreams));
669    }
670
671    /** @hide */
672    public static String streamToString(int stream) {
673        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
674        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
675        return "UNKNOWN_STREAM_" + stream;
676    }
677
678    private void updateStreamVolumeAlias(boolean updateVolumes) {
679        int dtmfStreamAlias;
680        if (mVoiceCapable) {
681            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
682            dtmfStreamAlias = AudioSystem.STREAM_RING;
683        } else {
684            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
685            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
686        }
687        if (isInCommunication()) {
688            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
689            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
690        } else {
691            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
692        }
693        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
694        if (updateVolumes) {
695            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
696            // apply stream mute states according to new value of mRingerModeAffectedStreams
697            setRingerModeInt(getRingerMode(), false);
698            sendMsg(mAudioHandler,
699                    MSG_SET_ALL_VOLUMES,
700                    SENDMSG_QUEUE,
701                    0,
702                    0,
703                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
704        }
705    }
706
707    private void readDockAudioSettings(ContentResolver cr)
708    {
709        mDockAudioMediaEnabled = Settings.Global.getInt(
710                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
711
712        if (mDockAudioMediaEnabled) {
713            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
714        } else {
715            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
716        }
717
718        sendMsg(mAudioHandler,
719                MSG_SET_FORCE_USE,
720                SENDMSG_QUEUE,
721                AudioSystem.FOR_DOCK,
722                mDockAudioMediaEnabled ?
723                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
724                null,
725                0);
726    }
727
728    private void readPersistedSettings() {
729        final ContentResolver cr = mContentResolver;
730
731        int ringerModeFromSettings =
732                Settings.Global.getInt(
733                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
734        int ringerMode = ringerModeFromSettings;
735        // sanity check in case the settings are restored from a device with incompatible
736        // ringer modes
737        if (!AudioManager.isValidRingerMode(ringerMode)) {
738            ringerMode = AudioManager.RINGER_MODE_NORMAL;
739        }
740        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
741            ringerMode = AudioManager.RINGER_MODE_SILENT;
742        }
743        if (ringerMode != ringerModeFromSettings) {
744            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
745        }
746        if (mUseFixedVolume) {
747            ringerMode = AudioManager.RINGER_MODE_NORMAL;
748        }
749        synchronized(mSettingsLock) {
750            mRingerMode = ringerMode;
751
752            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
753            // are still needed while setVibrateSetting() and getVibrateSetting() are being
754            // deprecated.
755            mVibrateSetting = getValueForVibrateSetting(0,
756                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
757                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
758                                                            : AudioManager.VIBRATE_SETTING_OFF);
759            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
760                                            AudioManager.VIBRATE_TYPE_RINGER,
761                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
762                                                            : AudioManager.VIBRATE_SETTING_OFF);
763
764            updateRingerModeAffectedStreams();
765            readDockAudioSettings(cr);
766        }
767
768        mMuteAffectedStreams = System.getIntForUser(cr,
769                System.MUTE_STREAMS_AFFECTED,
770                ((1 << AudioSystem.STREAM_MUSIC)|
771                 (1 << AudioSystem.STREAM_RING)|
772                 (1 << AudioSystem.STREAM_SYSTEM)),
773                 UserHandle.USER_CURRENT);
774
775        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
776                                                  0, UserHandle.USER_CURRENT) == 1;
777        if (mUseFixedVolume) {
778            masterMute = false;
779            AudioSystem.setMasterVolume(1.0f);
780        }
781        AudioSystem.setMasterMute(masterMute);
782        broadcastMasterMuteStatus(masterMute);
783
784        // Each stream will read its own persisted settings
785
786        // Broadcast the sticky intent
787        broadcastRingerMode(ringerMode);
788
789        // Broadcast vibrate settings
790        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
791        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
792
793        // Restore the default media button receiver from the system settings
794        mMediaFocusControl.restoreMediaButtonReceiver();
795    }
796
797    private int rescaleIndex(int index, int srcStream, int dstStream) {
798        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
799    }
800
801    ///////////////////////////////////////////////////////////////////////////
802    // IPC methods
803    ///////////////////////////////////////////////////////////////////////////
804    /** @see AudioManager#isLocalOrRemoteMusicActive() */
805    public boolean isLocalOrRemoteMusicActive() {
806        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
807            // local / wired / BT playback active
808            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
809            return true;
810        }
811        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
812            // remote "cast-like" playback active
813            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
814            return true;
815        }
816        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
817            // remote submix playback active
818            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
819            return true;
820        }
821        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
822        return false;
823    }
824
825    /** @see AudioManager#adjustVolume(int, int) */
826    public void adjustVolume(int direction, int flags, String callingPackage) {
827        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
828                callingPackage);
829    }
830
831    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
832     *  on streamType: fixed to STREAM_MUSIC */
833    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
834            String callingPackage) {
835        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
836        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
837            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
838        } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
839            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
840        }
841    }
842
843    /** @see AudioManager#adjustVolume(int, int) */
844    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
845            String callingPackage) {
846        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
847        int streamType;
848        if (mVolumeControlStream != -1) {
849            streamType = mVolumeControlStream;
850        } else {
851            streamType = getActiveStreamType(suggestedStreamType);
852        }
853
854        // Play sounds on STREAM_RING only and if lock screen is not on.
855        if ((streamType != STREAM_REMOTE_MUSIC) &&
856                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
857                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
858                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
859            flags &= ~AudioManager.FLAG_PLAY_SOUND;
860        }
861
862        if (streamType == STREAM_REMOTE_MUSIC) {
863            // don't play sounds for remote
864            flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
865            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
866            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
867        } else {
868            adjustStreamVolume(streamType, direction, flags, callingPackage);
869        }
870    }
871
872    /** @see AudioManager#adjustStreamVolume(int, int, int) */
873    public void adjustStreamVolume(int streamType, int direction, int flags,
874            String callingPackage) {
875        if (mUseFixedVolume) {
876            return;
877        }
878        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
879
880        ensureValidDirection(direction);
881        ensureValidStreamType(streamType);
882
883        // use stream type alias here so that streams with same alias have the same behavior,
884        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
885        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
886        int streamTypeAlias = mStreamVolumeAlias[streamType];
887        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
888
889        final int device = getDeviceForStream(streamTypeAlias);
890
891        int aliasIndex = streamState.getIndex(device);
892        boolean adjustVolume = true;
893        int step;
894
895        // skip a2dp absolute volume control request when the device
896        // is not an a2dp device
897        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
898            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
899            return;
900        }
901
902        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
903                callingPackage) != AppOpsManager.MODE_ALLOWED) {
904            return;
905        }
906
907        // reset any pending volume command
908        synchronized (mSafeMediaVolumeState) {
909            mPendingVolumeCommand = null;
910        }
911
912        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
913        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
914               ((device & mFixedVolumeDevices) != 0)) {
915            flags |= AudioManager.FLAG_FIXED_VOLUME;
916
917            // Always toggle between max safe volume and 0 for fixed volume devices where safe
918            // volume is enforced, and max and 0 for the others.
919            // This is simulated by stepping by the full allowed volume range
920            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
921                    (device & mSafeMediaVolumeDevices) != 0) {
922                step = mSafeMediaVolumeIndex;
923            } else {
924                step = streamState.getMaxIndex();
925            }
926            if (aliasIndex != 0) {
927                aliasIndex = step;
928            }
929        } else {
930            // convert one UI step (+/-1) into a number of internal units on the stream alias
931            step = rescaleIndex(10, streamType, streamTypeAlias);
932        }
933
934        // If either the client forces allowing ringer modes for this adjustment,
935        // or the stream type is one that is affected by ringer modes
936        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
937                (streamTypeAlias == getMasterStreamType())) {
938            int ringerMode = getRingerMode();
939            // do not vibrate if already in vibrate mode
940            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
941                flags &= ~AudioManager.FLAG_VIBRATE;
942            }
943            // Check if the ringer mode changes with this volume adjustment. If
944            // it does, it will handle adjusting the volume, so we won't below
945            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
946        }
947
948        int oldIndex = mStreamStates[streamType].getIndex(device);
949
950        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
951
952            // Check if volume update should be send to AVRCP
953            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
954                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
955                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
956                synchronized (mA2dpAvrcpLock) {
957                    if (mA2dp != null && mAvrcpAbsVolSupported) {
958                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
959                    }
960                }
961            }
962
963            if ((direction == AudioManager.ADJUST_RAISE) &&
964                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
965                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
966                mVolumeController.postDisplaySafeVolumeWarning(flags);
967            } else if (streamState.adjustIndex(direction * step, device)) {
968                // Post message to set system volume (it in turn will post a message
969                // to persist). Do not change volume if stream is muted.
970                sendMsg(mAudioHandler,
971                        MSG_SET_DEVICE_VOLUME,
972                        SENDMSG_QUEUE,
973                        device,
974                        0,
975                        streamState,
976                        0);
977            }
978        }
979        int index = mStreamStates[streamType].getIndex(device);
980        sendVolumeUpdate(streamType, oldIndex, index, flags);
981    }
982
983    /** @see AudioManager#adjustMasterVolume(int, int) */
984    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
985        if (mUseFixedVolume) {
986            return;
987        }
988        ensureValidSteps(steps);
989        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
990        int delta = 0;
991        int numSteps = Math.abs(steps);
992        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
993        for (int i = 0; i < numSteps; ++i) {
994            delta = findVolumeDelta(direction, volume);
995            volume += delta;
996        }
997
998        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
999        setMasterVolume(volume, flags, callingPackage);
1000    }
1001
1002    // StreamVolumeCommand contains the information needed to defer the process of
1003    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1004    class StreamVolumeCommand {
1005        public final int mStreamType;
1006        public final int mIndex;
1007        public final int mFlags;
1008        public final int mDevice;
1009
1010        StreamVolumeCommand(int streamType, int index, int flags, int device) {
1011            mStreamType = streamType;
1012            mIndex = index;
1013            mFlags = flags;
1014            mDevice = device;
1015        }
1016    };
1017
1018    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
1019        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
1020        // setting volume on master stream type also controls silent mode
1021        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1022                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1023            int newRingerMode;
1024            if (index == 0) {
1025                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
1026                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1027                        : AudioManager.RINGER_MODE_NORMAL;
1028            } else {
1029                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1030            }
1031            setRingerMode(newRingerMode);
1032        }
1033    }
1034
1035    /** @see AudioManager#setStreamVolume(int, int, int) */
1036    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
1037        if (mUseFixedVolume) {
1038            return;
1039        }
1040
1041        ensureValidStreamType(streamType);
1042        int streamTypeAlias = mStreamVolumeAlias[streamType];
1043        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1044
1045        final int device = getDeviceForStream(streamType);
1046        int oldIndex;
1047
1048        // skip a2dp absolute volume control request when the device
1049        // is not an a2dp device
1050        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1051            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1052            return;
1053        }
1054
1055        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1056                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1057            return;
1058        }
1059
1060        synchronized (mSafeMediaVolumeState) {
1061            // reset any pending volume command
1062            mPendingVolumeCommand = null;
1063
1064            oldIndex = streamState.getIndex(device);
1065
1066            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1067
1068            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1069                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1070                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1071                synchronized (mA2dpAvrcpLock) {
1072                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1073                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
1074                    }
1075                }
1076            }
1077
1078            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1079            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1080                    ((device & mFixedVolumeDevices) != 0)) {
1081                flags |= AudioManager.FLAG_FIXED_VOLUME;
1082
1083                // volume is either 0 or max allowed for fixed volume devices
1084                if (index != 0) {
1085                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1086                            (device & mSafeMediaVolumeDevices) != 0) {
1087                        index = mSafeMediaVolumeIndex;
1088                    } else {
1089                        index = streamState.getMaxIndex();
1090                    }
1091                }
1092            }
1093
1094            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
1095                mVolumeController.postDisplaySafeVolumeWarning(flags);
1096                mPendingVolumeCommand = new StreamVolumeCommand(
1097                                                    streamType, index, flags, device);
1098            } else {
1099                onSetStreamVolume(streamType, index, flags, device);
1100                index = mStreamStates[streamType].getIndex(device);
1101            }
1102        }
1103        sendVolumeUpdate(streamType, oldIndex, index, flags);
1104    }
1105
1106    /** @see AudioManager#forceVolumeControlStream(int) */
1107    public void forceVolumeControlStream(int streamType, IBinder cb) {
1108        synchronized(mForceControlStreamLock) {
1109            mVolumeControlStream = streamType;
1110            if (mVolumeControlStream == -1) {
1111                if (mForceControlStreamClient != null) {
1112                    mForceControlStreamClient.release();
1113                    mForceControlStreamClient = null;
1114                }
1115            } else {
1116                mForceControlStreamClient = new ForceControlStreamClient(cb);
1117            }
1118        }
1119    }
1120
1121    private class ForceControlStreamClient implements IBinder.DeathRecipient {
1122        private IBinder mCb; // To be notified of client's death
1123
1124        ForceControlStreamClient(IBinder cb) {
1125            if (cb != null) {
1126                try {
1127                    cb.linkToDeath(this, 0);
1128                } catch (RemoteException e) {
1129                    // Client has died!
1130                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1131                    cb = null;
1132                }
1133            }
1134            mCb = cb;
1135        }
1136
1137        public void binderDied() {
1138            synchronized(mForceControlStreamLock) {
1139                Log.w(TAG, "SCO client died");
1140                if (mForceControlStreamClient != this) {
1141                    Log.w(TAG, "unregistered control stream client died");
1142                } else {
1143                    mForceControlStreamClient = null;
1144                    mVolumeControlStream = -1;
1145                }
1146            }
1147        }
1148
1149        public void release() {
1150            if (mCb != null) {
1151                mCb.unlinkToDeath(this, 0);
1152                mCb = null;
1153            }
1154        }
1155    }
1156
1157    private int findVolumeDelta(int direction, int volume) {
1158        int delta = 0;
1159        if (direction == AudioManager.ADJUST_RAISE) {
1160            if (volume == MAX_MASTER_VOLUME) {
1161                return 0;
1162            }
1163            // This is the default value if we make it to the end
1164            delta = mMasterVolumeRamp[1];
1165            // If we're raising the volume move down the ramp array until we
1166            // find the volume we're above and use that groups delta.
1167            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1168                if (volume >= mMasterVolumeRamp[i - 1]) {
1169                    delta = mMasterVolumeRamp[i];
1170                    break;
1171                }
1172            }
1173        } else if (direction == AudioManager.ADJUST_LOWER){
1174            if (volume == 0) {
1175                return 0;
1176            }
1177            int length = mMasterVolumeRamp.length;
1178            // This is the default value if we make it to the end
1179            delta = -mMasterVolumeRamp[length - 1];
1180            // If we're lowering the volume move up the ramp array until we
1181            // find the volume we're below and use the group below it's delta
1182            for (int i = 2; i < length; i += 2) {
1183                if (volume <= mMasterVolumeRamp[i]) {
1184                    delta = -mMasterVolumeRamp[i - 1];
1185                    break;
1186                }
1187            }
1188        }
1189        return delta;
1190    }
1191
1192    private void sendBroadcastToAll(Intent intent) {
1193        final long ident = Binder.clearCallingIdentity();
1194        try {
1195            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1196        } finally {
1197            Binder.restoreCallingIdentity(ident);
1198        }
1199    }
1200
1201    private void sendStickyBroadcastToAll(Intent intent) {
1202        final long ident = Binder.clearCallingIdentity();
1203        try {
1204            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1205        } finally {
1206            Binder.restoreCallingIdentity(ident);
1207        }
1208    }
1209
1210    // UI update and Broadcast Intent
1211    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1212        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
1213            streamType = AudioSystem.STREAM_NOTIFICATION;
1214        }
1215
1216        mVolumeController.postVolumeChanged(streamType, flags);
1217
1218        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1219            oldIndex = (oldIndex + 5) / 10;
1220            index = (index + 5) / 10;
1221            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1222            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1223            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1224            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1225            sendBroadcastToAll(intent);
1226        }
1227    }
1228
1229    // UI update and Broadcast Intent
1230    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
1231        mVolumeController.postMasterVolumeChanged(flags);
1232
1233        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1234        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1235        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
1236        sendBroadcastToAll(intent);
1237    }
1238
1239    // UI update and Broadcast Intent
1240    private void sendMasterMuteUpdate(boolean muted, int flags) {
1241        mVolumeController.postMasterMuteChanged(flags);
1242        broadcastMasterMuteStatus(muted);
1243    }
1244
1245    private void broadcastMasterMuteStatus(boolean muted) {
1246        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1247        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
1248        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1249                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1250        sendStickyBroadcastToAll(intent);
1251    }
1252
1253    /**
1254     * Sets the stream state's index, and posts a message to set system volume.
1255     * This will not call out to the UI. Assumes a valid stream type.
1256     *
1257     * @param streamType Type of the stream
1258     * @param index Desired volume index of the stream
1259     * @param device the device whose volume must be changed
1260     * @param force If true, set the volume even if the desired volume is same
1261     * as the current volume.
1262     */
1263    private void setStreamVolumeInt(int streamType,
1264                                    int index,
1265                                    int device,
1266                                    boolean force) {
1267        VolumeStreamState streamState = mStreamStates[streamType];
1268
1269        if (streamState.setIndex(index, device) || force) {
1270            // Post message to set system volume (it in turn will post a message
1271            // to persist).
1272            sendMsg(mAudioHandler,
1273                    MSG_SET_DEVICE_VOLUME,
1274                    SENDMSG_QUEUE,
1275                    device,
1276                    0,
1277                    streamState,
1278                    0);
1279        }
1280    }
1281
1282    /** @see AudioManager#setStreamSolo(int, boolean) */
1283    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
1284        if (mUseFixedVolume) {
1285            return;
1286        }
1287
1288        for (int stream = 0; stream < mStreamStates.length; stream++) {
1289            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
1290            mStreamStates[stream].mute(cb, state);
1291         }
1292    }
1293
1294    /** @see AudioManager#setStreamMute(int, boolean) */
1295    public void setStreamMute(int streamType, boolean state, IBinder cb) {
1296        if (mUseFixedVolume) {
1297            return;
1298        }
1299
1300        if (isStreamAffectedByMute(streamType)) {
1301            mStreamStates[streamType].mute(cb, state);
1302        }
1303    }
1304
1305    /** get stream mute state. */
1306    public boolean isStreamMute(int streamType) {
1307        return mStreamStates[streamType].isMuted();
1308    }
1309
1310    /** @see AudioManager#setMasterMute(boolean, int) */
1311    public void setMasterMute(boolean state, int flags, IBinder cb) {
1312        if (mUseFixedVolume) {
1313            return;
1314        }
1315
1316        if (state != AudioSystem.getMasterMute()) {
1317            AudioSystem.setMasterMute(state);
1318            // Post a persist master volume msg
1319            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
1320                    : 0, 0, null, PERSIST_DELAY);
1321            sendMasterMuteUpdate(state, flags);
1322        }
1323    }
1324
1325    /** get master mute state. */
1326    public boolean isMasterMute() {
1327        return AudioSystem.getMasterMute();
1328    }
1329
1330    protected static int getMaxStreamVolume(int streamType) {
1331        return MAX_STREAM_VOLUME[streamType];
1332    }
1333
1334    /** @see AudioManager#getStreamVolume(int) */
1335    public int getStreamVolume(int streamType) {
1336        ensureValidStreamType(streamType);
1337        int device = getDeviceForStream(streamType);
1338        int index = mStreamStates[streamType].getIndex(device);
1339
1340        // by convention getStreamVolume() returns 0 when a stream is muted.
1341        if (mStreamStates[streamType].isMuted()) {
1342            index = 0;
1343        }
1344        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1345                (device & mFixedVolumeDevices) != 0) {
1346            index = mStreamStates[streamType].getMaxIndex();
1347        }
1348        return (index + 5) / 10;
1349    }
1350
1351    public int getMasterVolume() {
1352        if (isMasterMute()) return 0;
1353        return getLastAudibleMasterVolume();
1354    }
1355
1356    public void setMasterVolume(int volume, int flags, String callingPackage) {
1357        if (mUseFixedVolume) {
1358            return;
1359        }
1360
1361        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1362                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1363            return;
1364        }
1365
1366        if (volume < 0) {
1367            volume = 0;
1368        } else if (volume > MAX_MASTER_VOLUME) {
1369            volume = MAX_MASTER_VOLUME;
1370        }
1371        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1372    }
1373
1374    private void doSetMasterVolume(float volume, int flags) {
1375        // don't allow changing master volume when muted
1376        if (!AudioSystem.getMasterMute()) {
1377            int oldVolume = getMasterVolume();
1378            AudioSystem.setMasterVolume(volume);
1379
1380            int newVolume = getMasterVolume();
1381            if (newVolume != oldVolume) {
1382                // Post a persist master volume msg
1383                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1384                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
1385            }
1386            // Send the volume update regardless whether there was a change.
1387            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
1388        }
1389    }
1390
1391    /** @see AudioManager#getStreamMaxVolume(int) */
1392    public int getStreamMaxVolume(int streamType) {
1393        ensureValidStreamType(streamType);
1394        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
1395    }
1396
1397    public int getMasterMaxVolume() {
1398        return MAX_MASTER_VOLUME;
1399    }
1400
1401    /** Get last audible volume before stream was muted. */
1402    public int getLastAudibleStreamVolume(int streamType) {
1403        ensureValidStreamType(streamType);
1404        int device = getDeviceForStream(streamType);
1405        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
1406    }
1407
1408    /** Get last audible master volume before it was muted. */
1409    public int getLastAudibleMasterVolume() {
1410        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1411    }
1412
1413    /** @see AudioManager#getMasterStreamType()  */
1414    public int getMasterStreamType() {
1415        if (mVoiceCapable) {
1416            return AudioSystem.STREAM_RING;
1417        } else {
1418            return AudioSystem.STREAM_MUSIC;
1419        }
1420    }
1421
1422    /** @see AudioManager#getRingerMode() */
1423    public int getRingerMode() {
1424        synchronized(mSettingsLock) {
1425            return mRingerMode;
1426        }
1427    }
1428
1429    private void ensureValidRingerMode(int ringerMode) {
1430        if (!AudioManager.isValidRingerMode(ringerMode)) {
1431            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1432        }
1433    }
1434
1435    /** @see AudioManager#setRingerMode(int) */
1436    public void setRingerMode(int ringerMode) {
1437        if (mUseFixedVolume) {
1438            return;
1439        }
1440
1441        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1442            ringerMode = AudioManager.RINGER_MODE_SILENT;
1443        }
1444        if (ringerMode != getRingerMode()) {
1445            setRingerModeInt(ringerMode, true);
1446            // Send sticky broadcast
1447            broadcastRingerMode(ringerMode);
1448        }
1449    }
1450
1451    private void setRingerModeInt(int ringerMode, boolean persist) {
1452        synchronized(mSettingsLock) {
1453            mRingerMode = ringerMode;
1454        }
1455
1456        // Mute stream if not previously muted by ringer mode and ringer mode
1457        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1458        // Unmute stream if previously muted by ringer mode and ringer mode
1459        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1460        int numStreamTypes = AudioSystem.getNumStreamTypes();
1461        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1462            if (isStreamMutedByRingerMode(streamType)) {
1463                if (!isStreamAffectedByRingerMode(streamType) ||
1464                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1465                    // ring and notifications volume should never be 0 when not silenced
1466                    // on voice capable devices
1467                    if (mVoiceCapable &&
1468                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1469                        synchronized (mStreamStates[streamType]) {
1470                            Set set = mStreamStates[streamType].mIndex.entrySet();
1471                            Iterator i = set.iterator();
1472                            while (i.hasNext()) {
1473                                Map.Entry entry = (Map.Entry)i.next();
1474                                if ((Integer)entry.getValue() == 0) {
1475                                    entry.setValue(10);
1476                                }
1477                            }
1478                        }
1479                    }
1480                    mStreamStates[streamType].mute(null, false);
1481                    mRingerModeMutedStreams &= ~(1 << streamType);
1482                }
1483            } else {
1484                if (isStreamAffectedByRingerMode(streamType) &&
1485                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
1486                   mStreamStates[streamType].mute(null, true);
1487                   mRingerModeMutedStreams |= (1 << streamType);
1488               }
1489            }
1490        }
1491
1492        // Post a persist ringer mode msg
1493        if (persist) {
1494            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
1495                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1496        }
1497    }
1498
1499    private void restoreMasterVolume() {
1500        if (mUseFixedVolume) {
1501            AudioSystem.setMasterVolume(1.0f);
1502            return;
1503        }
1504        if (mUseMasterVolume) {
1505            float volume = Settings.System.getFloatForUser(mContentResolver,
1506                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
1507            if (volume >= 0.0f) {
1508                AudioSystem.setMasterVolume(volume);
1509            }
1510        }
1511    }
1512
1513    /** @see AudioManager#shouldVibrate(int) */
1514    public boolean shouldVibrate(int vibrateType) {
1515        if (!mHasVibrator) return false;
1516
1517        switch (getVibrateSetting(vibrateType)) {
1518
1519            case AudioManager.VIBRATE_SETTING_ON:
1520                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
1521
1522            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1523                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
1524
1525            case AudioManager.VIBRATE_SETTING_OFF:
1526                // return false, even for incoming calls
1527                return false;
1528
1529            default:
1530                return false;
1531        }
1532    }
1533
1534    /** @see AudioManager#getVibrateSetting(int) */
1535    public int getVibrateSetting(int vibrateType) {
1536        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
1537        return (mVibrateSetting >> (vibrateType * 2)) & 3;
1538    }
1539
1540    /** @see AudioManager#setVibrateSetting(int, int) */
1541    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1542
1543        if (!mHasVibrator) return;
1544
1545        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1546
1547        // Broadcast change
1548        broadcastVibrateSetting(vibrateType);
1549
1550    }
1551
1552    /**
1553     * @see #setVibrateSetting(int, int)
1554     */
1555    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1556            int vibrateSetting) {
1557
1558        // First clear the existing setting. Each vibrate type has two bits in
1559        // the value. Note '3' is '11' in binary.
1560        existingValue &= ~(3 << (vibrateType * 2));
1561
1562        // Set into the old value
1563        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1564
1565        return existingValue;
1566    }
1567
1568    private class SetModeDeathHandler implements IBinder.DeathRecipient {
1569        private IBinder mCb; // To be notified of client's death
1570        private int mPid;
1571        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1572
1573        SetModeDeathHandler(IBinder cb, int pid) {
1574            mCb = cb;
1575            mPid = pid;
1576        }
1577
1578        public void binderDied() {
1579            int newModeOwnerPid = 0;
1580            synchronized(mSetModeDeathHandlers) {
1581                Log.w(TAG, "setMode() client died");
1582                int index = mSetModeDeathHandlers.indexOf(this);
1583                if (index < 0) {
1584                    Log.w(TAG, "unregistered setMode() client died");
1585                } else {
1586                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
1587                }
1588            }
1589            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1590            // SCO connections not started by the application changing the mode
1591            if (newModeOwnerPid != 0) {
1592                final long ident = Binder.clearCallingIdentity();
1593                disconnectBluetoothSco(newModeOwnerPid);
1594                Binder.restoreCallingIdentity(ident);
1595            }
1596        }
1597
1598        public int getPid() {
1599            return mPid;
1600        }
1601
1602        public void setMode(int mode) {
1603            mMode = mode;
1604        }
1605
1606        public int getMode() {
1607            return mMode;
1608        }
1609
1610        public IBinder getBinder() {
1611            return mCb;
1612        }
1613    }
1614
1615    /** @see AudioManager#setMode(int) */
1616    public void setMode(int mode, IBinder cb) {
1617        if (!checkAudioSettingsPermission("setMode()")) {
1618            return;
1619        }
1620
1621        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1622            return;
1623        }
1624
1625        int newModeOwnerPid = 0;
1626        synchronized(mSetModeDeathHandlers) {
1627            if (mode == AudioSystem.MODE_CURRENT) {
1628                mode = mMode;
1629            }
1630            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
1631        }
1632        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1633        // SCO connections not started by the application changing the mode
1634        if (newModeOwnerPid != 0) {
1635             disconnectBluetoothSco(newModeOwnerPid);
1636        }
1637    }
1638
1639    // must be called synchronized on mSetModeDeathHandlers
1640    // setModeInt() returns a valid PID if the audio mode was successfully set to
1641    // any mode other than NORMAL.
1642    int setModeInt(int mode, IBinder cb, int pid) {
1643        int newModeOwnerPid = 0;
1644        if (cb == null) {
1645            Log.e(TAG, "setModeInt() called with null binder");
1646            return newModeOwnerPid;
1647        }
1648
1649        SetModeDeathHandler hdlr = null;
1650        Iterator iter = mSetModeDeathHandlers.iterator();
1651        while (iter.hasNext()) {
1652            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1653            if (h.getPid() == pid) {
1654                hdlr = h;
1655                // Remove from client list so that it is re-inserted at top of list
1656                iter.remove();
1657                hdlr.getBinder().unlinkToDeath(hdlr, 0);
1658                break;
1659            }
1660        }
1661        int status = AudioSystem.AUDIO_STATUS_OK;
1662        do {
1663            if (mode == AudioSystem.MODE_NORMAL) {
1664                // get new mode from client at top the list if any
1665                if (!mSetModeDeathHandlers.isEmpty()) {
1666                    hdlr = mSetModeDeathHandlers.get(0);
1667                    cb = hdlr.getBinder();
1668                    mode = hdlr.getMode();
1669                }
1670            } else {
1671                if (hdlr == null) {
1672                    hdlr = new SetModeDeathHandler(cb, pid);
1673                }
1674                // Register for client death notification
1675                try {
1676                    cb.linkToDeath(hdlr, 0);
1677                } catch (RemoteException e) {
1678                    // Client has died!
1679                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1680                }
1681
1682                // Last client to call setMode() is always at top of client list
1683                // as required by SetModeDeathHandler.binderDied()
1684                mSetModeDeathHandlers.add(0, hdlr);
1685                hdlr.setMode(mode);
1686            }
1687
1688            if (mode != mMode) {
1689                status = AudioSystem.setPhoneState(mode);
1690                if (status == AudioSystem.AUDIO_STATUS_OK) {
1691                    mMode = mode;
1692                } else {
1693                    if (hdlr != null) {
1694                        mSetModeDeathHandlers.remove(hdlr);
1695                        cb.unlinkToDeath(hdlr, 0);
1696                    }
1697                    // force reading new top of mSetModeDeathHandlers stack
1698                    mode = AudioSystem.MODE_NORMAL;
1699                }
1700            } else {
1701                status = AudioSystem.AUDIO_STATUS_OK;
1702            }
1703        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1704
1705        if (status == AudioSystem.AUDIO_STATUS_OK) {
1706            if (mode != AudioSystem.MODE_NORMAL) {
1707                if (mSetModeDeathHandlers.isEmpty()) {
1708                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1709                } else {
1710                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1711                }
1712            }
1713            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
1714            if (streamType == STREAM_REMOTE_MUSIC) {
1715                // here handle remote media playback the same way as local playback
1716                streamType = AudioManager.STREAM_MUSIC;
1717            }
1718            int device = getDeviceForStream(streamType);
1719            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1720            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
1721
1722            updateStreamVolumeAlias(true /*updateVolumes*/);
1723        }
1724        return newModeOwnerPid;
1725    }
1726
1727    /** @see AudioManager#getMode() */
1728    public int getMode() {
1729        return mMode;
1730    }
1731
1732    //==========================================================================================
1733    // Sound Effects
1734    //==========================================================================================
1735
1736    private static final String TAG_AUDIO_ASSETS = "audio_assets";
1737    private static final String ATTR_VERSION = "version";
1738    private static final String TAG_GROUP = "group";
1739    private static final String ATTR_GROUP_NAME = "name";
1740    private static final String TAG_ASSET = "asset";
1741    private static final String ATTR_ASSET_ID = "id";
1742    private static final String ATTR_ASSET_FILE = "file";
1743
1744    private static final String ASSET_FILE_VERSION = "1.0";
1745    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1746
1747    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
1748
1749    class LoadSoundEffectReply {
1750        public int mStatus = 1;
1751    };
1752
1753    private void loadTouchSoundAssetDefaults() {
1754        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1755        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1756            SOUND_EFFECT_FILES_MAP[i][0] = 0;
1757            SOUND_EFFECT_FILES_MAP[i][1] = -1;
1758        }
1759    }
1760
1761    private void loadTouchSoundAssets() {
1762        XmlResourceParser parser = null;
1763
1764        // only load assets once.
1765        if (!SOUND_EFFECT_FILES.isEmpty()) {
1766            return;
1767        }
1768
1769        loadTouchSoundAssetDefaults();
1770
1771        try {
1772            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1773
1774            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1775            String version = parser.getAttributeValue(null, ATTR_VERSION);
1776            boolean inTouchSoundsGroup = false;
1777
1778            if (ASSET_FILE_VERSION.equals(version)) {
1779                while (true) {
1780                    XmlUtils.nextElement(parser);
1781                    String element = parser.getName();
1782                    if (element == null) {
1783                        break;
1784                    }
1785                    if (element.equals(TAG_GROUP)) {
1786                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1787                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
1788                            inTouchSoundsGroup = true;
1789                            break;
1790                        }
1791                    }
1792                }
1793                while (inTouchSoundsGroup) {
1794                    XmlUtils.nextElement(parser);
1795                    String element = parser.getName();
1796                    if (element == null) {
1797                        break;
1798                    }
1799                    if (element.equals(TAG_ASSET)) {
1800                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1801                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1802                        int fx;
1803
1804                        try {
1805                            Field field = AudioManager.class.getField(id);
1806                            fx = field.getInt(null);
1807                        } catch (Exception e) {
1808                            Log.w(TAG, "Invalid touch sound ID: "+id);
1809                            continue;
1810                        }
1811
1812                        int i = SOUND_EFFECT_FILES.indexOf(file);
1813                        if (i == -1) {
1814                            i = SOUND_EFFECT_FILES.size();
1815                            SOUND_EFFECT_FILES.add(file);
1816                        }
1817                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
1818                    } else {
1819                        break;
1820                    }
1821                }
1822            }
1823        } catch (Resources.NotFoundException e) {
1824            Log.w(TAG, "audio assets file not found", e);
1825        } catch (XmlPullParserException e) {
1826            Log.w(TAG, "XML parser exception reading touch sound assets", e);
1827        } catch (IOException e) {
1828            Log.w(TAG, "I/O exception reading touch sound assets", e);
1829        } finally {
1830            if (parser != null) {
1831                parser.close();
1832            }
1833        }
1834    }
1835
1836    /** @see AudioManager#playSoundEffect(int) */
1837    public void playSoundEffect(int effectType) {
1838        playSoundEffectVolume(effectType, -1.0f);
1839    }
1840
1841    /** @see AudioManager#playSoundEffect(int, float) */
1842    public void playSoundEffectVolume(int effectType, float volume) {
1843        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1844            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1845            return;
1846        }
1847
1848        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
1849                effectType, (int) (volume * 1000), null, 0);
1850    }
1851
1852    /**
1853     * Loads samples into the soundpool.
1854     * This method must be called at first when sound effects are enabled
1855     */
1856    public boolean loadSoundEffects() {
1857        int attempts = 3;
1858        LoadSoundEffectReply reply = new LoadSoundEffectReply();
1859
1860        synchronized (reply) {
1861            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
1862            while ((reply.mStatus == 1) && (attempts-- > 0)) {
1863                try {
1864                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
1865                } catch (InterruptedException e) {
1866                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
1867                }
1868            }
1869        }
1870        return (reply.mStatus == 0);
1871    }
1872
1873    /**
1874     *  Unloads samples from the sound pool.
1875     *  This method can be called to free some memory when
1876     *  sound effects are disabled.
1877     */
1878    public void unloadSoundEffects() {
1879        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
1880    }
1881
1882    class SoundPoolListenerThread extends Thread {
1883        public SoundPoolListenerThread() {
1884            super("SoundPoolListenerThread");
1885        }
1886
1887        @Override
1888        public void run() {
1889
1890            Looper.prepare();
1891            mSoundPoolLooper = Looper.myLooper();
1892
1893            synchronized (mSoundEffectsLock) {
1894                if (mSoundPool != null) {
1895                    mSoundPoolCallBack = new SoundPoolCallback();
1896                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1897                }
1898                mSoundEffectsLock.notify();
1899            }
1900            Looper.loop();
1901        }
1902    }
1903
1904    private final class SoundPoolCallback implements
1905            android.media.SoundPool.OnLoadCompleteListener {
1906
1907        int mStatus = 1; // 1 means neither error nor last sample loaded yet
1908        List<Integer> mSamples = new ArrayList<Integer>();
1909
1910        public int status() {
1911            return mStatus;
1912        }
1913
1914        public void setSamples(int[] samples) {
1915            for (int i = 0; i < samples.length; i++) {
1916                // do not wait ack for samples rejected upfront by SoundPool
1917                if (samples[i] > 0) {
1918                    mSamples.add(samples[i]);
1919                }
1920            }
1921        }
1922
1923        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1924            synchronized (mSoundEffectsLock) {
1925                int i = mSamples.indexOf(sampleId);
1926                if (i >= 0) {
1927                    mSamples.remove(i);
1928                }
1929                if ((status != 0) || mSamples. isEmpty()) {
1930                    mStatus = status;
1931                    mSoundEffectsLock.notify();
1932                }
1933            }
1934        }
1935    }
1936
1937    /** @see AudioManager#reloadAudioSettings() */
1938    public void reloadAudioSettings() {
1939        readAudioSettings(false /*userSwitch*/);
1940    }
1941
1942    private void readAudioSettings(boolean userSwitch) {
1943        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
1944        readPersistedSettings();
1945
1946        // restore volume settings
1947        int numStreamTypes = AudioSystem.getNumStreamTypes();
1948        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1949            VolumeStreamState streamState = mStreamStates[streamType];
1950
1951            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1952                continue;
1953            }
1954
1955            synchronized (streamState) {
1956                streamState.readSettings();
1957
1958                // unmute stream that was muted but is not affect by mute anymore
1959                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
1960                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
1961                    int size = streamState.mDeathHandlers.size();
1962                    for (int i = 0; i < size; i++) {
1963                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
1964                        streamState.mDeathHandlers.get(i).mute(false);
1965                    }
1966                }
1967            }
1968        }
1969
1970        // apply new ringer mode before checking volume for alias streams so that streams
1971        // muted by ringer mode have the correct volume
1972        setRingerModeInt(getRingerMode(), false);
1973
1974        checkAllAliasStreamVolumes();
1975
1976        synchronized (mSafeMediaVolumeState) {
1977            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
1978                enforceSafeMediaVolume();
1979            }
1980        }
1981    }
1982
1983    /** @see AudioManager#setSpeakerphoneOn(boolean) */
1984    public void setSpeakerphoneOn(boolean on){
1985        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1986            return;
1987        }
1988
1989        if (on) {
1990            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
1991                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1992                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
1993            }
1994            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
1995        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
1996            mForcedUseForComm = AudioSystem.FORCE_NONE;
1997        }
1998
1999        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2000                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2001    }
2002
2003    /** @see AudioManager#isSpeakerphoneOn() */
2004    public boolean isSpeakerphoneOn() {
2005        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2006    }
2007
2008    /** @see AudioManager#setBluetoothScoOn(boolean) */
2009    public void setBluetoothScoOn(boolean on){
2010        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2011            return;
2012        }
2013
2014        if (on) {
2015            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2016        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2017            mForcedUseForComm = AudioSystem.FORCE_NONE;
2018        }
2019
2020        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2021                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2022        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2023                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2024    }
2025
2026    /** @see AudioManager#isBluetoothScoOn() */
2027    public boolean isBluetoothScoOn() {
2028        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2029    }
2030
2031    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
2032    public void setBluetoothA2dpOn(boolean on) {
2033        synchronized (mBluetoothA2dpEnabledLock) {
2034            mBluetoothA2dpEnabled = on;
2035            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2036                    AudioSystem.FOR_MEDIA,
2037                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2038                    null, 0);
2039        }
2040    }
2041
2042    /** @see AudioManager#isBluetoothA2dpOn() */
2043    public boolean isBluetoothA2dpOn() {
2044        synchronized (mBluetoothA2dpEnabledLock) {
2045            return mBluetoothA2dpEnabled;
2046        }
2047    }
2048
2049    /** @see AudioManager#startBluetoothSco() */
2050    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
2051        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
2052                !mSystemReady) {
2053            return;
2054        }
2055        ScoClient client = getScoClient(cb, true);
2056        // The calling identity must be cleared before calling ScoClient.incCount().
2057        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2058        // and this must be done on behalf of system server to make sure permissions are granted.
2059        // The caller identity must be cleared after getScoClient() because it is needed if a new
2060        // client is created.
2061        final long ident = Binder.clearCallingIdentity();
2062        client.incCount(targetSdkVersion);
2063        Binder.restoreCallingIdentity(ident);
2064    }
2065
2066    /** @see AudioManager#stopBluetoothSco() */
2067    public void stopBluetoothSco(IBinder cb){
2068        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
2069                !mSystemReady) {
2070            return;
2071        }
2072        ScoClient client = getScoClient(cb, false);
2073        // The calling identity must be cleared before calling ScoClient.decCount().
2074        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2075        // and this must be done on behalf of system server to make sure permissions are granted.
2076        final long ident = Binder.clearCallingIdentity();
2077        if (client != null) {
2078            client.decCount();
2079        }
2080        Binder.restoreCallingIdentity(ident);
2081    }
2082
2083
2084    private class ScoClient implements IBinder.DeathRecipient {
2085        private IBinder mCb; // To be notified of client's death
2086        private int mCreatorPid;
2087        private int mStartcount; // number of SCO connections started by this client
2088
2089        ScoClient(IBinder cb) {
2090            mCb = cb;
2091            mCreatorPid = Binder.getCallingPid();
2092            mStartcount = 0;
2093        }
2094
2095        public void binderDied() {
2096            synchronized(mScoClients) {
2097                Log.w(TAG, "SCO client died");
2098                int index = mScoClients.indexOf(this);
2099                if (index < 0) {
2100                    Log.w(TAG, "unregistered SCO client died");
2101                } else {
2102                    clearCount(true);
2103                    mScoClients.remove(this);
2104                }
2105            }
2106        }
2107
2108        public void incCount(int targetSdkVersion) {
2109            synchronized(mScoClients) {
2110                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
2111                if (mStartcount == 0) {
2112                    try {
2113                        mCb.linkToDeath(this, 0);
2114                    } catch (RemoteException e) {
2115                        // client has already died!
2116                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
2117                    }
2118                }
2119                mStartcount++;
2120            }
2121        }
2122
2123        public void decCount() {
2124            synchronized(mScoClients) {
2125                if (mStartcount == 0) {
2126                    Log.w(TAG, "ScoClient.decCount() already 0");
2127                } else {
2128                    mStartcount--;
2129                    if (mStartcount == 0) {
2130                        try {
2131                            mCb.unlinkToDeath(this, 0);
2132                        } catch (NoSuchElementException e) {
2133                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2134                        }
2135                    }
2136                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2137                }
2138            }
2139        }
2140
2141        public void clearCount(boolean stopSco) {
2142            synchronized(mScoClients) {
2143                if (mStartcount != 0) {
2144                    try {
2145                        mCb.unlinkToDeath(this, 0);
2146                    } catch (NoSuchElementException e) {
2147                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2148                    }
2149                }
2150                mStartcount = 0;
2151                if (stopSco) {
2152                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2153                }
2154            }
2155        }
2156
2157        public int getCount() {
2158            return mStartcount;
2159        }
2160
2161        public IBinder getBinder() {
2162            return mCb;
2163        }
2164
2165        public int getPid() {
2166            return mCreatorPid;
2167        }
2168
2169        public int totalCount() {
2170            synchronized(mScoClients) {
2171                int count = 0;
2172                int size = mScoClients.size();
2173                for (int i = 0; i < size; i++) {
2174                    count += mScoClients.get(i).getCount();
2175                }
2176                return count;
2177            }
2178        }
2179
2180        private void requestScoState(int state, int targetSdkVersion) {
2181            checkScoAudioState();
2182            if (totalCount() == 0) {
2183                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2184                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2185                    // the connection.
2186                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2187                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2188                    // currently controlled by the same client process.
2189                    synchronized(mSetModeDeathHandlers) {
2190                        if ((mSetModeDeathHandlers.isEmpty() ||
2191                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2192                                (mScoAudioState == SCO_STATE_INACTIVE ||
2193                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2194                            if (mScoAudioState == SCO_STATE_INACTIVE) {
2195                                mScoAudioMode =
2196                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2197                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
2198                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2199                                    boolean status;
2200                                    if (mScoAudioMode == SCO_MODE_RAW) {
2201                                        status = mBluetoothHeadset.connectAudio();
2202                                    } else {
2203                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2204                                                                            mBluetoothHeadsetDevice);
2205                                    }
2206                                    if (status) {
2207                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2208                                    } else {
2209                                        broadcastScoConnectionState(
2210                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2211                                    }
2212                                } else if (getBluetoothHeadset()) {
2213                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2214                                }
2215                            } else {
2216                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2217                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2218                            }
2219                        } else {
2220                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2221                        }
2222                    }
2223                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2224                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2225                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2226                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2227                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2228                            boolean status;
2229                            if (mScoAudioMode == SCO_MODE_RAW) {
2230                                status = mBluetoothHeadset.disconnectAudio();
2231                            } else {
2232                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2233                                                                        mBluetoothHeadsetDevice);
2234                            }
2235                            if (!status) {
2236                                mScoAudioState = SCO_STATE_INACTIVE;
2237                                broadcastScoConnectionState(
2238                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2239                            }
2240                        } else if (getBluetoothHeadset()) {
2241                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2242                        }
2243                    } else {
2244                        mScoAudioState = SCO_STATE_INACTIVE;
2245                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2246                    }
2247                }
2248            }
2249        }
2250    }
2251
2252    private void checkScoAudioState() {
2253        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2254                mScoAudioState == SCO_STATE_INACTIVE &&
2255                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2256                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2257            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2258        }
2259    }
2260
2261    private ScoClient getScoClient(IBinder cb, boolean create) {
2262        synchronized(mScoClients) {
2263            ScoClient client = null;
2264            int size = mScoClients.size();
2265            for (int i = 0; i < size; i++) {
2266                client = mScoClients.get(i);
2267                if (client.getBinder() == cb)
2268                    return client;
2269            }
2270            if (create) {
2271                client = new ScoClient(cb);
2272                mScoClients.add(client);
2273            }
2274            return client;
2275        }
2276    }
2277
2278    public void clearAllScoClients(int exceptPid, boolean stopSco) {
2279        synchronized(mScoClients) {
2280            ScoClient savedClient = null;
2281            int size = mScoClients.size();
2282            for (int i = 0; i < size; i++) {
2283                ScoClient cl = mScoClients.get(i);
2284                if (cl.getPid() != exceptPid) {
2285                    cl.clearCount(stopSco);
2286                } else {
2287                    savedClient = cl;
2288                }
2289            }
2290            mScoClients.clear();
2291            if (savedClient != null) {
2292                mScoClients.add(savedClient);
2293            }
2294        }
2295    }
2296
2297    private boolean getBluetoothHeadset() {
2298        boolean result = false;
2299        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2300        if (adapter != null) {
2301            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2302                                    BluetoothProfile.HEADSET);
2303        }
2304        // If we could not get a bluetooth headset proxy, send a failure message
2305        // without delay to reset the SCO audio state and clear SCO clients.
2306        // If we could get a proxy, send a delayed failure message that will reset our state
2307        // in case we don't receive onServiceConnected().
2308        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2309                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2310        return result;
2311    }
2312
2313    private void disconnectBluetoothSco(int exceptPid) {
2314        synchronized(mScoClients) {
2315            checkScoAudioState();
2316            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2317                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2318                if (mBluetoothHeadsetDevice != null) {
2319                    if (mBluetoothHeadset != null) {
2320                        if (!mBluetoothHeadset.stopVoiceRecognition(
2321                                mBluetoothHeadsetDevice)) {
2322                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2323                                    SENDMSG_REPLACE, 0, 0, null, 0);
2324                        }
2325                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2326                            getBluetoothHeadset()) {
2327                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2328                    }
2329                }
2330            } else {
2331                clearAllScoClients(exceptPid, true);
2332            }
2333        }
2334    }
2335
2336    private void resetBluetoothSco() {
2337        synchronized(mScoClients) {
2338            clearAllScoClients(0, false);
2339            mScoAudioState = SCO_STATE_INACTIVE;
2340            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2341        }
2342    }
2343
2344    private void broadcastScoConnectionState(int state) {
2345        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2346                SENDMSG_QUEUE, state, 0, null, 0);
2347    }
2348
2349    private void onBroadcastScoConnectionState(int state) {
2350        if (state != mScoConnectionState) {
2351            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2352            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2353            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2354                    mScoConnectionState);
2355            sendStickyBroadcastToAll(newIntent);
2356            mScoConnectionState = state;
2357        }
2358    }
2359
2360    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2361        new BluetoothProfile.ServiceListener() {
2362        public void onServiceConnected(int profile, BluetoothProfile proxy) {
2363            BluetoothDevice btDevice;
2364            List<BluetoothDevice> deviceList;
2365            switch(profile) {
2366            case BluetoothProfile.A2DP:
2367                synchronized (mA2dpAvrcpLock) {
2368                    mA2dp = (BluetoothA2dp) proxy;
2369                    deviceList = mA2dp.getConnectedDevices();
2370                    if (deviceList.size() > 0) {
2371                        btDevice = deviceList.get(0);
2372                        synchronized (mConnectedDevices) {
2373                            int state = mA2dp.getConnectionState(btDevice);
2374                            int delay = checkSendBecomingNoisyIntent(
2375                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2376                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2377                            queueMsgUnderWakeLock(mAudioHandler,
2378                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
2379                                    state,
2380                                    0,
2381                                    btDevice,
2382                                    delay);
2383                        }
2384                    }
2385                }
2386                break;
2387
2388            case BluetoothProfile.A2DP_SINK:
2389                deviceList = proxy.getConnectedDevices();
2390                if (deviceList.size() > 0) {
2391                    btDevice = deviceList.get(0);
2392                    synchronized (mConnectedDevices) {
2393                        int state = proxy.getConnectionState(btDevice);
2394                        queueMsgUnderWakeLock(mAudioHandler,
2395                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
2396                                state,
2397                                0,
2398                                btDevice,
2399                                0 /* delay */);
2400                    }
2401                }
2402                break;
2403
2404            case BluetoothProfile.HEADSET:
2405                synchronized (mScoClients) {
2406                    // Discard timeout message
2407                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2408                    mBluetoothHeadset = (BluetoothHeadset) proxy;
2409                    deviceList = mBluetoothHeadset.getConnectedDevices();
2410                    if (deviceList.size() > 0) {
2411                        mBluetoothHeadsetDevice = deviceList.get(0);
2412                    } else {
2413                        mBluetoothHeadsetDevice = null;
2414                    }
2415                    // Refresh SCO audio state
2416                    checkScoAudioState();
2417                    // Continue pending action if any
2418                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2419                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2420                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2421                        boolean status = false;
2422                        if (mBluetoothHeadsetDevice != null) {
2423                            switch (mScoAudioState) {
2424                            case SCO_STATE_ACTIVATE_REQ:
2425                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2426                                if (mScoAudioMode == SCO_MODE_RAW) {
2427                                    status = mBluetoothHeadset.connectAudio();
2428                                } else {
2429                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2430                                                                        mBluetoothHeadsetDevice);
2431                                }
2432                                break;
2433                            case SCO_STATE_DEACTIVATE_REQ:
2434                                if (mScoAudioMode == SCO_MODE_RAW) {
2435                                    status = mBluetoothHeadset.disconnectAudio();
2436                                } else {
2437                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2438                                                                        mBluetoothHeadsetDevice);
2439                                }
2440                                break;
2441                            case SCO_STATE_DEACTIVATE_EXT_REQ:
2442                                status = mBluetoothHeadset.stopVoiceRecognition(
2443                                        mBluetoothHeadsetDevice);
2444                            }
2445                        }
2446                        if (!status) {
2447                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2448                                    SENDMSG_REPLACE, 0, 0, null, 0);
2449                        }
2450                    }
2451                }
2452                break;
2453
2454            default:
2455                break;
2456            }
2457        }
2458        public void onServiceDisconnected(int profile) {
2459            switch(profile) {
2460            case BluetoothProfile.A2DP:
2461                synchronized (mA2dpAvrcpLock) {
2462                    mA2dp = null;
2463                    synchronized (mConnectedDevices) {
2464                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2465                            makeA2dpDeviceUnavailableNow(
2466                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2467                        }
2468                    }
2469                }
2470                break;
2471
2472            case BluetoothProfile.A2DP_SINK:
2473                synchronized (mConnectedDevices) {
2474                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2475                        makeA2dpSrcUnavailable(
2476                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2477                    }
2478                }
2479                break;
2480
2481            case BluetoothProfile.HEADSET:
2482                synchronized (mScoClients) {
2483                    mBluetoothHeadset = null;
2484                }
2485                break;
2486
2487            default:
2488                break;
2489            }
2490        }
2491    };
2492
2493    private void onCheckMusicActive() {
2494        synchronized (mSafeMediaVolumeState) {
2495            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2496                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2497
2498                if ((device & mSafeMediaVolumeDevices) != 0) {
2499                    sendMsg(mAudioHandler,
2500                            MSG_CHECK_MUSIC_ACTIVE,
2501                            SENDMSG_REPLACE,
2502                            0,
2503                            0,
2504                            null,
2505                            MUSIC_ACTIVE_POLL_PERIOD_MS);
2506                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2507                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2508                            (index > mSafeMediaVolumeIndex)) {
2509                        // Approximate cumulative active music time
2510                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2511                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2512                            setSafeMediaVolumeEnabled(true);
2513                            mMusicActiveMs = 0;
2514                        }
2515                    }
2516                }
2517            }
2518        }
2519    }
2520
2521    private void onConfigureSafeVolume(boolean force) {
2522        synchronized (mSafeMediaVolumeState) {
2523            int mcc = mContext.getResources().getConfiguration().mcc;
2524            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2525                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2526                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2527                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2528                        com.android.internal.R.bool.config_safe_media_volume_enabled);
2529
2530                // The persisted state is either "disabled" or "active": this is the state applied
2531                // next time we boot and cannot be "inactive"
2532                int persistedState;
2533                if (safeMediaVolumeEnabled) {
2534                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2535                    // The state can already be "inactive" here if the user has forced it before
2536                    // the 30 seconds timeout for forced configuration. In this case we don't reset
2537                    // it to "active".
2538                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2539                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2540                        enforceSafeMediaVolume();
2541                    }
2542                } else {
2543                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2544                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2545                }
2546                mMcc = mcc;
2547                sendMsg(mAudioHandler,
2548                        MSG_PERSIST_SAFE_VOLUME_STATE,
2549                        SENDMSG_QUEUE,
2550                        persistedState,
2551                        0,
2552                        null,
2553                        0);
2554            }
2555        }
2556    }
2557
2558    ///////////////////////////////////////////////////////////////////////////
2559    // Internal methods
2560    ///////////////////////////////////////////////////////////////////////////
2561
2562    /**
2563     * Checks if the adjustment should change ringer mode instead of just
2564     * adjusting volume. If so, this will set the proper ringer mode and volume
2565     * indices on the stream states.
2566     */
2567    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
2568        boolean adjustVolumeIndex = true;
2569        int ringerMode = getRingerMode();
2570
2571        switch (ringerMode) {
2572        case RINGER_MODE_NORMAL:
2573            if (direction == AudioManager.ADJUST_LOWER) {
2574                if (mHasVibrator) {
2575                    // "step" is the delta in internal index units corresponding to a
2576                    // change of 1 in UI index units.
2577                    // Because of rounding when rescaling from one stream index range to its alias
2578                    // index range, we cannot simply test oldIndex == step:
2579                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2580                    if (step <= oldIndex && oldIndex < 2 * step) {
2581                        ringerMode = RINGER_MODE_VIBRATE;
2582                    }
2583                } else {
2584                    // (oldIndex < step) is equivalent to (old UI index == 0)
2585                    if ((oldIndex < step)
2586                            && VOLUME_SETS_RINGER_MODE_SILENT
2587                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2588                        ringerMode = RINGER_MODE_SILENT;
2589                    }
2590                }
2591            }
2592            break;
2593        case RINGER_MODE_VIBRATE:
2594            if (!mHasVibrator) {
2595                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2596                        "but no vibrator is present");
2597                break;
2598            }
2599            if ((direction == AudioManager.ADJUST_LOWER)) {
2600                if (VOLUME_SETS_RINGER_MODE_SILENT
2601                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2602                    ringerMode = RINGER_MODE_SILENT;
2603                }
2604            } else if (direction == AudioManager.ADJUST_RAISE) {
2605                ringerMode = RINGER_MODE_NORMAL;
2606            }
2607            adjustVolumeIndex = false;
2608            break;
2609        case RINGER_MODE_SILENT:
2610            if (direction == AudioManager.ADJUST_RAISE) {
2611                if (mHasVibrator) {
2612                    ringerMode = RINGER_MODE_VIBRATE;
2613                } else {
2614                    ringerMode = RINGER_MODE_NORMAL;
2615                }
2616            }
2617            adjustVolumeIndex = false;
2618            break;
2619        default:
2620            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2621            break;
2622        }
2623
2624        setRingerMode(ringerMode);
2625
2626        mPrevVolDirection = direction;
2627
2628        return adjustVolumeIndex;
2629    }
2630
2631    @Override
2632    public boolean isStreamAffectedByRingerMode(int streamType) {
2633        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
2634    }
2635
2636    private boolean isStreamMutedByRingerMode(int streamType) {
2637        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2638    }
2639
2640    boolean updateRingerModeAffectedStreams() {
2641        int ringerModeAffectedStreams;
2642        // make sure settings for ringer mode are consistent with device type: non voice capable
2643        // devices (tablets) include media stream in silent mode whereas phones don't.
2644        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2645                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2646                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2647                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2648                 UserHandle.USER_CURRENT);
2649
2650        // ringtone, notification and system streams are always affected by ringer mode
2651        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2652                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
2653                                        (1 << AudioSystem.STREAM_SYSTEM);
2654
2655        if (mVoiceCapable) {
2656            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
2657        } else {
2658            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
2659        }
2660        synchronized (mCameraSoundForced) {
2661            if (mCameraSoundForced) {
2662                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2663            } else {
2664                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2665            }
2666        }
2667        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2668            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2669        } else {
2670            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2671        }
2672
2673        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2674            Settings.System.putIntForUser(mContentResolver,
2675                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2676                    ringerModeAffectedStreams,
2677                    UserHandle.USER_CURRENT);
2678            mRingerModeAffectedStreams = ringerModeAffectedStreams;
2679            return true;
2680        }
2681        return false;
2682    }
2683
2684    public boolean isStreamAffectedByMute(int streamType) {
2685        return (mMuteAffectedStreams & (1 << streamType)) != 0;
2686    }
2687
2688    private void ensureValidDirection(int direction) {
2689        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2690            throw new IllegalArgumentException("Bad direction " + direction);
2691        }
2692    }
2693
2694    private void ensureValidSteps(int steps) {
2695        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2696            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2697        }
2698    }
2699
2700    private void ensureValidStreamType(int streamType) {
2701        if (streamType < 0 || streamType >= mStreamStates.length) {
2702            throw new IllegalArgumentException("Bad stream type " + streamType);
2703        }
2704    }
2705
2706    private boolean isInCommunication() {
2707        boolean isOffhook = false;
2708
2709        if (mVoiceCapable) {
2710            try {
2711                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
2712                if (phone != null) isOffhook = phone.isOffhook();
2713            } catch (RemoteException e) {
2714                Log.w(TAG, "Couldn't connect to phone service", e);
2715            }
2716        }
2717        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
2718    }
2719
2720    /**
2721     * For code clarity for getActiveStreamType(int)
2722     * @param delay_ms max time since last STREAM_MUSIC activity to consider
2723     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2724     *     in the last "delay_ms" ms.
2725     */
2726    private boolean isAfMusicActiveRecently(int delay_ms) {
2727        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2728                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2729    }
2730
2731    private int getActiveStreamType(int suggestedStreamType) {
2732        if (mVoiceCapable) {
2733            if (isInCommunication()) {
2734                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2735                        == AudioSystem.FORCE_BT_SCO) {
2736                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2737                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2738                } else {
2739                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2740                    return AudioSystem.STREAM_VOICE_CALL;
2741                }
2742            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2743                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2744                    if (DEBUG_VOL)
2745                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2746                    return AudioSystem.STREAM_MUSIC;
2747                } else
2748                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2749                    {
2750                        if (DEBUG_VOL)
2751                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2752                        return STREAM_REMOTE_MUSIC;
2753                    } else {
2754                        if (DEBUG_VOL)
2755                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2756                        return AudioSystem.STREAM_RING;
2757                }
2758            } else if (isAfMusicActiveRecently(0)) {
2759                if (DEBUG_VOL)
2760                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2761                return AudioSystem.STREAM_MUSIC;
2762            } else {
2763                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2764                        + suggestedStreamType);
2765                return suggestedStreamType;
2766            }
2767        } else {
2768            if (isInCommunication()) {
2769                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2770                        == AudioSystem.FORCE_BT_SCO) {
2771                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
2772                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2773                } else {
2774                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
2775                    return AudioSystem.STREAM_VOICE_CALL;
2776                }
2777            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
2778                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
2779                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
2780                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2781                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
2782                return AudioSystem.STREAM_NOTIFICATION;
2783            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2784                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2785                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2786                    return AudioSystem.STREAM_MUSIC;
2787                } else
2788                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2789                    {
2790                        if (DEBUG_VOL)
2791                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2792                        return STREAM_REMOTE_MUSIC;
2793                } else {
2794                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
2795                    return AudioSystem.STREAM_MUSIC;
2796                }
2797            } else {
2798                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2799                        + suggestedStreamType);
2800                return suggestedStreamType;
2801            }
2802        }
2803    }
2804
2805    private void broadcastRingerMode(int ringerMode) {
2806        // Send sticky broadcast
2807        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2808        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
2809        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2810                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
2811        sendStickyBroadcastToAll(broadcast);
2812    }
2813
2814    private void broadcastVibrateSetting(int vibrateType) {
2815        // Send broadcast
2816        if (ActivityManagerNative.isSystemReady()) {
2817            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
2818            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
2819            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
2820            sendBroadcastToAll(broadcast);
2821        }
2822    }
2823
2824    // Message helper methods
2825    /**
2826     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
2827     * Note that the wake lock needs to be released after the message has been handled.
2828     */
2829    private void queueMsgUnderWakeLock(Handler handler, int msg,
2830            int arg1, int arg2, Object obj, int delay) {
2831        final long ident = Binder.clearCallingIdentity();
2832        // Always acquire the wake lock as AudioService because it is released by the
2833        // message handler.
2834        mAudioEventWakeLock.acquire();
2835        Binder.restoreCallingIdentity(ident);
2836        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2837    }
2838
2839    private static void sendMsg(Handler handler, int msg,
2840            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
2841
2842        if (existingMsgPolicy == SENDMSG_REPLACE) {
2843            handler.removeMessages(msg);
2844        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2845            return;
2846        }
2847
2848        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
2849    }
2850
2851    boolean checkAudioSettingsPermission(String method) {
2852        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2853                == PackageManager.PERMISSION_GRANTED) {
2854            return true;
2855        }
2856        String msg = "Audio Settings Permission Denial: " + method + " from pid="
2857                + Binder.getCallingPid()
2858                + ", uid=" + Binder.getCallingUid();
2859        Log.w(TAG, msg);
2860        return false;
2861    }
2862
2863    private int getDeviceForStream(int stream) {
2864        int device = AudioSystem.getDevicesForStream(stream);
2865        if ((device & (device - 1)) != 0) {
2866            // Multiple device selection is either:
2867            //  - speaker + one other device: give priority to speaker in this case.
2868            //  - one A2DP device + another device: happens with duplicated output. In this case
2869            // retain the device on the A2DP output as the other must not correspond to an active
2870            // selection if not the speaker.
2871            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2872                device = AudioSystem.DEVICE_OUT_SPEAKER;
2873            } else {
2874                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2875            }
2876        }
2877        return device;
2878    }
2879
2880    public void setWiredDeviceConnectionState(int device, int state, String name) {
2881        synchronized (mConnectedDevices) {
2882            int delay = checkSendBecomingNoisyIntent(device, state);
2883            queueMsgUnderWakeLock(mAudioHandler,
2884                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2885                    device,
2886                    state,
2887                    name,
2888                    delay);
2889        }
2890    }
2891
2892    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
2893    {
2894        int delay;
2895        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
2896            throw new IllegalArgumentException("invalid profile " + profile);
2897        }
2898        synchronized (mConnectedDevices) {
2899            if (profile == BluetoothProfile.A2DP) {
2900                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2901                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2902            } else {
2903                delay = 0;
2904            }
2905            queueMsgUnderWakeLock(mAudioHandler,
2906                    (profile == BluetoothProfile.A2DP ?
2907                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
2908                    state,
2909                    0,
2910                    device,
2911                    delay);
2912        }
2913        return delay;
2914    }
2915
2916    ///////////////////////////////////////////////////////////////////////////
2917    // Inner classes
2918    ///////////////////////////////////////////////////////////////////////////
2919
2920    public class VolumeStreamState {
2921        private final int mStreamType;
2922
2923        private String mVolumeIndexSettingName;
2924        private int mIndexMax;
2925        private final ConcurrentHashMap<Integer, Integer> mIndex =
2926                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2927        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
2928
2929        private VolumeStreamState(String settingName, int streamType) {
2930
2931            mVolumeIndexSettingName = settingName;
2932
2933            mStreamType = streamType;
2934            mIndexMax = MAX_STREAM_VOLUME[streamType];
2935            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2936            mIndexMax *= 10;
2937
2938            // mDeathHandlers must be created before calling readSettings()
2939            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
2940
2941            readSettings();
2942        }
2943
2944        public String getSettingNameForDevice(int device) {
2945            String name = mVolumeIndexSettingName;
2946            String suffix = AudioSystem.getOutputDeviceName(device);
2947            if (suffix.isEmpty()) {
2948                return name;
2949            }
2950            return name + "_" + suffix;
2951        }
2952
2953        public void readSettings() {
2954            synchronized (VolumeStreamState.class) {
2955                // force maximum volume on all streams if fixed volume property is set
2956                if (mUseFixedVolume) {
2957                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
2958                    return;
2959                }
2960                // do not read system stream volume from settings: this stream is always aliased
2961                // to another stream type and its volume is never persisted. Values in settings can
2962                // only be stale values
2963                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2964                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2965                    int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2966                    synchronized (mCameraSoundForced) {
2967                        if (mCameraSoundForced) {
2968                            index = mIndexMax;
2969                        }
2970                    }
2971                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2972                    return;
2973                }
2974
2975                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
2976
2977                for (int i = 0; remainingDevices != 0; i++) {
2978                    int device = (1 << i);
2979                    if ((device & remainingDevices) == 0) {
2980                        continue;
2981                    }
2982                    remainingDevices &= ~device;
2983
2984                    // retrieve current volume for device
2985                    String name = getSettingNameForDevice(device);
2986                    // if no volume stored for current stream and device, use default volume if default
2987                    // device, continue otherwise
2988                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
2989                                            AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
2990                    int index = Settings.System.getIntForUser(
2991                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
2992                    if (index == -1) {
2993                        continue;
2994                    }
2995
2996                    // ignore settings for fixed volume devices: volume should always be at max or 0
2997                    if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
2998                            ((device & mFixedVolumeDevices) != 0)) {
2999                        mIndex.put(device, (index != 0) ? mIndexMax : 0);
3000                    } else {
3001                        mIndex.put(device, getValidIndex(10 * index));
3002                    }
3003                }
3004            }
3005        }
3006
3007        public void applyDeviceVolume(int device) {
3008            int index;
3009            if (isMuted()) {
3010                index = 0;
3011            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3012                       mAvrcpAbsVolSupported) {
3013                index = (mIndexMax + 5)/10;
3014            } else {
3015                index = (getIndex(device) + 5)/10;
3016            }
3017            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
3018        }
3019
3020        public void applyAllVolumes() {
3021            synchronized (VolumeStreamState.class) {
3022                // apply default volume first: by convention this will reset all
3023                // devices volumes in audio policy manager to the supplied value
3024                int index;
3025                if (isMuted()) {
3026                    index = 0;
3027                } else {
3028                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3029                }
3030                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3031                // then apply device specific volumes
3032                Set set = mIndex.entrySet();
3033                Iterator i = set.iterator();
3034                while (i.hasNext()) {
3035                    Map.Entry entry = (Map.Entry)i.next();
3036                    int device = ((Integer)entry.getKey()).intValue();
3037                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3038                        if (isMuted()) {
3039                            index = 0;
3040                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3041                                mAvrcpAbsVolSupported) {
3042                            index = (mIndexMax + 5)/10;
3043                        } else {
3044                            index = ((Integer)entry.getValue() + 5)/10;
3045                        }
3046                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
3047                    }
3048                }
3049            }
3050        }
3051
3052        public boolean adjustIndex(int deltaIndex, int device) {
3053            return setIndex(getIndex(device) + deltaIndex,
3054                            device);
3055        }
3056
3057        public boolean setIndex(int index, int device) {
3058            synchronized (VolumeStreamState.class) {
3059                int oldIndex = getIndex(device);
3060                index = getValidIndex(index);
3061                synchronized (mCameraSoundForced) {
3062                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3063                        index = mIndexMax;
3064                    }
3065                }
3066                mIndex.put(device, index);
3067
3068                if (oldIndex != index) {
3069                    // Apply change to all streams using this one as alias
3070                    // if changing volume of current device, also change volume of current
3071                    // device on aliased stream
3072                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3073                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3074                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3075                        if (streamType != mStreamType &&
3076                                mStreamVolumeAlias[streamType] == mStreamType) {
3077                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3078                            mStreamStates[streamType].setIndex(scaledIndex,
3079                                                               device);
3080                            if (currentDevice) {
3081                                mStreamStates[streamType].setIndex(scaledIndex,
3082                                                                   getDeviceForStream(streamType));
3083                            }
3084                        }
3085                    }
3086                    return true;
3087                } else {
3088                    return false;
3089                }
3090            }
3091        }
3092
3093        public int getIndex(int device) {
3094            synchronized (VolumeStreamState.class) {
3095                Integer index = mIndex.get(device);
3096                if (index == null) {
3097                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3098                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3099                }
3100                return index.intValue();
3101            }
3102        }
3103
3104        public int getMaxIndex() {
3105            return mIndexMax;
3106        }
3107
3108        public void setAllIndexes(VolumeStreamState srcStream) {
3109            synchronized (VolumeStreamState.class) {
3110                int srcStreamType = srcStream.getStreamType();
3111                // apply default device volume from source stream to all devices first in case
3112                // some devices are present in this stream state but not in source stream state
3113                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
3114                index = rescaleIndex(index, srcStreamType, mStreamType);
3115                Set set = mIndex.entrySet();
3116                Iterator i = set.iterator();
3117                while (i.hasNext()) {
3118                    Map.Entry entry = (Map.Entry)i.next();
3119                    entry.setValue(index);
3120                }
3121                // Now apply actual volume for devices in source stream state
3122                set = srcStream.mIndex.entrySet();
3123                i = set.iterator();
3124                while (i.hasNext()) {
3125                    Map.Entry entry = (Map.Entry)i.next();
3126                    int device = ((Integer)entry.getKey()).intValue();
3127                    index = ((Integer)entry.getValue()).intValue();
3128                    index = rescaleIndex(index, srcStreamType, mStreamType);
3129
3130                    setIndex(index, device);
3131                }
3132            }
3133        }
3134
3135        public void setAllIndexesToMax() {
3136            synchronized (VolumeStreamState.class) {
3137                Set set = mIndex.entrySet();
3138                Iterator i = set.iterator();
3139                while (i.hasNext()) {
3140                    Map.Entry entry = (Map.Entry)i.next();
3141                    entry.setValue(mIndexMax);
3142                }
3143            }
3144        }
3145
3146        public void mute(IBinder cb, boolean state) {
3147            synchronized (VolumeStreamState.class) {
3148                VolumeDeathHandler handler = getDeathHandler(cb, state);
3149                if (handler == null) {
3150                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3151                    return;
3152                }
3153                handler.mute(state);
3154            }
3155        }
3156
3157        public int getStreamType() {
3158            return mStreamType;
3159        }
3160
3161        private int getValidIndex(int index) {
3162            if (index < 0) {
3163                return 0;
3164            } else if (mUseFixedVolume || index > mIndexMax) {
3165                return mIndexMax;
3166            }
3167
3168            return index;
3169        }
3170
3171        private class VolumeDeathHandler implements IBinder.DeathRecipient {
3172            private IBinder mICallback; // To be notified of client's death
3173            private int mMuteCount; // Number of active mutes for this client
3174
3175            VolumeDeathHandler(IBinder cb) {
3176                mICallback = cb;
3177            }
3178
3179            // must be called while synchronized on parent VolumeStreamState
3180            public void mute(boolean state) {
3181                boolean updateVolume = false;
3182                if (state) {
3183                    if (mMuteCount == 0) {
3184                        // Register for client death notification
3185                        try {
3186                            // mICallback can be 0 if muted by AudioService
3187                            if (mICallback != null) {
3188                                mICallback.linkToDeath(this, 0);
3189                            }
3190                            VolumeStreamState.this.mDeathHandlers.add(this);
3191                            // If the stream is not yet muted by any client, set level to 0
3192                            if (!VolumeStreamState.this.isMuted()) {
3193                                updateVolume = true;
3194                            }
3195                        } catch (RemoteException e) {
3196                            // Client has died!
3197                            binderDied();
3198                            return;
3199                        }
3200                    } else {
3201                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3202                    }
3203                    mMuteCount++;
3204                } else {
3205                    if (mMuteCount == 0) {
3206                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3207                    } else {
3208                        mMuteCount--;
3209                        if (mMuteCount == 0) {
3210                            // Unregister from client death notification
3211                            VolumeStreamState.this.mDeathHandlers.remove(this);
3212                            // mICallback can be 0 if muted by AudioService
3213                            if (mICallback != null) {
3214                                mICallback.unlinkToDeath(this, 0);
3215                            }
3216                            if (!VolumeStreamState.this.isMuted()) {
3217                                updateVolume = true;
3218                            }
3219                        }
3220                    }
3221                }
3222                if (updateVolume) {
3223                    sendMsg(mAudioHandler,
3224                            MSG_SET_ALL_VOLUMES,
3225                            SENDMSG_QUEUE,
3226                            0,
3227                            0,
3228                            VolumeStreamState.this, 0);
3229                }
3230            }
3231
3232            public void binderDied() {
3233                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3234                if (mMuteCount != 0) {
3235                    // Reset all active mute requests from this client.
3236                    mMuteCount = 1;
3237                    mute(false);
3238                }
3239            }
3240        }
3241
3242        private synchronized int muteCount() {
3243            int count = 0;
3244            int size = mDeathHandlers.size();
3245            for (int i = 0; i < size; i++) {
3246                count += mDeathHandlers.get(i).mMuteCount;
3247            }
3248            return count;
3249        }
3250
3251        private synchronized boolean isMuted() {
3252            return muteCount() != 0;
3253        }
3254
3255        // only called by mute() which is already synchronized
3256        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
3257            VolumeDeathHandler handler;
3258            int size = mDeathHandlers.size();
3259            for (int i = 0; i < size; i++) {
3260                handler = mDeathHandlers.get(i);
3261                if (cb == handler.mICallback) {
3262                    return handler;
3263                }
3264            }
3265            // If this is the first mute request for this client, create a new
3266            // client death handler. Otherwise, it is an out of sequence unmute request.
3267            if (state) {
3268                handler = new VolumeDeathHandler(cb);
3269            } else {
3270                Log.w(TAG, "stream was not muted by this client");
3271                handler = null;
3272            }
3273            return handler;
3274        }
3275
3276        private void dump(PrintWriter pw) {
3277            pw.print("   Mute count: ");
3278            pw.println(muteCount());
3279            pw.print("   Current: ");
3280            Set set = mIndex.entrySet();
3281            Iterator i = set.iterator();
3282            while (i.hasNext()) {
3283                Map.Entry entry = (Map.Entry)i.next();
3284                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3285                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3286            }
3287        }
3288    }
3289
3290    /** Thread that handles native AudioSystem control. */
3291    private class AudioSystemThread extends Thread {
3292        AudioSystemThread() {
3293            super("AudioService");
3294        }
3295
3296        @Override
3297        public void run() {
3298            // Set this thread up so the handler will work on it
3299            Looper.prepare();
3300
3301            synchronized(AudioService.this) {
3302                mAudioHandler = new AudioHandler();
3303
3304                // Notify that the handler has been created
3305                AudioService.this.notify();
3306            }
3307
3308            // Listen for volume change requests that are set by VolumePanel
3309            Looper.loop();
3310        }
3311    }
3312
3313    /** Handles internal volume messages in separate volume thread. */
3314    private class AudioHandler extends Handler {
3315
3316        private void setDeviceVolume(VolumeStreamState streamState, int device) {
3317
3318            // Apply volume
3319            streamState.applyDeviceVolume(device);
3320
3321            // Apply change to all streams using this one as alias
3322            int numStreamTypes = AudioSystem.getNumStreamTypes();
3323            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3324                if (streamType != streamState.mStreamType &&
3325                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3326                    // Make sure volume is also maxed out on A2DP device for aliased stream
3327                    // that may have a different device selected
3328                    int streamDevice = getDeviceForStream(streamType);
3329                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3330                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3331                        mStreamStates[streamType].applyDeviceVolume(device);
3332                    }
3333                    mStreamStates[streamType].applyDeviceVolume(streamDevice);
3334                }
3335            }
3336
3337            // Post a persist volume msg
3338            sendMsg(mAudioHandler,
3339                    MSG_PERSIST_VOLUME,
3340                    SENDMSG_QUEUE,
3341                    device,
3342                    0,
3343                    streamState,
3344                    PERSIST_DELAY);
3345
3346        }
3347
3348        private void setAllVolumes(VolumeStreamState streamState) {
3349
3350            // Apply volume
3351            streamState.applyAllVolumes();
3352
3353            // Apply change to all streams using this one as alias
3354            int numStreamTypes = AudioSystem.getNumStreamTypes();
3355            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3356                if (streamType != streamState.mStreamType &&
3357                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3358                    mStreamStates[streamType].applyAllVolumes();
3359                }
3360            }
3361        }
3362
3363        private void persistVolume(VolumeStreamState streamState, int device) {
3364            if (mUseFixedVolume) {
3365                return;
3366            }
3367            System.putIntForUser(mContentResolver,
3368                      streamState.getSettingNameForDevice(device),
3369                      (streamState.getIndex(device) + 5)/ 10,
3370                      UserHandle.USER_CURRENT);
3371        }
3372
3373        private void persistRingerMode(int ringerMode) {
3374            if (mUseFixedVolume) {
3375                return;
3376            }
3377            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
3378        }
3379
3380        private boolean onLoadSoundEffects() {
3381            int status;
3382
3383            synchronized (mSoundEffectsLock) {
3384                if (!mSystemReady) {
3385                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3386                    return false;
3387                }
3388
3389                if (mSoundPool != null) {
3390                    return true;
3391                }
3392
3393                loadTouchSoundAssets();
3394
3395                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
3396                mSoundPoolCallBack = null;
3397                mSoundPoolListenerThread = new SoundPoolListenerThread();
3398                mSoundPoolListenerThread.start();
3399                int attempts = 3;
3400                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3401                    try {
3402                        // Wait for mSoundPoolCallBack to be set by the other thread
3403                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
3404                    } catch (InterruptedException e) {
3405                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3406                    }
3407                }
3408
3409                if (mSoundPoolCallBack == null) {
3410                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3411                    if (mSoundPoolLooper != null) {
3412                        mSoundPoolLooper.quit();
3413                        mSoundPoolLooper = null;
3414                    }
3415                    mSoundPoolListenerThread = null;
3416                    mSoundPool.release();
3417                    mSoundPool = null;
3418                    return false;
3419                }
3420                /*
3421                 * poolId table: The value -1 in this table indicates that corresponding
3422                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3423                 * Once loaded, the value in poolId is the sample ID and the same
3424                 * sample can be reused for another effect using the same file.
3425                 */
3426                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3427                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3428                    poolId[fileIdx] = -1;
3429                }
3430                /*
3431                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3432                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3433                 * this indicates we have a valid sample loaded for this effect.
3434                 */
3435
3436                int numSamples = 0;
3437                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3438                    // Do not load sample if this effect uses the MediaPlayer
3439                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3440                        continue;
3441                    }
3442                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3443                        String filePath = Environment.getRootDirectory()
3444                                + SOUND_EFFECTS_PATH
3445                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3446                        int sampleId = mSoundPool.load(filePath, 0);
3447                        if (sampleId <= 0) {
3448                            Log.w(TAG, "Soundpool could not load file: "+filePath);
3449                        } else {
3450                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3451                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3452                            numSamples++;
3453                        }
3454                    } else {
3455                        SOUND_EFFECT_FILES_MAP[effect][1] =
3456                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3457                    }
3458                }
3459                // wait for all samples to be loaded
3460                if (numSamples > 0) {
3461                    mSoundPoolCallBack.setSamples(poolId);
3462
3463                    attempts = 3;
3464                    status = 1;
3465                    while ((status == 1) && (attempts-- > 0)) {
3466                        try {
3467                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
3468                            status = mSoundPoolCallBack.status();
3469                        } catch (InterruptedException e) {
3470                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
3471                        }
3472                    }
3473                } else {
3474                    status = -1;
3475                }
3476
3477                if (mSoundPoolLooper != null) {
3478                    mSoundPoolLooper.quit();
3479                    mSoundPoolLooper = null;
3480                }
3481                mSoundPoolListenerThread = null;
3482                if (status != 0) {
3483                    Log.w(TAG,
3484                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
3485                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3486                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3487                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3488                        }
3489                    }
3490
3491                    mSoundPool.release();
3492                    mSoundPool = null;
3493                }
3494            }
3495            return (status == 0);
3496        }
3497
3498        /**
3499         *  Unloads samples from the sound pool.
3500         *  This method can be called to free some memory when
3501         *  sound effects are disabled.
3502         */
3503        private void onUnloadSoundEffects() {
3504            synchronized (mSoundEffectsLock) {
3505                if (mSoundPool == null) {
3506                    return;
3507                }
3508
3509                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3510                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3511                    poolId[fileIdx] = 0;
3512                }
3513
3514                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3515                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3516                        continue;
3517                    }
3518                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3519                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3520                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3521                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3522                    }
3523                }
3524                mSoundPool.release();
3525                mSoundPool = null;
3526            }
3527        }
3528
3529        private void onPlaySoundEffect(int effectType, int volume) {
3530            synchronized (mSoundEffectsLock) {
3531
3532                onLoadSoundEffects();
3533
3534                if (mSoundPool == null) {
3535                    return;
3536                }
3537                float volFloat;
3538                // use default if volume is not specified by caller
3539                if (volume < 0) {
3540                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3541                } else {
3542                    volFloat = volume / 1000.0f;
3543                }
3544
3545                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
3546                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3547                                        volFloat, volFloat, 0, 0, 1.0f);
3548                } else {
3549                    MediaPlayer mediaPlayer = new MediaPlayer();
3550                    try {
3551                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3552                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
3553                        mediaPlayer.setDataSource(filePath);
3554                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3555                        mediaPlayer.prepare();
3556                        mediaPlayer.setVolume(volFloat);
3557                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3558                            public void onCompletion(MediaPlayer mp) {
3559                                cleanupPlayer(mp);
3560                            }
3561                        });
3562                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
3563                            public boolean onError(MediaPlayer mp, int what, int extra) {
3564                                cleanupPlayer(mp);
3565                                return true;
3566                            }
3567                        });
3568                        mediaPlayer.start();
3569                    } catch (IOException ex) {
3570                        Log.w(TAG, "MediaPlayer IOException: "+ex);
3571                    } catch (IllegalArgumentException ex) {
3572                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3573                    } catch (IllegalStateException ex) {
3574                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3575                    }
3576                }
3577            }
3578        }
3579
3580        private void cleanupPlayer(MediaPlayer mp) {
3581            if (mp != null) {
3582                try {
3583                    mp.stop();
3584                    mp.release();
3585                } catch (IllegalStateException ex) {
3586                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3587                }
3588            }
3589        }
3590
3591        private void setForceUse(int usage, int config) {
3592            AudioSystem.setForceUse(usage, config);
3593        }
3594
3595        private void onPersistSafeVolumeState(int state) {
3596            Settings.Global.putInt(mContentResolver,
3597                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3598                    state);
3599        }
3600
3601        @Override
3602        public void handleMessage(Message msg) {
3603
3604            switch (msg.what) {
3605
3606                case MSG_SET_DEVICE_VOLUME:
3607                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3608                    break;
3609
3610                case MSG_SET_ALL_VOLUMES:
3611                    setAllVolumes((VolumeStreamState) msg.obj);
3612                    break;
3613
3614                case MSG_PERSIST_VOLUME:
3615                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
3616                    break;
3617
3618                case MSG_PERSIST_MASTER_VOLUME:
3619                    if (mUseFixedVolume) {
3620                        return;
3621                    }
3622                    Settings.System.putFloatForUser(mContentResolver,
3623                                                    Settings.System.VOLUME_MASTER,
3624                                                    msg.arg1 / (float)1000.0,
3625                                                    UserHandle.USER_CURRENT);
3626                    break;
3627
3628                case MSG_PERSIST_MASTER_VOLUME_MUTE:
3629                    if (mUseFixedVolume) {
3630                        return;
3631                    }
3632                    Settings.System.putIntForUser(mContentResolver,
3633                                                 Settings.System.VOLUME_MASTER_MUTE,
3634                                                 msg.arg1,
3635                                                 UserHandle.USER_CURRENT);
3636                    break;
3637
3638                case MSG_PERSIST_RINGER_MODE:
3639                    // note that the value persisted is the current ringer mode, not the
3640                    // value of ringer mode as of the time the request was made to persist
3641                    persistRingerMode(getRingerMode());
3642                    break;
3643
3644                case MSG_MEDIA_SERVER_DIED:
3645                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
3646                        Log.e(TAG, "Media server died.");
3647                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
3648                                null, 500);
3649                        break;
3650                    }
3651                    Log.e(TAG, "Media server started.");
3652
3653                    // indicate to audio HAL that we start the reconfiguration phase after a media
3654                    // server crash
3655                    // Note that we only execute this when the media server
3656                    // process restarts after a crash, not the first time it is started.
3657                    AudioSystem.setParameters("restarting=true");
3658
3659                    readAndSetLowRamDevice();
3660
3661                    // Restore device connection states
3662                    synchronized (mConnectedDevices) {
3663                        Set set = mConnectedDevices.entrySet();
3664                        Iterator i = set.iterator();
3665                        while (i.hasNext()) {
3666                            Map.Entry device = (Map.Entry)i.next();
3667                            AudioSystem.setDeviceConnectionState(
3668                                                            ((Integer)device.getKey()).intValue(),
3669                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
3670                                                            (String)device.getValue());
3671                        }
3672                    }
3673                    // Restore call state
3674                    AudioSystem.setPhoneState(mMode);
3675
3676                    // Restore forced usage for communcations and record
3677                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3678                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3679                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3680                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3681
3682                    // Restore stream volumes
3683                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3684                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3685                        VolumeStreamState streamState = mStreamStates[streamType];
3686                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
3687
3688                        streamState.applyAllVolumes();
3689                    }
3690
3691                    // Restore ringer mode
3692                    setRingerModeInt(getRingerMode(), false);
3693
3694                    // Restore master volume
3695                    restoreMasterVolume();
3696
3697                    // Reset device orientation (if monitored for this device)
3698                    if (mMonitorOrientation) {
3699                        setOrientationForAudioSystem();
3700                    }
3701                    if (mMonitorRotation) {
3702                        setRotationForAudioSystem();
3703                    }
3704
3705                    synchronized (mBluetoothA2dpEnabledLock) {
3706                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3707                                mBluetoothA2dpEnabled ?
3708                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3709                    }
3710
3711                    synchronized (mSettingsLock) {
3712                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3713                                mDockAudioMediaEnabled ?
3714                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3715                    }
3716
3717                    // indicate the end of reconfiguration phase to audio HAL
3718                    AudioSystem.setParameters("restarting=false");
3719                    break;
3720
3721                case MSG_UNLOAD_SOUND_EFFECTS:
3722                    onUnloadSoundEffects();
3723                    break;
3724
3725                case MSG_LOAD_SOUND_EFFECTS:
3726                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3727                    // can take several dozens of milliseconds to complete
3728                    boolean loaded = onLoadSoundEffects();
3729                    if (msg.obj != null) {
3730                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3731                        synchronized (reply) {
3732                            reply.mStatus = loaded ? 0 : -1;
3733                            reply.notify();
3734                        }
3735                    }
3736                    break;
3737
3738                case MSG_PLAY_SOUND_EFFECT:
3739                    onPlaySoundEffect(msg.arg1, msg.arg2);
3740                    break;
3741
3742                case MSG_BTA2DP_DOCK_TIMEOUT:
3743                    // msg.obj  == address of BTA2DP device
3744                    synchronized (mConnectedDevices) {
3745                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
3746                    }
3747                    break;
3748
3749                case MSG_SET_FORCE_USE:
3750                case MSG_SET_FORCE_BT_A2DP_USE:
3751                    setForceUse(msg.arg1, msg.arg2);
3752                    break;
3753
3754                case MSG_BT_HEADSET_CNCT_FAILED:
3755                    resetBluetoothSco();
3756                    break;
3757
3758                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3759                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3760                    mAudioEventWakeLock.release();
3761                    break;
3762
3763                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
3764                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3765                    mAudioEventWakeLock.release();
3766                    break;
3767
3768                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
3769                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3770                    mAudioEventWakeLock.release();
3771                    break;
3772
3773                case MSG_REPORT_NEW_ROUTES: {
3774                    int N = mRoutesObservers.beginBroadcast();
3775                    if (N > 0) {
3776                        AudioRoutesInfo routes;
3777                        synchronized (mCurAudioRoutes) {
3778                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3779                        }
3780                        while (N > 0) {
3781                            N--;
3782                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3783                            try {
3784                                obs.dispatchAudioRoutesChanged(routes);
3785                            } catch (RemoteException e) {
3786                            }
3787                        }
3788                    }
3789                    mRoutesObservers.finishBroadcast();
3790                    break;
3791                }
3792
3793                case MSG_CHECK_MUSIC_ACTIVE:
3794                    onCheckMusicActive();
3795                    break;
3796
3797                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3798                    onSendBecomingNoisyIntent();
3799                    break;
3800
3801                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3802                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3803                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3804                    break;
3805                case MSG_PERSIST_SAFE_VOLUME_STATE:
3806                    onPersistSafeVolumeState(msg.arg1);
3807                    break;
3808
3809                case MSG_BROADCAST_BT_CONNECTION_STATE:
3810                    onBroadcastScoConnectionState(msg.arg1);
3811                    break;
3812
3813                case MSG_SYSTEM_READY:
3814                    onSystemReady();
3815                    break;
3816            }
3817        }
3818    }
3819
3820    private class SettingsObserver extends ContentObserver {
3821
3822        SettingsObserver() {
3823            super(new Handler());
3824            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3825                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3826            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3827                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3828        }
3829
3830        @Override
3831        public void onChange(boolean selfChange) {
3832            super.onChange(selfChange);
3833            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3834            //       However there appear to be some missing locks around mRingerModeMutedStreams
3835            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3836            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3837            synchronized (mSettingsLock) {
3838                if (updateRingerModeAffectedStreams()) {
3839                    /*
3840                     * Ensure all stream types that should be affected by ringer mode
3841                     * are in the proper state.
3842                     */
3843                    setRingerModeInt(getRingerMode(), false);
3844                }
3845                readDockAudioSettings(mContentResolver);
3846            }
3847        }
3848    }
3849
3850    // must be called synchronized on mConnectedDevices
3851    private void makeA2dpDeviceAvailable(String address) {
3852        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3853        // audio policy manager
3854        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3855        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3856                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
3857        setBluetoothA2dpOnInt(true);
3858        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3859                AudioSystem.DEVICE_STATE_AVAILABLE,
3860                address);
3861        // Reset A2DP suspend state each time a new sink is connected
3862        AudioSystem.setParameters("A2dpSuspended=false");
3863        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3864                address);
3865    }
3866
3867    private void onSendBecomingNoisyIntent() {
3868        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
3869    }
3870
3871    // must be called synchronized on mConnectedDevices
3872    private void makeA2dpDeviceUnavailableNow(String address) {
3873        synchronized (mA2dpAvrcpLock) {
3874            mAvrcpAbsVolSupported = false;
3875        }
3876        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3877                AudioSystem.DEVICE_STATE_UNAVAILABLE,
3878                address);
3879        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3880    }
3881
3882    // must be called synchronized on mConnectedDevices
3883    private void makeA2dpDeviceUnavailableLater(String address) {
3884        // prevent any activity on the A2DP audio output to avoid unwanted
3885        // reconnection of the sink.
3886        AudioSystem.setParameters("A2dpSuspended=true");
3887        // the device will be made unavailable later, so consider it disconnected right away
3888        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3889        // send the delayed message to make the device unavailable later
3890        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3891        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3892
3893    }
3894
3895    // must be called synchronized on mConnectedDevices
3896    private void makeA2dpSrcAvailable(String address) {
3897        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3898                AudioSystem.DEVICE_STATE_AVAILABLE,
3899                address);
3900        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
3901                address);
3902    }
3903
3904    // must be called synchronized on mConnectedDevices
3905    private void makeA2dpSrcUnavailable(String address) {
3906        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3907                AudioSystem.DEVICE_STATE_UNAVAILABLE,
3908                address);
3909        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
3910    }
3911
3912    // must be called synchronized on mConnectedDevices
3913    private void cancelA2dpDeviceTimeout() {
3914        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3915    }
3916
3917    // must be called synchronized on mConnectedDevices
3918    private boolean hasScheduledA2dpDockTimeout() {
3919        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3920    }
3921
3922    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
3923    {
3924        if (DEBUG_VOL) {
3925            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
3926        }
3927        if (btDevice == null) {
3928            return;
3929        }
3930        String address = btDevice.getAddress();
3931        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3932            address = "";
3933        }
3934
3935        synchronized (mConnectedDevices) {
3936            boolean isConnected =
3937                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
3938                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
3939
3940            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
3941                if (btDevice.isBluetoothDock()) {
3942                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
3943                        // introduction of a delay for transient disconnections of docks when
3944                        // power is rapidly turned off/on, this message will be canceled if
3945                        // we reconnect the dock under a preset delay
3946                        makeA2dpDeviceUnavailableLater(address);
3947                        // the next time isConnected is evaluated, it will be false for the dock
3948                    }
3949                } else {
3950                    makeA2dpDeviceUnavailableNow(address);
3951                }
3952                synchronized (mCurAudioRoutes) {
3953                    if (mCurAudioRoutes.mBluetoothName != null) {
3954                        mCurAudioRoutes.mBluetoothName = null;
3955                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3956                                SENDMSG_NOOP, 0, 0, null, 0);
3957                    }
3958                }
3959            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
3960                if (btDevice.isBluetoothDock()) {
3961                    // this could be a reconnection after a transient disconnection
3962                    cancelA2dpDeviceTimeout();
3963                    mDockAddress = address;
3964                } else {
3965                    // this could be a connection of another A2DP device before the timeout of
3966                    // a dock: cancel the dock timeout, and make the dock unavailable now
3967                    if(hasScheduledA2dpDockTimeout()) {
3968                        cancelA2dpDeviceTimeout();
3969                        makeA2dpDeviceUnavailableNow(mDockAddress);
3970                    }
3971                }
3972                makeA2dpDeviceAvailable(address);
3973                synchronized (mCurAudioRoutes) {
3974                    String name = btDevice.getAliasName();
3975                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3976                        mCurAudioRoutes.mBluetoothName = name;
3977                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3978                                SENDMSG_NOOP, 0, 0, null, 0);
3979                    }
3980                }
3981            }
3982        }
3983    }
3984
3985    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
3986    {
3987        if (DEBUG_VOL) {
3988            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
3989        }
3990        if (btDevice == null) {
3991            return;
3992        }
3993        String address = btDevice.getAddress();
3994        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3995            address = "";
3996        }
3997
3998        synchronized (mConnectedDevices) {
3999                boolean isConnected =
4000                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4001                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4002
4003            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4004                makeA2dpSrcUnavailable(address);
4005            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4006                makeA2dpSrcAvailable(address);
4007            }
4008        }
4009    }
4010
4011    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4012        // address is not used for now, but may be used when multiple a2dp devices are supported
4013        synchronized (mA2dpAvrcpLock) {
4014            mAvrcpAbsVolSupported = support;
4015            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4016                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4017                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4018            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4019                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4020                    mStreamStates[AudioSystem.STREAM_RING], 0);
4021        }
4022    }
4023
4024    private boolean handleDeviceConnection(boolean connected, int device, String params) {
4025        synchronized (mConnectedDevices) {
4026            boolean isConnected = (mConnectedDevices.containsKey(device) &&
4027                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
4028
4029            if (isConnected && !connected) {
4030                AudioSystem.setDeviceConnectionState(device,
4031                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
4032                                              mConnectedDevices.get(device));
4033                 mConnectedDevices.remove(device);
4034                 return true;
4035            } else if (!isConnected && connected) {
4036                 AudioSystem.setDeviceConnectionState(device,
4037                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
4038                                                      params);
4039                 mConnectedDevices.put(new Integer(device), params);
4040                 return true;
4041            }
4042        }
4043        return false;
4044    }
4045
4046    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4047    // sent if none of these devices is connected.
4048    int mBecomingNoisyIntentDevices =
4049            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4050            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4051            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4052            AudioSystem.DEVICE_OUT_ALL_USB;
4053
4054    // must be called before removing the device from mConnectedDevices
4055    private int checkSendBecomingNoisyIntent(int device, int state) {
4056        int delay = 0;
4057        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4058            int devices = 0;
4059            for (int dev : mConnectedDevices.keySet()) {
4060                if ((dev & mBecomingNoisyIntentDevices) != 0) {
4061                   devices |= dev;
4062                }
4063            }
4064            if (devices == device) {
4065                sendMsg(mAudioHandler,
4066                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4067                        SENDMSG_REPLACE,
4068                        0,
4069                        0,
4070                        null,
4071                        0);
4072                delay = 1000;
4073            }
4074        }
4075
4076        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4077                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4078                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4079            delay = 1000;
4080        }
4081        return delay;
4082    }
4083
4084    private void sendDeviceConnectionIntent(int device, int state, String name)
4085    {
4086        Intent intent = new Intent();
4087
4088        intent.putExtra("state", state);
4089        intent.putExtra("name", name);
4090        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4091
4092        int connType = 0;
4093
4094        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4095            connType = AudioRoutesInfo.MAIN_HEADSET;
4096            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4097            intent.putExtra("microphone", 1);
4098        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
4099            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4100            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4101            intent.putExtra("microphone", 0);
4102        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
4103            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4104            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4105        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
4106            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4107            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
4108        } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
4109            connType = AudioRoutesInfo.MAIN_HDMI;
4110            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4111        }
4112
4113        synchronized (mCurAudioRoutes) {
4114            if (connType != 0) {
4115                int newConn = mCurAudioRoutes.mMainType;
4116                if (state != 0) {
4117                    newConn |= connType;
4118                } else {
4119                    newConn &= ~connType;
4120                }
4121                if (newConn != mCurAudioRoutes.mMainType) {
4122                    mCurAudioRoutes.mMainType = newConn;
4123                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4124                            SENDMSG_NOOP, 0, 0, null, 0);
4125                }
4126            }
4127        }
4128
4129        final long ident = Binder.clearCallingIdentity();
4130        try {
4131            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4132        } finally {
4133            Binder.restoreCallingIdentity(ident);
4134        }
4135    }
4136
4137    private void onSetWiredDeviceConnectionState(int device, int state, String name)
4138    {
4139        synchronized (mConnectedDevices) {
4140            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4141                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4142                setBluetoothA2dpOnInt(true);
4143            }
4144            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
4145                            ((device & AudioSystem.DEVICE_IN_ALL_USB) != 0);
4146            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
4147            if (state != 0) {
4148                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4149                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4150                    setBluetoothA2dpOnInt(false);
4151                }
4152                if ((device & mSafeMediaVolumeDevices) != 0) {
4153                    sendMsg(mAudioHandler,
4154                            MSG_CHECK_MUSIC_ACTIVE,
4155                            SENDMSG_REPLACE,
4156                            0,
4157                            0,
4158                            null,
4159                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4160                }
4161            }
4162            if (!isUsb) {
4163                sendDeviceConnectionIntent(device, state, name);
4164            }
4165        }
4166    }
4167
4168    /* cache of the address of the last dock the device was connected to */
4169    private String mDockAddress;
4170
4171    /**
4172     * Receiver for misc intent broadcasts the Phone app cares about.
4173     */
4174    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4175        @Override
4176        public void onReceive(Context context, Intent intent) {
4177            String action = intent.getAction();
4178            int device;
4179            int state;
4180
4181            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4182                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4183                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4184                int config;
4185                switch (dockState) {
4186                    case Intent.EXTRA_DOCK_STATE_DESK:
4187                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4188                        break;
4189                    case Intent.EXTRA_DOCK_STATE_CAR:
4190                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4191                        break;
4192                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
4193                        config = AudioSystem.FORCE_ANALOG_DOCK;
4194                        break;
4195                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
4196                        config = AudioSystem.FORCE_DIGITAL_DOCK;
4197                        break;
4198                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4199                    default:
4200                        config = AudioSystem.FORCE_NONE;
4201                }
4202                // Low end docks have a menu to enable or disable audio
4203                // (see mDockAudioMediaEnabled)
4204                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4205                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4206                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4207                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4208                }
4209                mDockState = dockState;
4210            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
4211                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
4212                                               BluetoothProfile.STATE_DISCONNECTED);
4213                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4214                String address = null;
4215
4216                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4217                if (btDevice == null) {
4218                    return;
4219                }
4220
4221                address = btDevice.getAddress();
4222                BluetoothClass btClass = btDevice.getBluetoothClass();
4223                if (btClass != null) {
4224                    switch (btClass.getDeviceClass()) {
4225                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4226                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4227                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4228                        break;
4229                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4230                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4231                        break;
4232                    }
4233                }
4234
4235                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4236                    address = "";
4237                }
4238
4239                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4240                if (handleDeviceConnection(connected, device, address)) {
4241                    synchronized (mScoClients) {
4242                        if (connected) {
4243                            mBluetoothHeadsetDevice = btDevice;
4244                        } else {
4245                            mBluetoothHeadsetDevice = null;
4246                            resetBluetoothSco();
4247                        }
4248                    }
4249                }
4250            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4251                state = intent.getIntExtra("state", 0);
4252
4253                int alsaCard = intent.getIntExtra("card", -1);
4254                int alsaDevice = intent.getIntExtra("device", -1);
4255
4256                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4257                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4258
4259                // Playback Device
4260                device = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4261                setWiredDeviceConnectionState(device, state, params);
4262            } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
4263                state = intent.getIntExtra("state", 0);
4264
4265                int alsaCard = intent.getIntExtra("card", -1);
4266                int alsaDevice = intent.getIntExtra("device", -1);
4267                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4268                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4269                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4270
4271                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4272                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4273
4274                // Playback Device
4275                if (hasPlayback) {
4276                    device = AudioSystem.DEVICE_OUT_USB_DEVICE;
4277                    setWiredDeviceConnectionState(device, state, params);
4278                }
4279
4280                // Capture Device
4281                if (hasCapture) {
4282                    device = AudioSystem.DEVICE_IN_USB_DEVICE;
4283                    setWiredDeviceConnectionState(device, state, params);
4284                }
4285            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
4286                boolean broadcast = false;
4287                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
4288                synchronized (mScoClients) {
4289                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4290                    // broadcast intent if the connection was initated by AudioService
4291                    if (!mScoClients.isEmpty() &&
4292                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4293                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4294                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
4295                        broadcast = true;
4296                    }
4297                    switch (btState) {
4298                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
4299                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4300                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4301                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4302                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4303                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4304                        }
4305                        break;
4306                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
4307                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
4308                        mScoAudioState = SCO_STATE_INACTIVE;
4309                        clearAllScoClients(0, false);
4310                        break;
4311                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4312                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4313                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4314                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4315                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4316                        }
4317                    default:
4318                        // do not broadcast CONNECTING or invalid state
4319                        broadcast = false;
4320                        break;
4321                    }
4322                }
4323                if (broadcast) {
4324                    broadcastScoConnectionState(scoAudioState);
4325                    //FIXME: this is to maintain compatibility with deprecated intent
4326                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4327                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4328                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
4329                    sendStickyBroadcastToAll(newIntent);
4330                }
4331            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4332                AudioSystem.setParameters("screen_state=on");
4333            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4334                AudioSystem.setParameters("screen_state=off");
4335            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4336                handleConfigurationChanged(context);
4337            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4338                // attempt to stop music playback for background user
4339                sendMsg(mAudioHandler,
4340                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4341                        SENDMSG_REPLACE,
4342                        0,
4343                        0,
4344                        null,
4345                        0);
4346                // the current audio focus owner is no longer valid
4347                mMediaFocusControl.discardAudioFocusOwner();
4348
4349                // load volume settings for new user
4350                readAudioSettings(true /*userSwitch*/);
4351                // preserve STREAM_MUSIC volume from one user to the next.
4352                sendMsg(mAudioHandler,
4353                        MSG_SET_ALL_VOLUMES,
4354                        SENDMSG_QUEUE,
4355                        0,
4356                        0,
4357                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4358            }
4359        }
4360    } // end class AudioServiceBroadcastReceiver
4361
4362    //==========================================================================================
4363    // RemoteControlDisplay / RemoteControlClient / Remote info
4364    //==========================================================================================
4365    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4366            ComponentName listenerComp) {
4367        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4368    }
4369
4370    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4371        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4372    }
4373
4374    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4375        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4376    }
4377
4378    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4379        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4380    }
4381
4382    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4383            boolean wantsSync) {
4384        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4385    }
4386
4387    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4388        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
4389    }
4390
4391    public void unregisterMediaButtonEventReceiverForCalls() {
4392        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
4393    }
4394
4395    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
4396        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
4397    }
4398
4399    public void unregisterMediaButtonIntent(PendingIntent pi) {
4400        mMediaFocusControl.unregisterMediaButtonIntent(pi);
4401    }
4402
4403    public int registerRemoteControlClient(PendingIntent mediaIntent,
4404            IRemoteControlClient rcClient, String callingPckg) {
4405        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
4406    }
4407
4408    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
4409            IRemoteControlClient rcClient) {
4410        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
4411    }
4412
4413    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
4414        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
4415    }
4416
4417    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
4418        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
4419    }
4420
4421    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
4422        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
4423    }
4424
4425    @Override
4426    public int getRemoteStreamVolume() {
4427        return mMediaFocusControl.getRemoteStreamVolume();
4428    }
4429
4430    @Override
4431    public int getRemoteStreamMaxVolume() {
4432        return mMediaFocusControl.getRemoteStreamMaxVolume();
4433    }
4434
4435    @Override
4436    public void setRemoteStreamVolume(int index) {
4437        enforceSelfOrSystemUI("set the remote stream volume");
4438        mMediaFocusControl.setRemoteStreamVolume(index);
4439    }
4440
4441    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
4442        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
4443    }
4444
4445    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4446        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
4447    }
4448
4449    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
4450        if (USE_SESSIONS) {
4451            if (DEBUG_SESSIONS) {
4452                int pid = getCallingPid();
4453                Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid);
4454            }
4455            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
4456        } else {
4457            mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
4458        }
4459    }
4460
4461    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
4462        if (USE_SESSIONS) {
4463            if (DEBUG_SESSIONS) {
4464                int pid = getCallingPid();
4465                Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid);
4466            }
4467            MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true);
4468        } else {
4469            mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
4470        }
4471    }
4472
4473    //==========================================================================================
4474    // Audio Focus
4475    //==========================================================================================
4476    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4477            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4478        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4479                clientId, callingPackageName);
4480    }
4481
4482    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4483        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4484    }
4485
4486    public void unregisterAudioFocusClient(String clientId) {
4487        mMediaFocusControl.unregisterAudioFocusClient(clientId);
4488    }
4489
4490    public int getCurrentAudioFocus() {
4491        return mMediaFocusControl.getCurrentAudioFocus();
4492    }
4493
4494    //==========================================================================================
4495    // Device orientation
4496    //==========================================================================================
4497    /**
4498     * Handles device configuration changes that may map to a change in the orientation
4499     * or orientation.
4500     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4501     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4502     */
4503    private void handleConfigurationChanged(Context context) {
4504        try {
4505            // reading new orientation "safely" (i.e. under try catch) in case anything
4506            // goes wrong when obtaining resources and configuration
4507            Configuration config = context.getResources().getConfiguration();
4508            // TODO merge rotation and orientation
4509            if (mMonitorOrientation) {
4510                int newOrientation = config.orientation;
4511                if (newOrientation != mDeviceOrientation) {
4512                    mDeviceOrientation = newOrientation;
4513                    setOrientationForAudioSystem();
4514                }
4515            }
4516            if (mMonitorRotation) {
4517                int newRotation = ((WindowManager) context.getSystemService(
4518                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4519                if (newRotation != mDeviceRotation) {
4520                    mDeviceRotation = newRotation;
4521                    setRotationForAudioSystem();
4522                }
4523            }
4524            sendMsg(mAudioHandler,
4525                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4526                    SENDMSG_REPLACE,
4527                    0,
4528                    0,
4529                    null,
4530                    0);
4531
4532            boolean cameraSoundForced = mContext.getResources().getBoolean(
4533                    com.android.internal.R.bool.config_camera_sound_forced);
4534            synchronized (mSettingsLock) {
4535                synchronized (mCameraSoundForced) {
4536                    if (cameraSoundForced != mCameraSoundForced) {
4537                        mCameraSoundForced = cameraSoundForced;
4538
4539                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4540                        if (cameraSoundForced) {
4541                            s.setAllIndexesToMax();
4542                            mRingerModeAffectedStreams &=
4543                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4544                        } else {
4545                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4546                            mRingerModeAffectedStreams |=
4547                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4548                        }
4549                        // take new state into account for streams muted by ringer mode
4550                        setRingerModeInt(getRingerMode(), false);
4551
4552                        sendMsg(mAudioHandler,
4553                                MSG_SET_FORCE_USE,
4554                                SENDMSG_QUEUE,
4555                                AudioSystem.FOR_SYSTEM,
4556                                cameraSoundForced ?
4557                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4558                                null,
4559                                0);
4560
4561                        sendMsg(mAudioHandler,
4562                                MSG_SET_ALL_VOLUMES,
4563                                SENDMSG_QUEUE,
4564                                0,
4565                                0,
4566                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4567                    }
4568                }
4569            }
4570            mVolumeController.setLayoutDirection(config.getLayoutDirection());
4571        } catch (Exception e) {
4572            Log.e(TAG, "Error handling configuration change: ", e);
4573        }
4574    }
4575
4576    private void setOrientationForAudioSystem() {
4577        switch (mDeviceOrientation) {
4578            case Configuration.ORIENTATION_LANDSCAPE:
4579                //Log.i(TAG, "orientation is landscape");
4580                AudioSystem.setParameters("orientation=landscape");
4581                break;
4582            case Configuration.ORIENTATION_PORTRAIT:
4583                //Log.i(TAG, "orientation is portrait");
4584                AudioSystem.setParameters("orientation=portrait");
4585                break;
4586            case Configuration.ORIENTATION_SQUARE:
4587                //Log.i(TAG, "orientation is square");
4588                AudioSystem.setParameters("orientation=square");
4589                break;
4590            case Configuration.ORIENTATION_UNDEFINED:
4591                //Log.i(TAG, "orientation is undefined");
4592                AudioSystem.setParameters("orientation=undefined");
4593                break;
4594            default:
4595                Log.e(TAG, "Unknown orientation");
4596        }
4597    }
4598
4599    private void setRotationForAudioSystem() {
4600        switch (mDeviceRotation) {
4601            case Surface.ROTATION_0:
4602                AudioSystem.setParameters("rotation=0");
4603                break;
4604            case Surface.ROTATION_90:
4605                AudioSystem.setParameters("rotation=90");
4606                break;
4607            case Surface.ROTATION_180:
4608                AudioSystem.setParameters("rotation=180");
4609                break;
4610            case Surface.ROTATION_270:
4611                AudioSystem.setParameters("rotation=270");
4612                break;
4613            default:
4614                Log.e(TAG, "Unknown device rotation");
4615        }
4616    }
4617
4618
4619    // Handles request to override default use of A2DP for media.
4620    public void setBluetoothA2dpOnInt(boolean on) {
4621        synchronized (mBluetoothA2dpEnabledLock) {
4622            mBluetoothA2dpEnabled = on;
4623            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4624            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4625                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4626        }
4627    }
4628
4629    @Override
4630    public void setRingtonePlayer(IRingtonePlayer player) {
4631        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4632        mRingtonePlayer = player;
4633    }
4634
4635    @Override
4636    public IRingtonePlayer getRingtonePlayer() {
4637        return mRingtonePlayer;
4638    }
4639
4640    @Override
4641    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4642        synchronized (mCurAudioRoutes) {
4643            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4644            mRoutesObservers.register(observer);
4645            return routes;
4646        }
4647    }
4648
4649
4650    //==========================================================================================
4651    // Safe media volume management.
4652    // MUSIC stream volume level is limited when headphones are connected according to safety
4653    // regulation. When the user attempts to raise the volume above the limit, a warning is
4654    // displayed and the user has to acknowlegde before the volume is actually changed.
4655    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4656    // property. Platforms with a different limit must set this property accordingly in their
4657    // overlay.
4658    //==========================================================================================
4659
4660    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4661    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4662    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4663    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4664    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4665    // (when user opts out).
4666    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4667    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4668    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4669    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4670    private Integer mSafeMediaVolumeState;
4671
4672    private int mMcc = 0;
4673    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4674    private int mSafeMediaVolumeIndex;
4675    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4676    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4677                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4678    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4679    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4680    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4681    private int mMusicActiveMs;
4682    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4683    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4684    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4685
4686    private void setSafeMediaVolumeEnabled(boolean on) {
4687        synchronized (mSafeMediaVolumeState) {
4688            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4689                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4690                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4691                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4692                    enforceSafeMediaVolume();
4693                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4694                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4695                    mMusicActiveMs = 0;
4696                    sendMsg(mAudioHandler,
4697                            MSG_CHECK_MUSIC_ACTIVE,
4698                            SENDMSG_REPLACE,
4699                            0,
4700                            0,
4701                            null,
4702                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4703                }
4704            }
4705        }
4706    }
4707
4708    private void enforceSafeMediaVolume() {
4709        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4710        int devices = mSafeMediaVolumeDevices;
4711        int i = 0;
4712
4713        while (devices != 0) {
4714            int device = 1 << i++;
4715            if ((device & devices) == 0) {
4716                continue;
4717            }
4718            int index = streamState.getIndex(device);
4719            if (index > mSafeMediaVolumeIndex) {
4720                streamState.setIndex(mSafeMediaVolumeIndex, device);
4721                sendMsg(mAudioHandler,
4722                        MSG_SET_DEVICE_VOLUME,
4723                        SENDMSG_QUEUE,
4724                        device,
4725                        0,
4726                        streamState,
4727                        0);
4728            }
4729            devices &= ~device;
4730        }
4731    }
4732
4733    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4734        synchronized (mSafeMediaVolumeState) {
4735            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4736                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4737                    ((device & mSafeMediaVolumeDevices) != 0) &&
4738                    (index > mSafeMediaVolumeIndex)) {
4739                return false;
4740            }
4741            return true;
4742        }
4743    }
4744
4745    @Override
4746    public void disableSafeMediaVolume() {
4747        enforceSelfOrSystemUI("disable the safe media volume");
4748        synchronized (mSafeMediaVolumeState) {
4749            setSafeMediaVolumeEnabled(false);
4750            if (mPendingVolumeCommand != null) {
4751                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4752                                  mPendingVolumeCommand.mIndex,
4753                                  mPendingVolumeCommand.mFlags,
4754                                  mPendingVolumeCommand.mDevice);
4755                mPendingVolumeCommand = null;
4756            }
4757        }
4758    }
4759
4760
4761    //==========================================================================================
4762    // Camera shutter sound policy.
4763    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4764    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4765    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4766    //==========================================================================================
4767
4768    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4769    private Boolean mCameraSoundForced;
4770
4771    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4772    public boolean isCameraSoundForced() {
4773        synchronized (mCameraSoundForced) {
4774            return mCameraSoundForced;
4775        }
4776    }
4777
4778    private static final String[] RINGER_MODE_NAMES = new String[] {
4779            "SILENT",
4780            "VIBRATE",
4781            "NORMAL"
4782    };
4783
4784    private void dumpRingerMode(PrintWriter pw) {
4785        pw.println("\nRinger mode: ");
4786        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4787        pw.print("- ringer mode affected streams = 0x");
4788        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4789        pw.print("- ringer mode muted streams = 0x");
4790        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4791    }
4792
4793    @Override
4794    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4795        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4796
4797        mMediaFocusControl.dump(pw);
4798        dumpStreamStates(pw);
4799        dumpRingerMode(pw);
4800        pw.println("\nAudio routes:");
4801        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4802        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
4803        pw.print("  mVolumeController="); pw.println(mVolumeController);
4804    }
4805
4806    // Inform AudioFlinger of our device's low RAM attribute
4807    private static void readAndSetLowRamDevice()
4808    {
4809        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4810        if (status != 0) {
4811            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4812        }
4813    }
4814
4815    private void enforceSelfOrSystemUI(String action) {
4816        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
4817                "Only SystemUI can " + action);
4818    }
4819
4820    @Override
4821    public void setVolumeController(final IVolumeController controller) {
4822        enforceSelfOrSystemUI("set the volume controller");
4823
4824        // return early if things are not actually changing
4825        if (mVolumeController.isSameBinder(controller)) {
4826            return;
4827        }
4828
4829        // dismiss the old volume controller
4830        mVolumeController.postDismiss();
4831        if (controller != null) {
4832            // we are about to register a new controller, listen for its death
4833            try {
4834                controller.asBinder().linkToDeath(new DeathRecipient() {
4835                    @Override
4836                    public void binderDied() {
4837                        if (mVolumeController.isSameBinder(controller)) {
4838                            Log.w(TAG, "Current remote volume controller died, unregistering");
4839                            setVolumeController(null);
4840                        }
4841                    }
4842                }, 0);
4843            } catch (RemoteException e) {
4844                // noop
4845            }
4846        }
4847        mVolumeController.setController(controller);
4848    }
4849}
4850