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