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