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