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