AudioService.java revision c9d1d5f35091226e96fcfa91817480f589eb36e2
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        mAudioEventWakeLock.acquire();
2691        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2692    }
2693
2694    private static void sendMsg(Handler handler, int msg,
2695            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
2696
2697        if (existingMsgPolicy == SENDMSG_REPLACE) {
2698            handler.removeMessages(msg);
2699        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2700            return;
2701        }
2702
2703        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
2704    }
2705
2706    boolean checkAudioSettingsPermission(String method) {
2707        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2708                == PackageManager.PERMISSION_GRANTED) {
2709            return true;
2710        }
2711        String msg = "Audio Settings Permission Denial: " + method + " from pid="
2712                + Binder.getCallingPid()
2713                + ", uid=" + Binder.getCallingUid();
2714        Log.w(TAG, msg);
2715        return false;
2716    }
2717
2718    private int getDeviceForStream(int stream) {
2719        int device = AudioSystem.getDevicesForStream(stream);
2720        if ((device & (device - 1)) != 0) {
2721            // Multiple device selection is either:
2722            //  - speaker + one other device: give priority to speaker in this case.
2723            //  - one A2DP device + another device: happens with duplicated output. In this case
2724            // retain the device on the A2DP output as the other must not correspond to an active
2725            // selection if not the speaker.
2726            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2727                device = AudioSystem.DEVICE_OUT_SPEAKER;
2728            } else {
2729                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2730            }
2731        }
2732        return device;
2733    }
2734
2735    public void setWiredDeviceConnectionState(int device, int state, String name) {
2736        synchronized (mConnectedDevices) {
2737            int delay = checkSendBecomingNoisyIntent(device, state);
2738            queueMsgUnderWakeLock(mAudioHandler,
2739                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2740                    device,
2741                    state,
2742                    name,
2743                    delay);
2744        }
2745    }
2746
2747    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2748    {
2749        int delay;
2750        synchronized (mConnectedDevices) {
2751            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2752                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2753            queueMsgUnderWakeLock(mAudioHandler,
2754                    MSG_SET_A2DP_CONNECTION_STATE,
2755                    state,
2756                    0,
2757                    device,
2758                    delay);
2759        }
2760        return delay;
2761    }
2762
2763    ///////////////////////////////////////////////////////////////////////////
2764    // Inner classes
2765    ///////////////////////////////////////////////////////////////////////////
2766
2767    public class VolumeStreamState {
2768        private final int mStreamType;
2769
2770        private String mVolumeIndexSettingName;
2771        private int mIndexMax;
2772        private final ConcurrentHashMap<Integer, Integer> mIndex =
2773                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2774        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
2775
2776        private VolumeStreamState(String settingName, int streamType) {
2777
2778            mVolumeIndexSettingName = settingName;
2779
2780            mStreamType = streamType;
2781            mIndexMax = MAX_STREAM_VOLUME[streamType];
2782            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2783            mIndexMax *= 10;
2784
2785            // mDeathHandlers must be created before calling readSettings()
2786            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
2787
2788            readSettings();
2789        }
2790
2791        public String getSettingNameForDevice(int device) {
2792            String name = mVolumeIndexSettingName;
2793            String suffix = AudioSystem.getDeviceName(device);
2794            if (suffix.isEmpty()) {
2795                return name;
2796            }
2797            return name + "_" + suffix;
2798        }
2799
2800        public synchronized void readSettings() {
2801            // force maximum volume on all streams if fixed volume property is set
2802            if (mUseFixedVolume) {
2803                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
2804                return;
2805            }
2806            // do not read system stream volume from settings: this stream is always aliased
2807            // to another stream type and its volume is never persisted. Values in settings can
2808            // only be stale values
2809            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2810                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2811                int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2812                synchronized (mCameraSoundForced) {
2813                    if (mCameraSoundForced) {
2814                        index = mIndexMax;
2815                    }
2816                }
2817                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2818                return;
2819            }
2820
2821            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
2822
2823            for (int i = 0; remainingDevices != 0; i++) {
2824                int device = (1 << i);
2825                if ((device & remainingDevices) == 0) {
2826                    continue;
2827                }
2828                remainingDevices &= ~device;
2829
2830                // retrieve current volume for device
2831                String name = getSettingNameForDevice(device);
2832                // if no volume stored for current stream and device, use default volume if default
2833                // device, continue otherwise
2834                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
2835                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
2836                int index = Settings.System.getIntForUser(
2837                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
2838                if (index == -1) {
2839                    continue;
2840                }
2841
2842                // ignore settings for fixed volume devices: volume should always be at max or 0
2843                if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
2844                        ((device & mFixedVolumeDevices) != 0)) {
2845                    mIndex.put(device, (index != 0) ? mIndexMax : 0);
2846                } else {
2847                    mIndex.put(device, getValidIndex(10 * index));
2848                }
2849            }
2850        }
2851
2852        public void applyDeviceVolume(int device) {
2853            int index;
2854            if (isMuted()) {
2855                index = 0;
2856            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
2857                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
2858                       mAvrcpAbsVolSupported) {
2859                index = (mIndexMax + 5)/10;
2860            }
2861            else {
2862                index = (getIndex(device) + 5)/10;
2863            }
2864            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
2865        }
2866
2867        public synchronized void applyAllVolumes() {
2868            // apply default volume first: by convention this will reset all
2869            // devices volumes in audio policy manager to the supplied value
2870            int index;
2871            if (isMuted()) {
2872                index = 0;
2873            } else {
2874                index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
2875            }
2876            AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
2877            // then apply device specific volumes
2878            Set set = mIndex.entrySet();
2879            Iterator i = set.iterator();
2880            while (i.hasNext()) {
2881                Map.Entry entry = (Map.Entry)i.next();
2882                int device = ((Integer)entry.getKey()).intValue();
2883                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
2884                    if (isMuted()) {
2885                        index = 0;
2886                    } else {
2887                        index = ((Integer)entry.getValue() + 5)/10;
2888                    }
2889                    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
2890                }
2891            }
2892        }
2893
2894        public boolean adjustIndex(int deltaIndex, int device) {
2895            return setIndex(getIndex(device) + deltaIndex,
2896                            device);
2897        }
2898
2899        public synchronized boolean setIndex(int index, int device) {
2900            int oldIndex = getIndex(device);
2901            index = getValidIndex(index);
2902            synchronized (mCameraSoundForced) {
2903                if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
2904                    index = mIndexMax;
2905                }
2906            }
2907            mIndex.put(device, index);
2908
2909            if (oldIndex != index) {
2910                // Apply change to all streams using this one as alias
2911                // if changing volume of current device, also change volume of current
2912                // device on aliased stream
2913                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2914                int numStreamTypes = AudioSystem.getNumStreamTypes();
2915                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2916                    if (streamType != mStreamType &&
2917                            mStreamVolumeAlias[streamType] == mStreamType) {
2918                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2919                        mStreamStates[streamType].setIndex(scaledIndex,
2920                                                           device);
2921                        if (currentDevice) {
2922                            mStreamStates[streamType].setIndex(scaledIndex,
2923                                                               getDeviceForStream(streamType));
2924                        }
2925                    }
2926                }
2927                return true;
2928            } else {
2929                return false;
2930            }
2931        }
2932
2933        public synchronized int getIndex(int device) {
2934            Integer index = mIndex.get(device);
2935            if (index == null) {
2936                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
2937                index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
2938            }
2939            return index.intValue();
2940        }
2941
2942        public int getMaxIndex() {
2943            return mIndexMax;
2944        }
2945
2946        public synchronized void setAllIndexes(VolumeStreamState srcStream) {
2947            Set set = srcStream.mIndex.entrySet();
2948            Iterator i = set.iterator();
2949            while (i.hasNext()) {
2950                Map.Entry entry = (Map.Entry)i.next();
2951                int device = ((Integer)entry.getKey()).intValue();
2952                int index = ((Integer)entry.getValue()).intValue();
2953                index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
2954
2955                setIndex(index, device);
2956            }
2957        }
2958
2959        public synchronized void setAllIndexesToMax() {
2960            Set set = mIndex.entrySet();
2961            Iterator i = set.iterator();
2962            while (i.hasNext()) {
2963                Map.Entry entry = (Map.Entry)i.next();
2964                entry.setValue(mIndexMax);
2965            }
2966        }
2967
2968        public synchronized void mute(IBinder cb, boolean state) {
2969            VolumeDeathHandler handler = getDeathHandler(cb, state);
2970            if (handler == null) {
2971                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
2972                return;
2973            }
2974            handler.mute(state);
2975        }
2976
2977        public int getStreamType() {
2978            return mStreamType;
2979        }
2980
2981        private int getValidIndex(int index) {
2982            if (index < 0) {
2983                return 0;
2984            } else if (mUseFixedVolume || index > mIndexMax) {
2985                return mIndexMax;
2986            }
2987
2988            return index;
2989        }
2990
2991        private class VolumeDeathHandler implements IBinder.DeathRecipient {
2992            private IBinder mICallback; // To be notified of client's death
2993            private int mMuteCount; // Number of active mutes for this client
2994
2995            VolumeDeathHandler(IBinder cb) {
2996                mICallback = cb;
2997            }
2998
2999            // must be called while synchronized on parent VolumeStreamState
3000            public void mute(boolean state) {
3001                boolean updateVolume = false;
3002                if (state) {
3003                    if (mMuteCount == 0) {
3004                        // Register for client death notification
3005                        try {
3006                            // mICallback can be 0 if muted by AudioService
3007                            if (mICallback != null) {
3008                                mICallback.linkToDeath(this, 0);
3009                            }
3010                            VolumeStreamState.this.mDeathHandlers.add(this);
3011                            // If the stream is not yet muted by any client, set level to 0
3012                            if (!VolumeStreamState.this.isMuted()) {
3013                                updateVolume = true;
3014                            }
3015                        } catch (RemoteException e) {
3016                            // Client has died!
3017                            binderDied();
3018                            return;
3019                        }
3020                    } else {
3021                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3022                    }
3023                    mMuteCount++;
3024                } else {
3025                    if (mMuteCount == 0) {
3026                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3027                    } else {
3028                        mMuteCount--;
3029                        if (mMuteCount == 0) {
3030                            // Unregister from client death notification
3031                            VolumeStreamState.this.mDeathHandlers.remove(this);
3032                            // mICallback can be 0 if muted by AudioService
3033                            if (mICallback != null) {
3034                                mICallback.unlinkToDeath(this, 0);
3035                            }
3036                            if (!VolumeStreamState.this.isMuted()) {
3037                                updateVolume = true;
3038                            }
3039                        }
3040                    }
3041                }
3042                if (updateVolume) {
3043                    sendMsg(mAudioHandler,
3044                            MSG_SET_ALL_VOLUMES,
3045                            SENDMSG_QUEUE,
3046                            0,
3047                            0,
3048                            VolumeStreamState.this, 0);
3049                }
3050            }
3051
3052            public void binderDied() {
3053                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3054                if (mMuteCount != 0) {
3055                    // Reset all active mute requests from this client.
3056                    mMuteCount = 1;
3057                    mute(false);
3058                }
3059            }
3060        }
3061
3062        private synchronized int muteCount() {
3063            int count = 0;
3064            int size = mDeathHandlers.size();
3065            for (int i = 0; i < size; i++) {
3066                count += mDeathHandlers.get(i).mMuteCount;
3067            }
3068            return count;
3069        }
3070
3071        private synchronized boolean isMuted() {
3072            return muteCount() != 0;
3073        }
3074
3075        // only called by mute() which is already synchronized
3076        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
3077            VolumeDeathHandler handler;
3078            int size = mDeathHandlers.size();
3079            for (int i = 0; i < size; i++) {
3080                handler = mDeathHandlers.get(i);
3081                if (cb == handler.mICallback) {
3082                    return handler;
3083                }
3084            }
3085            // If this is the first mute request for this client, create a new
3086            // client death handler. Otherwise, it is an out of sequence unmute request.
3087            if (state) {
3088                handler = new VolumeDeathHandler(cb);
3089            } else {
3090                Log.w(TAG, "stream was not muted by this client");
3091                handler = null;
3092            }
3093            return handler;
3094        }
3095
3096        private void dump(PrintWriter pw) {
3097            pw.print("   Mute count: ");
3098            pw.println(muteCount());
3099            pw.print("   Current: ");
3100            Set set = mIndex.entrySet();
3101            Iterator i = set.iterator();
3102            while (i.hasNext()) {
3103                Map.Entry entry = (Map.Entry)i.next();
3104                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3105                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3106            }
3107        }
3108    }
3109
3110    /** Thread that handles native AudioSystem control. */
3111    private class AudioSystemThread extends Thread {
3112        AudioSystemThread() {
3113            super("AudioService");
3114        }
3115
3116        @Override
3117        public void run() {
3118            // Set this thread up so the handler will work on it
3119            Looper.prepare();
3120
3121            synchronized(AudioService.this) {
3122                mAudioHandler = new AudioHandler();
3123
3124                // Notify that the handler has been created
3125                AudioService.this.notify();
3126            }
3127
3128            // Listen for volume change requests that are set by VolumePanel
3129            Looper.loop();
3130        }
3131    }
3132
3133    /** Handles internal volume messages in separate volume thread. */
3134    private class AudioHandler extends Handler {
3135
3136        private void setDeviceVolume(VolumeStreamState streamState, int device) {
3137
3138            // Apply volume
3139            streamState.applyDeviceVolume(device);
3140
3141            // Apply change to all streams using this one as alias
3142            int numStreamTypes = AudioSystem.getNumStreamTypes();
3143            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3144                if (streamType != streamState.mStreamType &&
3145                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3146                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
3147                }
3148            }
3149
3150            // Post a persist volume msg
3151            sendMsg(mAudioHandler,
3152                    MSG_PERSIST_VOLUME,
3153                    SENDMSG_QUEUE,
3154                    device,
3155                    0,
3156                    streamState,
3157                    PERSIST_DELAY);
3158
3159        }
3160
3161        private void setAllVolumes(VolumeStreamState streamState) {
3162
3163            // Apply volume
3164            streamState.applyAllVolumes();
3165
3166            // Apply change to all streams using this one as alias
3167            int numStreamTypes = AudioSystem.getNumStreamTypes();
3168            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3169                if (streamType != streamState.mStreamType &&
3170                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3171                    mStreamStates[streamType].applyAllVolumes();
3172                }
3173            }
3174        }
3175
3176        private void persistVolume(VolumeStreamState streamState, int device) {
3177            if (mUseFixedVolume) {
3178                return;
3179            }
3180            System.putIntForUser(mContentResolver,
3181                      streamState.getSettingNameForDevice(device),
3182                      (streamState.getIndex(device) + 5)/ 10,
3183                      UserHandle.USER_CURRENT);
3184        }
3185
3186        private void persistRingerMode(int ringerMode) {
3187            if (mUseFixedVolume) {
3188                return;
3189            }
3190            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
3191        }
3192
3193        private boolean onLoadSoundEffects() {
3194            int status;
3195
3196            synchronized (mSoundEffectsLock) {
3197                if (!mBootCompleted) {
3198                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3199                    return false;
3200                }
3201
3202                if (mSoundPool != null) {
3203                    return true;
3204                }
3205
3206                loadTouchSoundAssets();
3207
3208                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
3209                mSoundPoolCallBack = null;
3210                mSoundPoolListenerThread = new SoundPoolListenerThread();
3211                mSoundPoolListenerThread.start();
3212                int attempts = 3;
3213                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3214                    try {
3215                        // Wait for mSoundPoolCallBack to be set by the other thread
3216                        mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
3217                    } catch (InterruptedException e) {
3218                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3219                    }
3220                }
3221
3222                if (mSoundPoolCallBack == null) {
3223                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3224                    if (mSoundPoolLooper != null) {
3225                        mSoundPoolLooper.quit();
3226                        mSoundPoolLooper = null;
3227                    }
3228                    mSoundPoolListenerThread = null;
3229                    mSoundPool.release();
3230                    mSoundPool = null;
3231                    return false;
3232                }
3233                /*
3234                 * poolId table: The value -1 in this table indicates that corresponding
3235                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3236                 * Once loaded, the value in poolId is the sample ID and the same
3237                 * sample can be reused for another effect using the same file.
3238                 */
3239                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3240                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3241                    poolId[fileIdx] = -1;
3242                }
3243                /*
3244                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3245                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3246                 * this indicates we have a valid sample loaded for this effect.
3247                 */
3248
3249                int numSamples = 0;
3250                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3251                    // Do not load sample if this effect uses the MediaPlayer
3252                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3253                        continue;
3254                    }
3255                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3256                        String filePath = Environment.getRootDirectory()
3257                                + SOUND_EFFECTS_PATH
3258                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3259                        int sampleId = mSoundPool.load(filePath, 0);
3260                        if (sampleId <= 0) {
3261                            Log.w(TAG, "Soundpool could not load file: "+filePath);
3262                        } else {
3263                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3264                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3265                            numSamples++;
3266                        }
3267                    } else {
3268                        SOUND_EFFECT_FILES_MAP[effect][1] =
3269                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3270                    }
3271                }
3272                // wait for all samples to be loaded
3273                if (numSamples > 0) {
3274                    mSoundPoolCallBack.setSamples(poolId);
3275
3276                    attempts = 3;
3277                    status = 1;
3278                    while ((status == 1) && (attempts-- > 0)) {
3279                        try {
3280                            mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
3281                            status = mSoundPoolCallBack.status();
3282                        } catch (InterruptedException e) {
3283                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
3284                        }
3285                    }
3286                } else {
3287                    status = -1;
3288                }
3289
3290                if (mSoundPoolLooper != null) {
3291                    mSoundPoolLooper.quit();
3292                    mSoundPoolLooper = null;
3293                }
3294                mSoundPoolListenerThread = null;
3295                if (status != 0) {
3296                    Log.w(TAG,
3297                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
3298                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3299                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3300                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3301                        }
3302                    }
3303
3304                    mSoundPool.release();
3305                    mSoundPool = null;
3306                }
3307            }
3308            return (status == 0);
3309        }
3310
3311        /**
3312         *  Unloads samples from the sound pool.
3313         *  This method can be called to free some memory when
3314         *  sound effects are disabled.
3315         */
3316        private void onUnloadSoundEffects() {
3317            synchronized (mSoundEffectsLock) {
3318                if (mSoundPool == null) {
3319                    return;
3320                }
3321
3322                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3323                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3324                    poolId[fileIdx] = 0;
3325                }
3326
3327                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3328                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3329                        continue;
3330                    }
3331                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3332                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3333                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3334                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3335                    }
3336                }
3337                mSoundPool.release();
3338                mSoundPool = null;
3339            }
3340        }
3341
3342        private void onPlaySoundEffect(int effectType, int volume) {
3343            synchronized (mSoundEffectsLock) {
3344
3345                onLoadSoundEffects();
3346
3347                if (mSoundPool == null) {
3348                    return;
3349                }
3350                float volFloat;
3351                // use default if volume is not specified by caller
3352                if (volume < 0) {
3353                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3354                } else {
3355                    volFloat = (float) volume / 1000.0f;
3356                }
3357
3358                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
3359                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3360                                        volFloat, volFloat, 0, 0, 1.0f);
3361                } else {
3362                    MediaPlayer mediaPlayer = new MediaPlayer();
3363                    try {
3364                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3365                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
3366                        mediaPlayer.setDataSource(filePath);
3367                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3368                        mediaPlayer.prepare();
3369                        mediaPlayer.setVolume(volFloat);
3370                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3371                            public void onCompletion(MediaPlayer mp) {
3372                                cleanupPlayer(mp);
3373                            }
3374                        });
3375                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
3376                            public boolean onError(MediaPlayer mp, int what, int extra) {
3377                                cleanupPlayer(mp);
3378                                return true;
3379                            }
3380                        });
3381                        mediaPlayer.start();
3382                    } catch (IOException ex) {
3383                        Log.w(TAG, "MediaPlayer IOException: "+ex);
3384                    } catch (IllegalArgumentException ex) {
3385                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3386                    } catch (IllegalStateException ex) {
3387                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3388                    }
3389                }
3390            }
3391        }
3392
3393        private void cleanupPlayer(MediaPlayer mp) {
3394            if (mp != null) {
3395                try {
3396                    mp.stop();
3397                    mp.release();
3398                } catch (IllegalStateException ex) {
3399                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3400                }
3401            }
3402        }
3403
3404        private void setForceUse(int usage, int config) {
3405            AudioSystem.setForceUse(usage, config);
3406        }
3407
3408        private void onPersistSafeVolumeState(int state) {
3409            Settings.Global.putInt(mContentResolver,
3410                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3411                    state);
3412        }
3413
3414        @Override
3415        public void handleMessage(Message msg) {
3416
3417            switch (msg.what) {
3418
3419                case MSG_SET_DEVICE_VOLUME:
3420                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3421                    break;
3422
3423                case MSG_SET_ALL_VOLUMES:
3424                    setAllVolumes((VolumeStreamState) msg.obj);
3425                    break;
3426
3427                case MSG_PERSIST_VOLUME:
3428                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
3429                    break;
3430
3431                case MSG_PERSIST_MASTER_VOLUME:
3432                    if (mUseFixedVolume) {
3433                        return;
3434                    }
3435                    Settings.System.putFloatForUser(mContentResolver,
3436                                                    Settings.System.VOLUME_MASTER,
3437                                                    (float)msg.arg1 / (float)1000.0,
3438                                                    UserHandle.USER_CURRENT);
3439                    break;
3440
3441                case MSG_PERSIST_MASTER_VOLUME_MUTE:
3442                    if (mUseFixedVolume) {
3443                        return;
3444                    }
3445                    Settings.System.putIntForUser(mContentResolver,
3446                                                 Settings.System.VOLUME_MASTER_MUTE,
3447                                                 msg.arg1,
3448                                                 UserHandle.USER_CURRENT);
3449                    break;
3450
3451                case MSG_PERSIST_RINGER_MODE:
3452                    // note that the value persisted is the current ringer mode, not the
3453                    // value of ringer mode as of the time the request was made to persist
3454                    persistRingerMode(getRingerMode());
3455                    break;
3456
3457                case MSG_MEDIA_SERVER_DIED:
3458                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
3459                        Log.e(TAG, "Media server died.");
3460                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
3461                                null, 500);
3462                        break;
3463                    }
3464                    Log.e(TAG, "Media server started.");
3465
3466                    // indicate to audio HAL that we start the reconfiguration phase after a media
3467                    // server crash
3468                    // Note that we only execute this when the media server
3469                    // process restarts after a crash, not the first time it is started.
3470                    AudioSystem.setParameters("restarting=true");
3471
3472                    readAndSetLowRamDevice();
3473
3474                    // Restore device connection states
3475                    synchronized (mConnectedDevices) {
3476                        Set set = mConnectedDevices.entrySet();
3477                        Iterator i = set.iterator();
3478                        while (i.hasNext()) {
3479                            Map.Entry device = (Map.Entry)i.next();
3480                            AudioSystem.setDeviceConnectionState(
3481                                                            ((Integer)device.getKey()).intValue(),
3482                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
3483                                                            (String)device.getValue());
3484                        }
3485                    }
3486                    // Restore call state
3487                    AudioSystem.setPhoneState(mMode);
3488
3489                    // Restore forced usage for communcations and record
3490                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3491                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3492                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3493                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3494
3495                    // Restore stream volumes
3496                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3497                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3498                        VolumeStreamState streamState = mStreamStates[streamType];
3499                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
3500
3501                        streamState.applyAllVolumes();
3502                    }
3503
3504                    // Restore ringer mode
3505                    setRingerModeInt(getRingerMode(), false);
3506
3507                    // Restore master volume
3508                    restoreMasterVolume();
3509
3510                    // Reset device orientation (if monitored for this device)
3511                    if (mMonitorOrientation) {
3512                        setOrientationForAudioSystem();
3513                    }
3514                    if (mMonitorRotation) {
3515                        setRotationForAudioSystem();
3516                    }
3517
3518                    synchronized (mBluetoothA2dpEnabledLock) {
3519                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3520                                mBluetoothA2dpEnabled ?
3521                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3522                    }
3523
3524                    synchronized (mSettingsLock) {
3525                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3526                                mDockAudioMediaEnabled ?
3527                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3528                    }
3529
3530                    // indicate the end of reconfiguration phase to audio HAL
3531                    AudioSystem.setParameters("restarting=false");
3532                    break;
3533
3534                case MSG_UNLOAD_SOUND_EFFECTS:
3535                    onUnloadSoundEffects();
3536                    break;
3537
3538                case MSG_LOAD_SOUND_EFFECTS:
3539                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3540                    // can take several dozens of milliseconds to complete
3541                    boolean loaded = onLoadSoundEffects();
3542                    if (msg.obj != null) {
3543                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3544                        synchronized (reply) {
3545                            reply.mStatus = loaded ? 0 : -1;
3546                            reply.notify();
3547                        }
3548                    }
3549                    break;
3550
3551                case MSG_PLAY_SOUND_EFFECT:
3552                    onPlaySoundEffect(msg.arg1, msg.arg2);
3553                    break;
3554
3555                case MSG_BTA2DP_DOCK_TIMEOUT:
3556                    // msg.obj  == address of BTA2DP device
3557                    synchronized (mConnectedDevices) {
3558                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
3559                    }
3560                    break;
3561
3562                case MSG_SET_FORCE_USE:
3563                case MSG_SET_FORCE_BT_A2DP_USE:
3564                    setForceUse(msg.arg1, msg.arg2);
3565                    break;
3566
3567                case MSG_BT_HEADSET_CNCT_FAILED:
3568                    resetBluetoothSco();
3569                    break;
3570
3571                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3572                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3573                    mAudioEventWakeLock.release();
3574                    break;
3575
3576                case MSG_SET_A2DP_CONNECTION_STATE:
3577                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3578                    mAudioEventWakeLock.release();
3579                    break;
3580
3581                case MSG_REPORT_NEW_ROUTES: {
3582                    int N = mRoutesObservers.beginBroadcast();
3583                    if (N > 0) {
3584                        AudioRoutesInfo routes;
3585                        synchronized (mCurAudioRoutes) {
3586                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3587                        }
3588                        while (N > 0) {
3589                            N--;
3590                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3591                            try {
3592                                obs.dispatchAudioRoutesChanged(routes);
3593                            } catch (RemoteException e) {
3594                            }
3595                        }
3596                    }
3597                    mRoutesObservers.finishBroadcast();
3598                    break;
3599                }
3600
3601                case MSG_CHECK_MUSIC_ACTIVE:
3602                    onCheckMusicActive();
3603                    break;
3604
3605                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3606                    onSendBecomingNoisyIntent();
3607                    break;
3608
3609                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3610                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3611                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3612                    break;
3613                case MSG_PERSIST_SAFE_VOLUME_STATE:
3614                    onPersistSafeVolumeState(msg.arg1);
3615                    break;
3616
3617                case MSG_BROADCAST_BT_CONNECTION_STATE:
3618                    onBroadcastScoConnectionState(msg.arg1);
3619                    break;
3620            }
3621        }
3622    }
3623
3624    private class SettingsObserver extends ContentObserver {
3625
3626        SettingsObserver() {
3627            super(new Handler());
3628            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3629                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3630            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3631                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3632        }
3633
3634        @Override
3635        public void onChange(boolean selfChange) {
3636            super.onChange(selfChange);
3637            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3638            //       However there appear to be some missing locks around mRingerModeMutedStreams
3639            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3640            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3641            synchronized (mSettingsLock) {
3642                int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3643                       Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3644                       ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3645                       (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3646                       UserHandle.USER_CURRENT);
3647                if (mVoiceCapable) {
3648                    ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3649                } else {
3650                    ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
3651                }
3652                synchronized (mCameraSoundForced) {
3653                    if (mCameraSoundForced) {
3654                        ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3655                    } else {
3656                        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3657                    }
3658                }
3659                if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3660                    /*
3661                     * Ensure all stream types that should be affected by ringer mode
3662                     * are in the proper state.
3663                     */
3664                    mRingerModeAffectedStreams = ringerModeAffectedStreams;
3665                    setRingerModeInt(getRingerMode(), false);
3666                }
3667                readDockAudioSettings(mContentResolver);
3668            }
3669        }
3670    }
3671
3672    // must be called synchronized on mConnectedDevices
3673    private void makeA2dpDeviceAvailable(String address) {
3674        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3675        // audio policy manager
3676        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3677        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3678                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
3679        setBluetoothA2dpOnInt(true);
3680        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3681                AudioSystem.DEVICE_STATE_AVAILABLE,
3682                address);
3683        // Reset A2DP suspend state each time a new sink is connected
3684        AudioSystem.setParameters("A2dpSuspended=false");
3685        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3686                address);
3687    }
3688
3689    private void onSendBecomingNoisyIntent() {
3690        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
3691    }
3692
3693    // must be called synchronized on mConnectedDevices
3694    private void makeA2dpDeviceUnavailableNow(String address) {
3695        synchronized (mA2dpAvrcpLock) {
3696            mAvrcpAbsVolSupported = false;
3697        }
3698        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3699                AudioSystem.DEVICE_STATE_UNAVAILABLE,
3700                address);
3701        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3702    }
3703
3704    // must be called synchronized on mConnectedDevices
3705    private void makeA2dpDeviceUnavailableLater(String address) {
3706        // prevent any activity on the A2DP audio output to avoid unwanted
3707        // reconnection of the sink.
3708        AudioSystem.setParameters("A2dpSuspended=true");
3709        // the device will be made unavailable later, so consider it disconnected right away
3710        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3711        // send the delayed message to make the device unavailable later
3712        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3713        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3714
3715    }
3716
3717    // must be called synchronized on mConnectedDevices
3718    private void cancelA2dpDeviceTimeout() {
3719        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3720    }
3721
3722    // must be called synchronized on mConnectedDevices
3723    private boolean hasScheduledA2dpDockTimeout() {
3724        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3725    }
3726
3727    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
3728    {
3729        if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state);
3730        if (btDevice == null) {
3731            return;
3732        }
3733        String address = btDevice.getAddress();
3734        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3735            address = "";
3736        }
3737
3738        synchronized (mConnectedDevices) {
3739            boolean isConnected =
3740                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
3741                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
3742
3743            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
3744                if (btDevice.isBluetoothDock()) {
3745                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
3746                        // introduction of a delay for transient disconnections of docks when
3747                        // power is rapidly turned off/on, this message will be canceled if
3748                        // we reconnect the dock under a preset delay
3749                        makeA2dpDeviceUnavailableLater(address);
3750                        // the next time isConnected is evaluated, it will be false for the dock
3751                    }
3752                } else {
3753                    makeA2dpDeviceUnavailableNow(address);
3754                }
3755                synchronized (mCurAudioRoutes) {
3756                    if (mCurAudioRoutes.mBluetoothName != null) {
3757                        mCurAudioRoutes.mBluetoothName = null;
3758                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3759                                SENDMSG_NOOP, 0, 0, null, 0);
3760                    }
3761                }
3762            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
3763                if (btDevice.isBluetoothDock()) {
3764                    // this could be a reconnection after a transient disconnection
3765                    cancelA2dpDeviceTimeout();
3766                    mDockAddress = address;
3767                } else {
3768                    // this could be a connection of another A2DP device before the timeout of
3769                    // a dock: cancel the dock timeout, and make the dock unavailable now
3770                    if(hasScheduledA2dpDockTimeout()) {
3771                        cancelA2dpDeviceTimeout();
3772                        makeA2dpDeviceUnavailableNow(mDockAddress);
3773                    }
3774                }
3775                makeA2dpDeviceAvailable(address);
3776                synchronized (mCurAudioRoutes) {
3777                    String name = btDevice.getAliasName();
3778                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3779                        mCurAudioRoutes.mBluetoothName = name;
3780                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3781                                SENDMSG_NOOP, 0, 0, null, 0);
3782                    }
3783                }
3784            }
3785        }
3786    }
3787
3788    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
3789        // address is not used for now, but may be used when multiple a2dp devices are supported
3790        synchronized (mA2dpAvrcpLock) {
3791            mAvrcpAbsVolSupported = support;
3792            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3793            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3794                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
3795        }
3796    }
3797
3798    private boolean handleDeviceConnection(boolean connected, int device, String params) {
3799        synchronized (mConnectedDevices) {
3800            boolean isConnected = (mConnectedDevices.containsKey(device) &&
3801                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
3802
3803            if (isConnected && !connected) {
3804                AudioSystem.setDeviceConnectionState(device,
3805                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
3806                                              mConnectedDevices.get(device));
3807                 mConnectedDevices.remove(device);
3808                 return true;
3809            } else if (!isConnected && connected) {
3810                 AudioSystem.setDeviceConnectionState(device,
3811                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
3812                                                      params);
3813                 mConnectedDevices.put(new Integer(device), params);
3814                 return true;
3815            }
3816        }
3817        return false;
3818    }
3819
3820    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3821    // sent if none of these devices is connected.
3822    int mBecomingNoisyIntentDevices =
3823            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3824            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL |
3825            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
3826            AudioSystem.DEVICE_OUT_ALL_USB;
3827
3828    // must be called before removing the device from mConnectedDevices
3829    private int checkSendBecomingNoisyIntent(int device, int state) {
3830        int delay = 0;
3831        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3832            int devices = 0;
3833            for (int dev : mConnectedDevices.keySet()) {
3834                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3835                   devices |= dev;
3836                }
3837            }
3838            if (devices == device) {
3839                sendMsg(mAudioHandler,
3840                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
3841                        SENDMSG_REPLACE,
3842                        0,
3843                        0,
3844                        null,
3845                        0);
3846                delay = 1000;
3847            }
3848        }
3849
3850        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3851                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3852            delay = 1000;
3853        }
3854        return delay;
3855    }
3856
3857    private void sendDeviceConnectionIntent(int device, int state, String name)
3858    {
3859        Intent intent = new Intent();
3860
3861        intent.putExtra("state", state);
3862        intent.putExtra("name", name);
3863        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3864
3865        int connType = 0;
3866
3867        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3868            connType = AudioRoutesInfo.MAIN_HEADSET;
3869            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3870            intent.putExtra("microphone", 1);
3871        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3872            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3873            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3874            intent.putExtra("microphone", 0);
3875        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3876            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3877            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3878        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3879            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3880            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3881        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3882            connType = AudioRoutesInfo.MAIN_HDMI;
3883            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3884        }
3885
3886        synchronized (mCurAudioRoutes) {
3887            if (connType != 0) {
3888                int newConn = mCurAudioRoutes.mMainType;
3889                if (state != 0) {
3890                    newConn |= connType;
3891                } else {
3892                    newConn &= ~connType;
3893                }
3894                if (newConn != mCurAudioRoutes.mMainType) {
3895                    mCurAudioRoutes.mMainType = newConn;
3896                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3897                            SENDMSG_NOOP, 0, 0, null, 0);
3898                }
3899            }
3900        }
3901
3902        final long ident = Binder.clearCallingIdentity();
3903        try {
3904            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3905        } finally {
3906            Binder.restoreCallingIdentity(ident);
3907        }
3908    }
3909
3910    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3911    {
3912        synchronized (mConnectedDevices) {
3913            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3914                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3915                setBluetoothA2dpOnInt(true);
3916            }
3917            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
3918            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
3919            if (state != 0) {
3920                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3921                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
3922                    setBluetoothA2dpOnInt(false);
3923                }
3924                if ((device & mSafeMediaVolumeDevices) != 0) {
3925                    sendMsg(mAudioHandler,
3926                            MSG_CHECK_MUSIC_ACTIVE,
3927                            SENDMSG_REPLACE,
3928                            0,
3929                            0,
3930                            null,
3931                            MUSIC_ACTIVE_POLL_PERIOD_MS);
3932                }
3933            }
3934            if (!isUsb) {
3935                sendDeviceConnectionIntent(device, state, name);
3936            }
3937        }
3938    }
3939
3940    /* cache of the address of the last dock the device was connected to */
3941    private String mDockAddress;
3942
3943    /**
3944     * Receiver for misc intent broadcasts the Phone app cares about.
3945     */
3946    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
3947        @Override
3948        public void onReceive(Context context, Intent intent) {
3949            String action = intent.getAction();
3950            int device;
3951            int state;
3952
3953            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
3954                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
3955                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
3956                int config;
3957                switch (dockState) {
3958                    case Intent.EXTRA_DOCK_STATE_DESK:
3959                        config = AudioSystem.FORCE_BT_DESK_DOCK;
3960                        break;
3961                    case Intent.EXTRA_DOCK_STATE_CAR:
3962                        config = AudioSystem.FORCE_BT_CAR_DOCK;
3963                        break;
3964                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
3965                        config = AudioSystem.FORCE_ANALOG_DOCK;
3966                        break;
3967                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
3968                        config = AudioSystem.FORCE_DIGITAL_DOCK;
3969                        break;
3970                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
3971                    default:
3972                        config = AudioSystem.FORCE_NONE;
3973                }
3974                // Low end docks have a menu to enable or disable audio
3975                // (see mDockAudioMediaEnabled)
3976                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
3977                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
3978                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
3979                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
3980                }
3981                mDockState = dockState;
3982            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
3983                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
3984                                               BluetoothProfile.STATE_DISCONNECTED);
3985                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3986                String address = null;
3987
3988                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
3989                if (btDevice == null) {
3990                    return;
3991                }
3992
3993                address = btDevice.getAddress();
3994                BluetoothClass btClass = btDevice.getBluetoothClass();
3995                if (btClass != null) {
3996                    switch (btClass.getDeviceClass()) {
3997                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3998                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3999                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4000                        break;
4001                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4002                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4003                        break;
4004                    }
4005                }
4006
4007                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4008                    address = "";
4009                }
4010
4011                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4012                if (handleDeviceConnection(connected, device, address)) {
4013                    synchronized (mScoClients) {
4014                        if (connected) {
4015                            mBluetoothHeadsetDevice = btDevice;
4016                        } else {
4017                            mBluetoothHeadsetDevice = null;
4018                            resetBluetoothSco();
4019                        }
4020                    }
4021                }
4022            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
4023                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
4024                state = intent.getIntExtra("state", 0);
4025                int alsaCard = intent.getIntExtra("card", -1);
4026                int alsaDevice = intent.getIntExtra("device", -1);
4027                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4028                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4029                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
4030                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
4031                Log.v(TAG, "Broadcast Receiver: Got "
4032                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
4033                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
4034                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
4035                setWiredDeviceConnectionState(device, state, params);
4036            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
4037                boolean broadcast = false;
4038                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
4039                synchronized (mScoClients) {
4040                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4041                    // broadcast intent if the connection was initated by AudioService
4042                    if (!mScoClients.isEmpty() &&
4043                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4044                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4045                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
4046                        broadcast = true;
4047                    }
4048                    switch (btState) {
4049                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
4050                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4051                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4052                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4053                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4054                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4055                        }
4056                        break;
4057                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
4058                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
4059                        mScoAudioState = SCO_STATE_INACTIVE;
4060                        clearAllScoClients(0, false);
4061                        break;
4062                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4063                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4064                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4065                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4066                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4067                        }
4068                    default:
4069                        // do not broadcast CONNECTING or invalid state
4070                        broadcast = false;
4071                        break;
4072                    }
4073                }
4074                if (broadcast) {
4075                    broadcastScoConnectionState(scoAudioState);
4076                    //FIXME: this is to maintain compatibility with deprecated intent
4077                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4078                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4079                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
4080                    sendStickyBroadcastToAll(newIntent);
4081                }
4082            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
4083                mBootCompleted = true;
4084                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
4085                        0, 0, null, 0);
4086
4087                mKeyguardManager =
4088                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
4089                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
4090                resetBluetoothSco();
4091                getBluetoothHeadset();
4092                //FIXME: this is to maintain compatibility with deprecated intent
4093                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4094                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4095                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
4096                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
4097                sendStickyBroadcastToAll(newIntent);
4098
4099                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
4100                if (adapter != null) {
4101                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
4102                                            BluetoothProfile.A2DP);
4103                }
4104
4105                sendMsg(mAudioHandler,
4106                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
4107                        SENDMSG_REPLACE,
4108                        0,
4109                        0,
4110                        null,
4111                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
4112            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4113                AudioSystem.setParameters("screen_state=on");
4114            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4115                AudioSystem.setParameters("screen_state=off");
4116            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4117                handleConfigurationChanged(context);
4118            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4119                // attempt to stop music playback for background user
4120                sendMsg(mAudioHandler,
4121                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4122                        SENDMSG_REPLACE,
4123                        0,
4124                        0,
4125                        null,
4126                        0);
4127                // the current audio focus owner is no longer valid
4128                mMediaFocusControl.discardAudioFocusOwner();
4129
4130                // load volume settings for new user
4131                readAudioSettings(true /*userSwitch*/);
4132                // preserve STREAM_MUSIC volume from one user to the next.
4133                sendMsg(mAudioHandler,
4134                        MSG_SET_ALL_VOLUMES,
4135                        SENDMSG_QUEUE,
4136                        0,
4137                        0,
4138                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4139            }
4140        }
4141    }
4142
4143    //==========================================================================================
4144    // RemoteControlDisplay / RemoteControlClient / Remote info
4145    //==========================================================================================
4146    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4147        mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4148    }
4149
4150    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4151        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4152    }
4153
4154    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4155        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4156    }
4157
4158    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4159            boolean wantsSync) {
4160        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4161    }
4162
4163    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4164        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
4165    }
4166
4167    public void unregisterMediaButtonEventReceiverForCalls() {
4168        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
4169    }
4170
4171    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
4172        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
4173    }
4174
4175    public void unregisterMediaButtonIntent(PendingIntent pi) {
4176        mMediaFocusControl.unregisterMediaButtonIntent(pi);
4177    }
4178
4179    public int registerRemoteControlClient(PendingIntent mediaIntent,
4180            IRemoteControlClient rcClient, String callingPckg) {
4181        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
4182    }
4183
4184    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
4185            IRemoteControlClient rcClient) {
4186        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
4187    }
4188
4189    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
4190        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
4191    }
4192
4193    public void updateRemoteControlClientMetadata(int generationId, int key, long value) {
4194        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
4195    }
4196
4197    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
4198        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
4199    }
4200
4201    public int getRemoteStreamVolume() {
4202        return mMediaFocusControl.getRemoteStreamVolume();
4203    }
4204
4205    public int getRemoteStreamMaxVolume() {
4206        return mMediaFocusControl.getRemoteStreamMaxVolume();
4207    }
4208
4209    public void setRemoteStreamVolume(int index) {
4210        mMediaFocusControl.setRemoteStreamVolume(index);
4211    }
4212
4213    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
4214        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
4215    }
4216
4217    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4218        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
4219    }
4220
4221    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
4222        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
4223    }
4224
4225    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
4226        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
4227    }
4228
4229    //==========================================================================================
4230    // Audio Focus
4231    //==========================================================================================
4232    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4233            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4234        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4235                clientId, callingPackageName);
4236    }
4237
4238    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4239        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4240    }
4241
4242    public void unregisterAudioFocusClient(String clientId) {
4243        mMediaFocusControl.unregisterAudioFocusClient(clientId);
4244    }
4245
4246    public int getCurrentAudioFocus() {
4247        return mMediaFocusControl.getCurrentAudioFocus();
4248    }
4249
4250    //==========================================================================================
4251    // Device orientation
4252    //==========================================================================================
4253    /**
4254     * Handles device configuration changes that may map to a change in the orientation
4255     * or orientation.
4256     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4257     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4258     */
4259    private void handleConfigurationChanged(Context context) {
4260        try {
4261            // reading new orientation "safely" (i.e. under try catch) in case anything
4262            // goes wrong when obtaining resources and configuration
4263            Configuration config = context.getResources().getConfiguration();
4264            // TODO merge rotation and orientation
4265            if (mMonitorOrientation) {
4266                int newOrientation = config.orientation;
4267                if (newOrientation != mDeviceOrientation) {
4268                    mDeviceOrientation = newOrientation;
4269                    setOrientationForAudioSystem();
4270                }
4271            }
4272            if (mMonitorRotation) {
4273                int newRotation = ((WindowManager) context.getSystemService(
4274                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4275                if (newRotation != mDeviceRotation) {
4276                    mDeviceRotation = newRotation;
4277                    setRotationForAudioSystem();
4278                }
4279            }
4280            sendMsg(mAudioHandler,
4281                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4282                    SENDMSG_REPLACE,
4283                    0,
4284                    0,
4285                    null,
4286                    0);
4287
4288            boolean cameraSoundForced = mContext.getResources().getBoolean(
4289                    com.android.internal.R.bool.config_camera_sound_forced);
4290            synchronized (mSettingsLock) {
4291                synchronized (mCameraSoundForced) {
4292                    if (cameraSoundForced != mCameraSoundForced) {
4293                        mCameraSoundForced = cameraSoundForced;
4294
4295                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4296                        if (cameraSoundForced) {
4297                            s.setAllIndexesToMax();
4298                            mRingerModeAffectedStreams &=
4299                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4300                        } else {
4301                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4302                            mRingerModeAffectedStreams |=
4303                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4304                        }
4305                        // take new state into account for streams muted by ringer mode
4306                        setRingerModeInt(getRingerMode(), false);
4307
4308                        sendMsg(mAudioHandler,
4309                                MSG_SET_FORCE_USE,
4310                                SENDMSG_QUEUE,
4311                                AudioSystem.FOR_SYSTEM,
4312                                cameraSoundForced ?
4313                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4314                                null,
4315                                0);
4316
4317                        sendMsg(mAudioHandler,
4318                                MSG_SET_ALL_VOLUMES,
4319                                SENDMSG_QUEUE,
4320                                0,
4321                                0,
4322                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4323                    }
4324                }
4325            }
4326            mVolumePanel.setLayoutDirection(config.getLayoutDirection());
4327        } catch (Exception e) {
4328            Log.e(TAG, "Error handling configuration change: ", e);
4329        }
4330    }
4331
4332    private void setOrientationForAudioSystem() {
4333        switch (mDeviceOrientation) {
4334            case Configuration.ORIENTATION_LANDSCAPE:
4335                //Log.i(TAG, "orientation is landscape");
4336                AudioSystem.setParameters("orientation=landscape");
4337                break;
4338            case Configuration.ORIENTATION_PORTRAIT:
4339                //Log.i(TAG, "orientation is portrait");
4340                AudioSystem.setParameters("orientation=portrait");
4341                break;
4342            case Configuration.ORIENTATION_SQUARE:
4343                //Log.i(TAG, "orientation is square");
4344                AudioSystem.setParameters("orientation=square");
4345                break;
4346            case Configuration.ORIENTATION_UNDEFINED:
4347                //Log.i(TAG, "orientation is undefined");
4348                AudioSystem.setParameters("orientation=undefined");
4349                break;
4350            default:
4351                Log.e(TAG, "Unknown orientation");
4352        }
4353    }
4354
4355    private void setRotationForAudioSystem() {
4356        switch (mDeviceRotation) {
4357            case Surface.ROTATION_0:
4358                AudioSystem.setParameters("rotation=0");
4359                break;
4360            case Surface.ROTATION_90:
4361                AudioSystem.setParameters("rotation=90");
4362                break;
4363            case Surface.ROTATION_180:
4364                AudioSystem.setParameters("rotation=180");
4365                break;
4366            case Surface.ROTATION_270:
4367                AudioSystem.setParameters("rotation=270");
4368                break;
4369            default:
4370                Log.e(TAG, "Unknown device rotation");
4371        }
4372    }
4373
4374
4375    // Handles request to override default use of A2DP for media.
4376    public void setBluetoothA2dpOnInt(boolean on) {
4377        synchronized (mBluetoothA2dpEnabledLock) {
4378            mBluetoothA2dpEnabled = on;
4379            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4380            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4381                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4382        }
4383    }
4384
4385    @Override
4386    public void setRingtonePlayer(IRingtonePlayer player) {
4387        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4388        mRingtonePlayer = player;
4389    }
4390
4391    @Override
4392    public IRingtonePlayer getRingtonePlayer() {
4393        return mRingtonePlayer;
4394    }
4395
4396    @Override
4397    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4398        synchronized (mCurAudioRoutes) {
4399            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4400            mRoutesObservers.register(observer);
4401            return routes;
4402        }
4403    }
4404
4405
4406    //==========================================================================================
4407    // Safe media volume management.
4408    // MUSIC stream volume level is limited when headphones are connected according to safety
4409    // regulation. When the user attempts to raise the volume above the limit, a warning is
4410    // displayed and the user has to acknowlegde before the volume is actually changed.
4411    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4412    // property. Platforms with a different limit must set this property accordingly in their
4413    // overlay.
4414    //==========================================================================================
4415
4416    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4417    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4418    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4419    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4420    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4421    // (when user opts out).
4422    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4423    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4424    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4425    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4426    private Integer mSafeMediaVolumeState;
4427
4428    private int mMcc = 0;
4429    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4430    private int mSafeMediaVolumeIndex;
4431    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4432    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4433                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4434    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4435    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4436    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4437    private int mMusicActiveMs;
4438    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4439    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4440    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4441
4442    private void setSafeMediaVolumeEnabled(boolean on) {
4443        synchronized (mSafeMediaVolumeState) {
4444            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4445                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4446                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4447                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4448                    enforceSafeMediaVolume();
4449                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4450                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4451                    mMusicActiveMs = 0;
4452                    sendMsg(mAudioHandler,
4453                            MSG_CHECK_MUSIC_ACTIVE,
4454                            SENDMSG_REPLACE,
4455                            0,
4456                            0,
4457                            null,
4458                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4459                }
4460            }
4461        }
4462    }
4463
4464    private void enforceSafeMediaVolume() {
4465        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4466        int devices = mSafeMediaVolumeDevices;
4467        int i = 0;
4468
4469        while (devices != 0) {
4470            int device = 1 << i++;
4471            if ((device & devices) == 0) {
4472                continue;
4473            }
4474            int index = streamState.getIndex(device);
4475            if (index > mSafeMediaVolumeIndex) {
4476                streamState.setIndex(mSafeMediaVolumeIndex, device);
4477                sendMsg(mAudioHandler,
4478                        MSG_SET_DEVICE_VOLUME,
4479                        SENDMSG_QUEUE,
4480                        device,
4481                        0,
4482                        streamState,
4483                        0);
4484            }
4485            devices &= ~device;
4486        }
4487    }
4488
4489    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4490        synchronized (mSafeMediaVolumeState) {
4491            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4492                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4493                    ((device & mSafeMediaVolumeDevices) != 0) &&
4494                    (index > mSafeMediaVolumeIndex)) {
4495                return false;
4496            }
4497            return true;
4498        }
4499    }
4500
4501    public void disableSafeMediaVolume() {
4502        synchronized (mSafeMediaVolumeState) {
4503            setSafeMediaVolumeEnabled(false);
4504            if (mPendingVolumeCommand != null) {
4505                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4506                                  mPendingVolumeCommand.mIndex,
4507                                  mPendingVolumeCommand.mFlags,
4508                                  mPendingVolumeCommand.mDevice);
4509                mPendingVolumeCommand = null;
4510            }
4511        }
4512    }
4513
4514
4515    //==========================================================================================
4516    // Camera shutter sound policy.
4517    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4518    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4519    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4520    //==========================================================================================
4521
4522    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4523    private Boolean mCameraSoundForced;
4524
4525    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4526    public boolean isCameraSoundForced() {
4527        synchronized (mCameraSoundForced) {
4528            return mCameraSoundForced;
4529        }
4530    }
4531
4532    private static final String[] RINGER_MODE_NAMES = new String[] {
4533            "SILENT",
4534            "VIBRATE",
4535            "NORMAL"
4536    };
4537
4538    private void dumpRingerMode(PrintWriter pw) {
4539        pw.println("\nRinger mode: ");
4540        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4541        pw.print("- ringer mode affected streams = 0x");
4542        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4543        pw.print("- ringer mode muted streams = 0x");
4544        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4545    }
4546
4547    @Override
4548    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4549        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4550
4551        mMediaFocusControl.dump(pw);
4552        dumpStreamStates(pw);
4553        dumpRingerMode(pw);
4554        pw.println("\nAudio routes:");
4555        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4556        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
4557    }
4558
4559    // Inform AudioFlinger of our device's low RAM attribute
4560    private static void readAndSetLowRamDevice()
4561    {
4562        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4563        if (status != 0) {
4564            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4565        }
4566    }
4567}
4568