AudioService.java revision 84aa61e2a838fdeb7484ffaf95945a205bccb453
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.ActivityManagerNative;
26import android.app.KeyguardManager;
27import android.app.PendingIntent;
28import android.app.PendingIntent.CanceledException;
29import android.app.PendingIntent.OnFinished;
30import android.bluetooth.BluetoothA2dp;
31import android.bluetooth.BluetoothAdapter;
32import android.bluetooth.BluetoothClass;
33import android.bluetooth.BluetoothDevice;
34import android.bluetooth.BluetoothHeadset;
35import android.bluetooth.BluetoothProfile;
36import android.content.ActivityNotFoundException;
37import android.content.BroadcastReceiver;
38import android.content.ComponentName;
39import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
42import android.content.IntentFilter;
43import android.content.pm.PackageManager;
44import android.content.res.Configuration;
45import android.database.ContentObserver;
46import android.media.MediaPlayer.OnCompletionListener;
47import android.media.MediaPlayer.OnErrorListener;
48import android.os.Binder;
49import android.os.Bundle;
50import android.os.Environment;
51import android.os.Handler;
52import android.os.IBinder;
53import android.os.Looper;
54import android.os.Message;
55import android.os.PowerManager;
56import android.os.RemoteCallbackList;
57import android.os.RemoteException;
58import android.os.ServiceManager;
59import android.os.SystemProperties;
60import android.os.UserHandle;
61import android.os.Vibrator;
62import android.provider.Settings;
63import android.provider.Settings.System;
64import android.speech.RecognizerIntent;
65import android.telephony.PhoneStateListener;
66import android.telephony.TelephonyManager;
67import android.text.TextUtils;
68import android.util.Log;
69import android.view.KeyEvent;
70import android.view.VolumePanel;
71
72import com.android.internal.telephony.ITelephony;
73
74import java.io.FileDescriptor;
75import java.io.IOException;
76import java.io.PrintWriter;
77import java.util.ArrayList;
78import java.util.concurrent.ConcurrentHashMap;
79import java.util.HashMap;
80import java.util.Iterator;
81import java.util.List;
82import java.util.Map;
83import java.util.NoSuchElementException;
84import java.util.Set;
85import java.util.Stack;
86
87/**
88 * The implementation of the volume manager service.
89 * <p>
90 * This implementation focuses on delivering a responsive UI. Most methods are
91 * asynchronous to external calls. For example, the task of setting a volume
92 * will update our internal state, but in a separate thread will set the system
93 * volume and later persist to the database. Similarly, setting the ringer mode
94 * will update the state and broadcast a change and in a separate thread later
95 * persist the ringer mode.
96 *
97 * @hide
98 */
99public class AudioService extends IAudioService.Stub implements OnFinished {
100
101    private static final String TAG = "AudioService";
102
103    /** Debug remote control client/display feature */
104    protected static final boolean DEBUG_RC = false;
105    /** Debug volumes */
106    protected static final boolean DEBUG_VOL = false;
107
108    /** How long to delay before persisting a change in volume/ringer mode. */
109    private static final int PERSIST_DELAY = 500;
110
111    private Context mContext;
112    private ContentResolver mContentResolver;
113    private boolean mVoiceCapable;
114
115    /** The UI */
116    private VolumePanel mVolumePanel;
117
118    // sendMsg() flags
119    /** If the msg is already queued, replace it with this one. */
120    private static final int SENDMSG_REPLACE = 0;
121    /** If the msg is already queued, ignore this one and leave the old. */
122    private static final int SENDMSG_NOOP = 1;
123    /** If the msg is already queued, queue this one and leave the old. */
124    private static final int SENDMSG_QUEUE = 2;
125
126    // AudioHandler messages
127    private static final int MSG_SET_DEVICE_VOLUME = 0;
128    private static final int MSG_PERSIST_VOLUME = 1;
129    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
130    private static final int MSG_PERSIST_RINGER_MODE = 3;
131    private static final int MSG_MEDIA_SERVER_DIED = 4;
132    private static final int MSG_MEDIA_SERVER_STARTED = 5;
133    private static final int MSG_PLAY_SOUND_EFFECT = 6;
134    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7;
135    private static final int MSG_LOAD_SOUND_EFFECTS = 8;
136    private static final int MSG_SET_FORCE_USE = 9;
137    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10;
138    private static final int MSG_BT_HEADSET_CNCT_FAILED = 11;
139    private static final int MSG_RCDISPLAY_CLEAR = 12;
140    private static final int MSG_RCDISPLAY_UPDATE = 13;
141    private static final int MSG_SET_ALL_VOLUMES = 14;
142    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
143    private static final int MSG_REPORT_NEW_ROUTES = 16;
144    private static final int MSG_REEVALUATE_REMOTE = 17;
145    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18;
146    private static final int MSG_RCC_NEW_VOLUME_OBS = 19;
147    private static final int MSG_SET_FORCE_BT_A2DP_USE = 20;
148    // start of messages handled under wakelock
149    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
150    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
151    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21;
152    private static final int MSG_SET_A2DP_CONNECTION_STATE = 22;
153    // end of messages handled under wakelock
154    private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection
155    private static final int MSG_CHECK_MUSIC_ACTIVE = 24;
156    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 25;
157    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 26;
158    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 27;
159    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 28;
160
161    // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
162    // persisted
163    private static final int PERSIST_CURRENT = 0x1;
164    private static final int PERSIST_LAST_AUDIBLE = 0x2;
165
166    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
167    // Timeout for connection to bluetooth headset service
168    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
169
170    /** @see AudioSystemThread */
171    private AudioSystemThread mAudioSystemThread;
172    /** @see AudioHandler */
173    private AudioHandler mAudioHandler;
174    /** @see VolumeStreamState */
175    private VolumeStreamState[] mStreamStates;
176    private SettingsObserver mSettingsObserver;
177
178    private int mMode;
179    // protects mRingerMode
180    private final Object mSettingsLock = new Object();
181
182    private boolean mMediaServerOk;
183
184    private SoundPool mSoundPool;
185    private final Object mSoundEffectsLock = new Object();
186    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
187
188    // Internally master volume is a float in the 0.0 - 1.0 range,
189    // but to support integer based AudioManager API we translate it to 0 - 100
190    private static final int MAX_MASTER_VOLUME = 100;
191
192    // Maximum volume adjust steps allowed in a single batch call.
193    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
194
195    /* Sound effect file names  */
196    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
197    private static final String[] SOUND_EFFECT_FILES = new String[] {
198        "Effect_Tick.ogg",
199        "KeypressStandard.ogg",
200        "KeypressSpacebar.ogg",
201        "KeypressDelete.ogg",
202        "KeypressReturn.ogg"
203    };
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[][] {
209        {0, -1},  // FX_KEY_CLICK
210        {0, -1},  // FX_FOCUS_NAVIGATION_UP
211        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
212        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
213        {0, -1},  // FX_FOCUS_NAVIGATION_RIGHT
214        {1, -1},  // FX_KEYPRESS_STANDARD
215        {2, -1},  // FX_KEYPRESS_SPACEBAR
216        {3, -1},  // FX_FOCUS_DELETE
217        {4, -1}   // FX_FOCUS_RETURN
218    };
219
220   /** @hide Maximum volume index values for audio streams */
221    private final int[] MAX_STREAM_VOLUME = new int[] {
222        5,  // STREAM_VOICE_CALL
223        7,  // STREAM_SYSTEM
224        7,  // STREAM_RING
225        15, // STREAM_MUSIC
226        7,  // STREAM_ALARM
227        7,  // STREAM_NOTIFICATION
228        15, // STREAM_BLUETOOTH_SCO
229        7,  // STREAM_SYSTEM_ENFORCED
230        15, // STREAM_DTMF
231        15  // STREAM_TTS
232    };
233    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
234     * of another stream: This avoids multiplying the volume settings for hidden
235     * stream types that follow other stream behavior for volume settings
236     * NOTE: do not create loops in aliases!
237     * Some streams alias to different streams according to device category (phone or tablet) or
238     * use case (in call s off call...).See updateStreamVolumeAlias() for more details
239     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
240     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
241    private final int[] STREAM_VOLUME_ALIAS = new int[] {
242        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
243        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
244        AudioSystem.STREAM_RING,            // STREAM_RING
245        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
246        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
247        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
248        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
249        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
250        AudioSystem.STREAM_RING,            // STREAM_DTMF
251        AudioSystem.STREAM_MUSIC            // STREAM_TTS
252    };
253    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
254        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
255        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
256        AudioSystem.STREAM_RING,            // STREAM_RING
257        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
258        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
259        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
260        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
261        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
262        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
263        AudioSystem.STREAM_MUSIC            // STREAM_TTS
264    };
265    private int[] mStreamVolumeAlias;
266
267    // stream names used by dumpStreamStates()
268    private final String[] STREAM_NAMES = new String[] {
269            "STREAM_VOICE_CALL",
270            "STREAM_SYSTEM",
271            "STREAM_RING",
272            "STREAM_MUSIC",
273            "STREAM_ALARM",
274            "STREAM_NOTIFICATION",
275            "STREAM_BLUETOOTH_SCO",
276            "STREAM_SYSTEM_ENFORCED",
277            "STREAM_DTMF",
278            "STREAM_TTS"
279    };
280
281    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
282        public void onError(int error) {
283            switch (error) {
284            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
285                if (mMediaServerOk) {
286                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
287                            null, 1500);
288                    mMediaServerOk = false;
289                }
290                break;
291            case AudioSystem.AUDIO_STATUS_OK:
292                if (!mMediaServerOk) {
293                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0,
294                            null, 0);
295                    mMediaServerOk = true;
296                }
297                break;
298            default:
299                break;
300            }
301       }
302    };
303
304    /**
305     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
306     * {@link AudioManager#RINGER_MODE_SILENT}, or
307     * {@link AudioManager#RINGER_MODE_VIBRATE}.
308     */
309    // protected by mSettingsLock
310    private int mRingerMode;
311
312    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
313    private int mRingerModeAffectedStreams;
314
315    // Streams currently muted by ringer mode
316    private int mRingerModeMutedStreams;
317
318    /** @see System#MUTE_STREAMS_AFFECTED */
319    private int mMuteAffectedStreams;
320
321    /**
322     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
323     * mVibrateSetting is just maintained during deprecation period but vibration policy is
324     * now only controlled by mHasVibrator and mRingerMode
325     */
326    private int mVibrateSetting;
327
328    // Is there a vibrator
329    private final boolean mHasVibrator;
330
331    // Broadcast receiver for device connections intent broadcasts
332    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
333
334    // Used to alter media button redirection when the phone is ringing.
335    private boolean mIsRinging = false;
336
337    // Devices currently connected
338    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
339
340    // Forced device usage for communications
341    private int mForcedUseForComm;
342
343    // True if we have master volume support
344    private final boolean mUseMasterVolume;
345
346    private final int[] mMasterVolumeRamp;
347
348    // List of binder death handlers for setMode() client processes.
349    // The last process to have called setMode() is at the top of the list.
350    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
351
352    // List of clients having issued a SCO start request
353    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
354
355    // BluetoothHeadset API to control SCO connection
356    private BluetoothHeadset mBluetoothHeadset;
357
358    // Bluetooth headset device
359    private BluetoothDevice mBluetoothHeadsetDevice;
360
361    // Indicate if SCO audio connection is currently active and if the initiator is
362    // audio service (internal) or bluetooth headset (external)
363    private int mScoAudioState;
364    // SCO audio state is not active
365    private static final int SCO_STATE_INACTIVE = 0;
366    // SCO audio activation request waiting for headset service to connect
367    private static final int SCO_STATE_ACTIVATE_REQ = 1;
368    // SCO audio state is active or starting due to a local request to start a virtual call
369    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
370    // SCO audio deactivation request waiting for headset service to connect
371    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
372
373    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
374    // in call audio)
375    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
376    // Deactivation request for all SCO connections (initiated by audio mode change)
377    // waiting for headset service to connect
378    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
379
380    // Current connection state indicated by bluetooth headset
381    private int mScoConnectionState;
382
383    // true if boot sequence has been completed
384    private boolean mBootCompleted;
385    // listener for SoundPool sample load completion indication
386    private SoundPoolCallback mSoundPoolCallBack;
387    // thread for SoundPool listener
388    private SoundPoolListenerThread mSoundPoolListenerThread;
389    // message looper for SoundPool listener
390    private Looper mSoundPoolLooper = null;
391    // volume applied to sound played with playSoundEffect()
392    private static int sSoundEffectVolumeDb;
393    // getActiveStreamType() will return:
394    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
395    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
396    // stopped
397    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
398    // previous volume adjustment direction received by checkForRingerModeChange()
399    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
400    // Keyguard manager proxy
401    private KeyguardManager mKeyguardManager;
402    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
403    // is controlled by Vol keys.
404    private int  mVolumeControlStream = -1;
405    private final Object mForceControlStreamLock = new Object();
406    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
407    // server process so in theory it is not necessary to monitor the client death.
408    // However it is good to be ready for future evolutions.
409    private ForceControlStreamClient mForceControlStreamClient = null;
410    // Used to play ringtones outside system_server
411    private volatile IRingtonePlayer mRingtonePlayer;
412
413    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
414
415    // Request to override default use of A2DP for media.
416    private boolean mBluetoothA2dpEnabled;
417    private final Object mBluetoothA2dpEnabledLock = new Object();
418
419    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
420    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
421    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
422            = new RemoteCallbackList<IAudioRoutesObserver>();
423
424    /**
425     * A fake stream type to match the notion of remote media playback
426     */
427    public final static int STREAM_REMOTE_MUSIC = -200;
428
429    // Devices for which the volume is fixed and VolumePanel slider should be disabled
430    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL |
431            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
432            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
433            AudioSystem.DEVICE_OUT_ALL_USB;
434
435    private final boolean mMonitorOrientation;
436
437    private boolean mDockAudioMediaEnabled = true;
438
439    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
440
441    // Used when safe volume warning message display is requested by setStreamVolume(). In this
442    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
443    // and used later when/if disableSafeMediaVolume() is called.
444    private StreamVolumeCommand mPendingVolumeCommand;
445
446    ///////////////////////////////////////////////////////////////////////////
447    // Construction
448    ///////////////////////////////////////////////////////////////////////////
449
450    /** @hide */
451    public AudioService(Context context) {
452        mContext = context;
453        mContentResolver = context.getContentResolver();
454        mVoiceCapable = mContext.getResources().getBoolean(
455                com.android.internal.R.bool.config_voice_capable);
456
457        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
458        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
459
460        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
461        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
462
463       // Intialized volume
464        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
465            "ro.config.vc_call_vol_steps",
466           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
467
468        sSoundEffectVolumeDb = context.getResources().getInteger(
469                com.android.internal.R.integer.config_soundEffectVolumeDb);
470
471        mVolumePanel = new VolumePanel(context, this);
472        mMode = AudioSystem.MODE_NORMAL;
473        mForcedUseForComm = AudioSystem.FORCE_NONE;
474
475        createAudioSystemThread();
476
477        boolean cameraSoundForced = mContext.getResources().getBoolean(
478                com.android.internal.R.bool.config_camera_sound_forced);
479        mCameraSoundForced = new Boolean(cameraSoundForced);
480        sendMsg(mAudioHandler,
481                MSG_SET_FORCE_USE,
482                SENDMSG_QUEUE,
483                AudioSystem.FOR_SYSTEM,
484                cameraSoundForced ?
485                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
486                null,
487                0);
488
489        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
490                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
491                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
492        // The default safe volume index read here will be replaced by the actual value when
493        // the mcc is read by onConfigureSafeVolume()
494        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
495                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
496
497        readPersistedSettings();
498        mSettingsObserver = new SettingsObserver();
499        updateStreamVolumeAlias(false /*updateVolumes*/);
500        createStreamStates();
501
502        mMediaServerOk = true;
503
504        // Call setRingerModeInt() to apply correct mute
505        // state on streams affected by ringer mode.
506        mRingerModeMutedStreams = 0;
507        setRingerModeInt(getRingerMode(), false);
508
509        AudioSystem.setErrorCallback(mAudioSystemCallback);
510
511        // Register for device connection intent broadcasts.
512        IntentFilter intentFilter =
513                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
514        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
515        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
516        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
517        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
518        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
519        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
520        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
521        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
522
523        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
524        // Register a configuration change listener only if requested by system properties
525        // to monitor orientation changes (off by default)
526        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
527        if (mMonitorOrientation) {
528            Log.v(TAG, "monitoring device orientation");
529            // initialize orientation in AudioSystem
530            setOrientationForAudioSystem();
531        }
532
533        context.registerReceiver(mReceiver, intentFilter);
534
535        // Register for package removal intent broadcasts for media button receiver persistence
536        IntentFilter pkgFilter = new IntentFilter();
537        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
538        pkgFilter.addDataScheme("package");
539        context.registerReceiver(mReceiver, pkgFilter);
540
541        // Register for phone state monitoring
542        TelephonyManager tmgr = (TelephonyManager)
543                context.getSystemService(Context.TELEPHONY_SERVICE);
544        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
545
546        mUseMasterVolume = context.getResources().getBoolean(
547                com.android.internal.R.bool.config_useMasterVolume);
548        restoreMasterVolume();
549
550        mMasterVolumeRamp = context.getResources().getIntArray(
551                com.android.internal.R.array.config_masterVolumeRamp);
552
553        mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC],
554                MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
555        mHasRemotePlayback = false;
556        mMainRemoteIsActive = false;
557        postReevaluateRemote();
558    }
559
560    private void createAudioSystemThread() {
561        mAudioSystemThread = new AudioSystemThread();
562        mAudioSystemThread.start();
563        waitForAudioHandlerCreation();
564    }
565
566    /** Waits for the volume handler to be created by the other thread. */
567    private void waitForAudioHandlerCreation() {
568        synchronized(this) {
569            while (mAudioHandler == null) {
570                try {
571                    // Wait for mAudioHandler to be set by the other thread
572                    wait();
573                } catch (InterruptedException e) {
574                    Log.e(TAG, "Interrupted while waiting on volume handler.");
575                }
576            }
577        }
578    }
579
580    private void checkAllAliasStreamVolumes() {
581        int numStreamTypes = AudioSystem.getNumStreamTypes();
582        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
583            if (streamType != mStreamVolumeAlias[streamType]) {
584                mStreamStates[streamType].
585                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
586                                                  false /*lastAudible*/);
587                mStreamStates[streamType].
588                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
589                                                  true /*lastAudible*/);
590            }
591            // apply stream volume
592            if (mStreamStates[streamType].muteCount() == 0) {
593                mStreamStates[streamType].applyAllVolumes();
594            }
595        }
596    }
597
598    private void createStreamStates() {
599        int numStreamTypes = AudioSystem.getNumStreamTypes();
600        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
601
602        for (int i = 0; i < numStreamTypes; i++) {
603            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
604        }
605
606        checkAllAliasStreamVolumes();
607    }
608
609    private void dumpStreamStates(PrintWriter pw) {
610        pw.println("\nStream volumes (device: index)");
611        int numStreamTypes = AudioSystem.getNumStreamTypes();
612        for (int i = 0; i < numStreamTypes; i++) {
613            pw.println("- "+STREAM_NAMES[i]+":");
614            mStreamStates[i].dump(pw);
615            pw.println("");
616        }
617        pw.print("\n- mute affected streams = 0x");
618        pw.println(Integer.toHexString(mMuteAffectedStreams));
619    }
620
621
622    private void updateStreamVolumeAlias(boolean updateVolumes) {
623        int dtmfStreamAlias;
624        if (mVoiceCapable) {
625            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
626            dtmfStreamAlias = AudioSystem.STREAM_RING;
627        } else {
628            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
629            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
630        }
631        if (isInCommunication()) {
632            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
633        }
634        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
635        if (updateVolumes) {
636            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
637                                                                 false /*lastAudible*/);
638            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
639                                                                 true /*lastAudible*/);
640            sendMsg(mAudioHandler,
641                    MSG_SET_ALL_VOLUMES,
642                    SENDMSG_QUEUE,
643                    0,
644                    0,
645                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
646        }
647    }
648
649    private void readDockAudioSettings(ContentResolver cr)
650    {
651        mDockAudioMediaEnabled = Settings.Global.getInt(
652                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
653
654        if (mDockAudioMediaEnabled) {
655            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
656        } else {
657            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
658        }
659
660        sendMsg(mAudioHandler,
661                MSG_SET_FORCE_USE,
662                SENDMSG_QUEUE,
663                AudioSystem.FOR_DOCK,
664                mDockAudioMediaEnabled ?
665                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
666                null,
667                0);
668    }
669
670    private void readPersistedSettings() {
671        final ContentResolver cr = mContentResolver;
672
673        int ringerModeFromSettings =
674                Settings.Global.getInt(
675                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
676        int ringerMode = ringerModeFromSettings;
677        // sanity check in case the settings are restored from a device with incompatible
678        // ringer modes
679        if (!AudioManager.isValidRingerMode(ringerMode)) {
680            ringerMode = AudioManager.RINGER_MODE_NORMAL;
681        }
682        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
683            ringerMode = AudioManager.RINGER_MODE_SILENT;
684        }
685        if (ringerMode != ringerModeFromSettings) {
686            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
687        }
688        synchronized(mSettingsLock) {
689            mRingerMode = ringerMode;
690
691            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
692            // are still needed while setVibrateSetting() and getVibrateSetting() are being
693            // deprecated.
694            mVibrateSetting = getValueForVibrateSetting(0,
695                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
696                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
697                                                            : AudioManager.VIBRATE_SETTING_OFF);
698            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
699                                            AudioManager.VIBRATE_TYPE_RINGER,
700                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
701                                                            : AudioManager.VIBRATE_SETTING_OFF);
702
703            // make sure settings for ringer mode are consistent with device type: non voice capable
704            // devices (tablets) include media stream in silent mode whereas phones don't.
705            mRingerModeAffectedStreams = Settings.System.getIntForUser(cr,
706                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
707                    ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
708                     (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
709                     UserHandle.USER_CURRENT);
710
711            // ringtone, notification and system streams are always affected by ringer mode
712            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
713                                            (1 << AudioSystem.STREAM_NOTIFICATION)|
714                                            (1 << AudioSystem.STREAM_SYSTEM);
715
716            if (mVoiceCapable) {
717                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
718            } else {
719                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
720            }
721            synchronized (mCameraSoundForced) {
722                if (mCameraSoundForced) {
723                    mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
724                } else {
725                    mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
726                }
727            }
728
729            Settings.System.putIntForUser(cr,
730                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
731                    mRingerModeAffectedStreams,
732                    UserHandle.USER_CURRENT);
733
734            readDockAudioSettings(cr);
735        }
736
737        mMuteAffectedStreams = System.getIntForUser(cr,
738                System.MUTE_STREAMS_AFFECTED,
739                ((1 << AudioSystem.STREAM_MUSIC)|
740                 (1 << AudioSystem.STREAM_RING)|
741                 (1 << AudioSystem.STREAM_SYSTEM)),
742                 UserHandle.USER_CURRENT);
743
744        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
745                                                  0, UserHandle.USER_CURRENT) == 1;
746        AudioSystem.setMasterMute(masterMute);
747        broadcastMasterMuteStatus(masterMute);
748
749        // Each stream will read its own persisted settings
750
751        // Broadcast the sticky intent
752        broadcastRingerMode(ringerMode);
753
754        // Broadcast vibrate settings
755        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
756        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
757
758        // Restore the default media button receiver from the system settings
759        restoreMediaButtonReceiver();
760    }
761
762    private int rescaleIndex(int index, int srcStream, int dstStream) {
763        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
764    }
765
766    ///////////////////////////////////////////////////////////////////////////
767    // IPC methods
768    ///////////////////////////////////////////////////////////////////////////
769
770    /** @see AudioManager#adjustVolume(int, int) */
771    public void adjustVolume(int direction, int flags) {
772        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
773    }
774
775    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
776     *  on streamType: fixed to STREAM_MUSIC */
777    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
778        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
779        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
780            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
781        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
782            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0);
783        }
784    }
785
786    /** @see AudioManager#adjustVolume(int, int, int) */
787    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
788        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
789        int streamType;
790        if (mVolumeControlStream != -1) {
791            streamType = mVolumeControlStream;
792        } else {
793            streamType = getActiveStreamType(suggestedStreamType);
794        }
795
796        // Play sounds on STREAM_RING only and if lock screen is not on.
797        if ((streamType != STREAM_REMOTE_MUSIC) &&
798                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
799                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
800                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
801            flags &= ~AudioManager.FLAG_PLAY_SOUND;
802        }
803
804        if (streamType == STREAM_REMOTE_MUSIC) {
805            // don't play sounds for remote
806            flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
807            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
808            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
809        } else {
810            adjustStreamVolume(streamType, direction, flags);
811        }
812    }
813
814    /** @see AudioManager#adjustStreamVolume(int, int, int) */
815    public void adjustStreamVolume(int streamType, int direction, int flags) {
816        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
817
818        ensureValidDirection(direction);
819        ensureValidStreamType(streamType);
820
821        // use stream type alias here so that streams with same alias have the same behavior,
822        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
823        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
824        int streamTypeAlias = mStreamVolumeAlias[streamType];
825        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
826
827        final int device = getDeviceForStream(streamTypeAlias);
828
829        // get last audible index if stream is muted, current index otherwise
830        int aliasIndex = streamState.getIndex(device,
831                        (streamState.muteCount() != 0) /* lastAudible */);
832        boolean adjustVolume = true;
833
834        int step;
835        int index;
836        int oldIndex;
837
838        // reset any pending volume command
839        synchronized (mSafeMediaVolumeState) {
840            mPendingVolumeCommand = null;
841        }
842
843        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
844        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
845               ((device & mFixedVolumeDevices) != 0)) {
846            flags |= AudioManager.FLAG_FIXED_VOLUME;
847
848            // Always toggle between max safe volume and 0 for fixed volume devices where safe
849            // volume is enforced, and max and 0 for the others.
850            // This is simulated by stepping by the full allowed volume range
851            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
852                    (device & mSafeMediaVolumeDevices) != 0) {
853                step = mSafeMediaVolumeIndex;
854            } else {
855                step = streamState.getMaxIndex();
856            }
857            if (aliasIndex != 0) {
858                aliasIndex = step;
859            }
860        } else {
861            // convert one UI step (+/-1) into a number of internal units on the stream alias
862            step = rescaleIndex(10, streamType, streamTypeAlias);
863        }
864
865        if ((direction == AudioManager.ADJUST_RAISE) &&
866                !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
867            index = mStreamStates[streamType].getIndex(device,
868                                                 (streamState.muteCount() != 0)  /* lastAudible */);
869            oldIndex = index;
870            mVolumePanel.postDisplaySafeVolumeWarning(flags);
871        } else {
872            // If either the client forces allowing ringer modes for this adjustment,
873            // or the stream type is one that is affected by ringer modes
874            if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
875                    (streamTypeAlias == getMasterStreamType())) {
876                int ringerMode = getRingerMode();
877                // do not vibrate if already in vibrate mode
878                if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
879                    flags &= ~AudioManager.FLAG_VIBRATE;
880                }
881                // Check if the ringer mode changes with this volume adjustment. If
882                // it does, it will handle adjusting the volume, so we won't below
883                adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
884                if ((streamTypeAlias == getMasterStreamType()) &&
885                        (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
886                    streamState.setLastAudibleIndex(0, device);
887                }
888            }
889
890            // If stream is muted, adjust last audible index only
891            oldIndex = mStreamStates[streamType].getIndex(device,
892                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
893
894            if (streamState.muteCount() != 0) {
895                if (adjustVolume) {
896                    // Post a persist volume msg
897                    // no need to persist volume on all streams sharing the same alias
898                    streamState.adjustLastAudibleIndex(direction * step, device);
899                    sendMsg(mAudioHandler,
900                            MSG_PERSIST_VOLUME,
901                            SENDMSG_QUEUE,
902                            PERSIST_LAST_AUDIBLE,
903                            device,
904                            streamState,
905                            PERSIST_DELAY);
906                }
907                index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
908            } else {
909                if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
910                    // Post message to set system volume (it in turn will post a message
911                    // to persist). Do not change volume if stream is muted.
912                    sendMsg(mAudioHandler,
913                            MSG_SET_DEVICE_VOLUME,
914                            SENDMSG_QUEUE,
915                            device,
916                            0,
917                            streamState,
918                            0);
919                }
920                index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
921            }
922        }
923        sendVolumeUpdate(streamType, oldIndex, index, flags);
924    }
925
926    /** @see AudioManager#adjustMasterVolume(int) */
927    public void adjustMasterVolume(int steps, int flags) {
928        ensureValidSteps(steps);
929        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
930        int delta = 0;
931        int numSteps = Math.abs(steps);
932        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
933        for (int i = 0; i < numSteps; ++i) {
934            delta = findVolumeDelta(direction, volume);
935            volume += delta;
936        }
937
938        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
939        setMasterVolume(volume, flags);
940    }
941
942    // StreamVolumeCommand contains the information needed to defer the process of
943    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
944    class StreamVolumeCommand {
945        public final int mStreamType;
946        public final int mIndex;
947        public final int mFlags;
948        public final int mDevice;
949
950        StreamVolumeCommand(int streamType, int index, int flags, int device) {
951            mStreamType = streamType;
952            mIndex = index;
953            mFlags = flags;
954            mDevice = device;
955        }
956    };
957
958    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
959        // setting volume on master stream type also controls silent mode
960        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
961                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
962            int newRingerMode;
963            if (index == 0) {
964                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
965                                              : AudioManager.RINGER_MODE_SILENT;
966                setStreamVolumeInt(mStreamVolumeAlias[streamType],
967                                   index,
968                                   device,
969                                   false,
970                                   true);
971            } else {
972                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
973            }
974            setRingerMode(newRingerMode);
975        }
976
977        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
978    }
979
980    /** @see AudioManager#setStreamVolume(int, int, int) */
981    public void setStreamVolume(int streamType, int index, int flags) {
982        ensureValidStreamType(streamType);
983        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
984
985        final int device = getDeviceForStream(streamType);
986        int oldIndex;
987
988        synchronized (mSafeMediaVolumeState) {
989            // reset any pending volume command
990            mPendingVolumeCommand = null;
991
992            // get last audible index if stream is muted, current index otherwise
993            oldIndex = streamState.getIndex(device,
994                                            (streamState.muteCount() != 0) /* lastAudible */);
995
996            index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
997
998            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
999            if ((mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1000                    ((device & mFixedVolumeDevices) != 0)) {
1001                flags |= AudioManager.FLAG_FIXED_VOLUME;
1002
1003                // volume is either 0 or max allowed for fixed volume devices
1004                if (index != 0) {
1005                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1006                            (device & mSafeMediaVolumeDevices) != 0) {
1007                        index = mSafeMediaVolumeIndex;
1008                    } else {
1009                        index = streamState.getMaxIndex();
1010                    }
1011                }
1012            }
1013
1014            if (!checkSafeMediaVolume(mStreamVolumeAlias[streamType], index, device)) {
1015                mVolumePanel.postDisplaySafeVolumeWarning(flags);
1016                mPendingVolumeCommand = new StreamVolumeCommand(
1017                                                    streamType, index, flags, device);
1018            } else {
1019                onSetStreamVolume(streamType, index, flags, device);
1020                // get last audible index if stream is muted, current index otherwise
1021                index = mStreamStates[streamType].getIndex(device,
1022                                    (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
1023            }
1024        }
1025        sendVolumeUpdate(streamType, oldIndex, index, flags);
1026    }
1027
1028    /** @see AudioManager#forceVolumeControlStream(int) */
1029    public void forceVolumeControlStream(int streamType, IBinder cb) {
1030        synchronized(mForceControlStreamLock) {
1031            mVolumeControlStream = streamType;
1032            if (mVolumeControlStream == -1) {
1033                if (mForceControlStreamClient != null) {
1034                    mForceControlStreamClient.release();
1035                    mForceControlStreamClient = null;
1036                }
1037            } else {
1038                mForceControlStreamClient = new ForceControlStreamClient(cb);
1039            }
1040        }
1041    }
1042
1043    private class ForceControlStreamClient implements IBinder.DeathRecipient {
1044        private IBinder mCb; // To be notified of client's death
1045
1046        ForceControlStreamClient(IBinder cb) {
1047            if (cb != null) {
1048                try {
1049                    cb.linkToDeath(this, 0);
1050                } catch (RemoteException e) {
1051                    // Client has died!
1052                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1053                    cb = null;
1054                }
1055            }
1056            mCb = cb;
1057        }
1058
1059        public void binderDied() {
1060            synchronized(mForceControlStreamLock) {
1061                Log.w(TAG, "SCO client died");
1062                if (mForceControlStreamClient != this) {
1063                    Log.w(TAG, "unregistered control stream client died");
1064                } else {
1065                    mForceControlStreamClient = null;
1066                    mVolumeControlStream = -1;
1067                }
1068            }
1069        }
1070
1071        public void release() {
1072            if (mCb != null) {
1073                mCb.unlinkToDeath(this, 0);
1074                mCb = null;
1075            }
1076        }
1077    }
1078
1079    private int findVolumeDelta(int direction, int volume) {
1080        int delta = 0;
1081        if (direction == AudioManager.ADJUST_RAISE) {
1082            if (volume == MAX_MASTER_VOLUME) {
1083                return 0;
1084            }
1085            // This is the default value if we make it to the end
1086            delta = mMasterVolumeRamp[1];
1087            // If we're raising the volume move down the ramp array until we
1088            // find the volume we're above and use that groups delta.
1089            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1090                if (volume >= mMasterVolumeRamp[i - 1]) {
1091                    delta = mMasterVolumeRamp[i];
1092                    break;
1093                }
1094            }
1095        } else if (direction == AudioManager.ADJUST_LOWER){
1096            if (volume == 0) {
1097                return 0;
1098            }
1099            int length = mMasterVolumeRamp.length;
1100            // This is the default value if we make it to the end
1101            delta = -mMasterVolumeRamp[length - 1];
1102            // If we're lowering the volume move up the ramp array until we
1103            // find the volume we're below and use the group below it's delta
1104            for (int i = 2; i < length; i += 2) {
1105                if (volume <= mMasterVolumeRamp[i]) {
1106                    delta = -mMasterVolumeRamp[i - 1];
1107                    break;
1108                }
1109            }
1110        }
1111        return delta;
1112    }
1113
1114    private void sendBroadcastToAll(Intent intent) {
1115        final long ident = Binder.clearCallingIdentity();
1116        try {
1117            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1118        } finally {
1119            Binder.restoreCallingIdentity(ident);
1120        }
1121    }
1122
1123    private void sendStickyBroadcastToAll(Intent intent) {
1124        final long ident = Binder.clearCallingIdentity();
1125        try {
1126            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1127        } finally {
1128            Binder.restoreCallingIdentity(ident);
1129        }
1130    }
1131
1132    // UI update and Broadcast Intent
1133    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1134        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
1135            streamType = AudioSystem.STREAM_NOTIFICATION;
1136        }
1137
1138        mVolumePanel.postVolumeChanged(streamType, flags);
1139
1140        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1141            oldIndex = (oldIndex + 5) / 10;
1142            index = (index + 5) / 10;
1143            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1144            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1145            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1146            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1147            sendBroadcastToAll(intent);
1148        }
1149    }
1150
1151    // UI update and Broadcast Intent
1152    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
1153        mVolumePanel.postMasterVolumeChanged(flags);
1154
1155        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1156        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1157        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
1158        sendBroadcastToAll(intent);
1159    }
1160
1161    // UI update and Broadcast Intent
1162    private void sendMasterMuteUpdate(boolean muted, int flags) {
1163        mVolumePanel.postMasterMuteChanged(flags);
1164        broadcastMasterMuteStatus(muted);
1165    }
1166
1167    private void broadcastMasterMuteStatus(boolean muted) {
1168        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1169        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
1170        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1171                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1172        sendStickyBroadcastToAll(intent);
1173    }
1174
1175    /**
1176     * Sets the stream state's index, and posts a message to set system volume.
1177     * This will not call out to the UI. Assumes a valid stream type.
1178     *
1179     * @param streamType Type of the stream
1180     * @param index Desired volume index of the stream
1181     * @param device the device whose volume must be changed
1182     * @param force If true, set the volume even if the desired volume is same
1183     * as the current volume.
1184     * @param lastAudible If true, stores new index as last audible one
1185     */
1186    private void setStreamVolumeInt(int streamType,
1187                                    int index,
1188                                    int device,
1189                                    boolean force,
1190                                    boolean lastAudible) {
1191        VolumeStreamState streamState = mStreamStates[streamType];
1192
1193        // If stream is muted, set last audible index only
1194        if (streamState.muteCount() != 0) {
1195            // Do not allow last audible index to be 0
1196            if (index != 0) {
1197                streamState.setLastAudibleIndex(index, device);
1198                // Post a persist volume msg
1199                sendMsg(mAudioHandler,
1200                        MSG_PERSIST_VOLUME,
1201                        SENDMSG_QUEUE,
1202                        PERSIST_LAST_AUDIBLE,
1203                        device,
1204                        streamState,
1205                        PERSIST_DELAY);
1206            }
1207        } else {
1208            if (streamState.setIndex(index, device, lastAudible) || force) {
1209                // Post message to set system volume (it in turn will post a message
1210                // to persist).
1211                sendMsg(mAudioHandler,
1212                        MSG_SET_DEVICE_VOLUME,
1213                        SENDMSG_QUEUE,
1214                        device,
1215                        0,
1216                        streamState,
1217                        0);
1218            }
1219        }
1220    }
1221
1222    /** @see AudioManager#setStreamSolo(int, boolean) */
1223    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
1224        for (int stream = 0; stream < mStreamStates.length; stream++) {
1225            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
1226            // Bring back last audible volume
1227            mStreamStates[stream].mute(cb, state);
1228         }
1229    }
1230
1231    /** @see AudioManager#setStreamMute(int, boolean) */
1232    public void setStreamMute(int streamType, boolean state, IBinder cb) {
1233        if (isStreamAffectedByMute(streamType)) {
1234            mStreamStates[streamType].mute(cb, state);
1235        }
1236    }
1237
1238    /** get stream mute state. */
1239    public boolean isStreamMute(int streamType) {
1240        return (mStreamStates[streamType].muteCount() != 0);
1241    }
1242
1243    /** @see AudioManager#setMasterMute(boolean, IBinder) */
1244    public void setMasterMute(boolean state, int flags, IBinder cb) {
1245        if (state != AudioSystem.getMasterMute()) {
1246            AudioSystem.setMasterMute(state);
1247            // Post a persist master volume msg
1248            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
1249                    : 0, 0, null, PERSIST_DELAY);
1250            sendMasterMuteUpdate(state, flags);
1251        }
1252    }
1253
1254    /** get master mute state. */
1255    public boolean isMasterMute() {
1256        return AudioSystem.getMasterMute();
1257    }
1258
1259    /** @see AudioManager#getStreamVolume(int) */
1260    public int getStreamVolume(int streamType) {
1261        ensureValidStreamType(streamType);
1262        int device = getDeviceForStream(streamType);
1263        int index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
1264
1265        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1266                (device & mFixedVolumeDevices) != 0) {
1267            index = mStreamStates[streamType].getMaxIndex();
1268        }
1269        return (index + 5) / 10;
1270    }
1271
1272    public int getMasterVolume() {
1273        if (isMasterMute()) return 0;
1274        return getLastAudibleMasterVolume();
1275    }
1276
1277    public void setMasterVolume(int volume, int flags) {
1278        if (volume < 0) {
1279            volume = 0;
1280        } else if (volume > MAX_MASTER_VOLUME) {
1281            volume = MAX_MASTER_VOLUME;
1282        }
1283        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1284    }
1285
1286    private void doSetMasterVolume(float volume, int flags) {
1287        // don't allow changing master volume when muted
1288        if (!AudioSystem.getMasterMute()) {
1289            int oldVolume = getMasterVolume();
1290            AudioSystem.setMasterVolume(volume);
1291
1292            int newVolume = getMasterVolume();
1293            if (newVolume != oldVolume) {
1294                // Post a persist master volume msg
1295                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1296                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
1297            }
1298            // Send the volume update regardless whether there was a change.
1299            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
1300        }
1301    }
1302
1303    /** @see AudioManager#getStreamMaxVolume(int) */
1304    public int getStreamMaxVolume(int streamType) {
1305        ensureValidStreamType(streamType);
1306        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
1307    }
1308
1309    public int getMasterMaxVolume() {
1310        return MAX_MASTER_VOLUME;
1311    }
1312
1313    /** Get last audible volume before stream was muted. */
1314    public int getLastAudibleStreamVolume(int streamType) {
1315        ensureValidStreamType(streamType);
1316        int device = getDeviceForStream(streamType);
1317        return (mStreamStates[streamType].getIndex(device, true  /* lastAudible */) + 5) / 10;
1318    }
1319
1320    /** Get last audible master volume before it was muted. */
1321    public int getLastAudibleMasterVolume() {
1322        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1323    }
1324
1325    /** @see AudioManager#getMasterStreamType(int) */
1326    public int getMasterStreamType() {
1327        if (mVoiceCapable) {
1328            return AudioSystem.STREAM_RING;
1329        } else {
1330            return AudioSystem.STREAM_MUSIC;
1331        }
1332    }
1333
1334    /** @see AudioManager#getRingerMode() */
1335    public int getRingerMode() {
1336        synchronized(mSettingsLock) {
1337            return mRingerMode;
1338        }
1339    }
1340
1341    private void ensureValidRingerMode(int ringerMode) {
1342        if (!AudioManager.isValidRingerMode(ringerMode)) {
1343            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1344        }
1345    }
1346
1347    /** @see AudioManager#setRingerMode(int) */
1348    public void setRingerMode(int ringerMode) {
1349        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1350            ringerMode = AudioManager.RINGER_MODE_SILENT;
1351        }
1352        if (ringerMode != getRingerMode()) {
1353            setRingerModeInt(ringerMode, true);
1354            // Send sticky broadcast
1355            broadcastRingerMode(ringerMode);
1356        }
1357    }
1358
1359    private void setRingerModeInt(int ringerMode, boolean persist) {
1360        synchronized(mSettingsLock) {
1361            mRingerMode = ringerMode;
1362        }
1363
1364        // Mute stream if not previously muted by ringer mode and ringer mode
1365        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1366        // Unmute stream if previously muted by ringer mode and ringer mode
1367        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1368        int numStreamTypes = AudioSystem.getNumStreamTypes();
1369        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1370            if (isStreamMutedByRingerMode(streamType)) {
1371                if (!isStreamAffectedByRingerMode(streamType) ||
1372                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1373                    // ring and notifications volume should never be 0 when not silenced
1374                    // on voice capable devices
1375                    if (mVoiceCapable &&
1376                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1377                        synchronized (mStreamStates[streamType]) {
1378                            Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
1379                            Iterator i = set.iterator();
1380                            while (i.hasNext()) {
1381                                Map.Entry entry = (Map.Entry)i.next();
1382                                if ((Integer)entry.getValue() == 0) {
1383                                    entry.setValue(10);
1384                                }
1385                            }
1386                        }
1387                    }
1388                    mStreamStates[streamType].mute(null, false);
1389                    mRingerModeMutedStreams &= ~(1 << streamType);
1390                }
1391            } else {
1392                if (isStreamAffectedByRingerMode(streamType) &&
1393                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
1394                   mStreamStates[streamType].mute(null, true);
1395                   mRingerModeMutedStreams |= (1 << streamType);
1396               }
1397            }
1398        }
1399
1400        // Post a persist ringer mode msg
1401        if (persist) {
1402            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
1403                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1404        }
1405    }
1406
1407    private void restoreMasterVolume() {
1408        if (mUseMasterVolume) {
1409            float volume = Settings.System.getFloatForUser(mContentResolver,
1410                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
1411            if (volume >= 0.0f) {
1412                AudioSystem.setMasterVolume(volume);
1413            }
1414        }
1415    }
1416
1417    /** @see AudioManager#shouldVibrate(int) */
1418    public boolean shouldVibrate(int vibrateType) {
1419        if (!mHasVibrator) return false;
1420
1421        switch (getVibrateSetting(vibrateType)) {
1422
1423            case AudioManager.VIBRATE_SETTING_ON:
1424                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
1425
1426            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1427                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
1428
1429            case AudioManager.VIBRATE_SETTING_OFF:
1430                // return false, even for incoming calls
1431                return false;
1432
1433            default:
1434                return false;
1435        }
1436    }
1437
1438    /** @see AudioManager#getVibrateSetting(int) */
1439    public int getVibrateSetting(int vibrateType) {
1440        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
1441        return (mVibrateSetting >> (vibrateType * 2)) & 3;
1442    }
1443
1444    /** @see AudioManager#setVibrateSetting(int, int) */
1445    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1446
1447        if (!mHasVibrator) return;
1448
1449        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1450
1451        // Broadcast change
1452        broadcastVibrateSetting(vibrateType);
1453
1454    }
1455
1456    /**
1457     * @see #setVibrateSetting(int, int)
1458     */
1459    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1460            int vibrateSetting) {
1461
1462        // First clear the existing setting. Each vibrate type has two bits in
1463        // the value. Note '3' is '11' in binary.
1464        existingValue &= ~(3 << (vibrateType * 2));
1465
1466        // Set into the old value
1467        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1468
1469        return existingValue;
1470    }
1471
1472    private class SetModeDeathHandler implements IBinder.DeathRecipient {
1473        private IBinder mCb; // To be notified of client's death
1474        private int mPid;
1475        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1476
1477        SetModeDeathHandler(IBinder cb, int pid) {
1478            mCb = cb;
1479            mPid = pid;
1480        }
1481
1482        public void binderDied() {
1483            int newModeOwnerPid = 0;
1484            synchronized(mSetModeDeathHandlers) {
1485                Log.w(TAG, "setMode() client died");
1486                int index = mSetModeDeathHandlers.indexOf(this);
1487                if (index < 0) {
1488                    Log.w(TAG, "unregistered setMode() client died");
1489                } else {
1490                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
1491                }
1492            }
1493            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1494            // SCO connections not started by the application changing the mode
1495            if (newModeOwnerPid != 0) {
1496                 disconnectBluetoothSco(newModeOwnerPid);
1497            }
1498        }
1499
1500        public int getPid() {
1501            return mPid;
1502        }
1503
1504        public void setMode(int mode) {
1505            mMode = mode;
1506        }
1507
1508        public int getMode() {
1509            return mMode;
1510        }
1511
1512        public IBinder getBinder() {
1513            return mCb;
1514        }
1515    }
1516
1517    /** @see AudioManager#setMode(int) */
1518    public void setMode(int mode, IBinder cb) {
1519        if (!checkAudioSettingsPermission("setMode()")) {
1520            return;
1521        }
1522
1523        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1524            return;
1525        }
1526
1527        int newModeOwnerPid = 0;
1528        synchronized(mSetModeDeathHandlers) {
1529            if (mode == AudioSystem.MODE_CURRENT) {
1530                mode = mMode;
1531            }
1532            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
1533        }
1534        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1535        // SCO connections not started by the application changing the mode
1536        if (newModeOwnerPid != 0) {
1537             disconnectBluetoothSco(newModeOwnerPid);
1538        }
1539    }
1540
1541    // must be called synchronized on mSetModeDeathHandlers
1542    // setModeInt() returns a valid PID if the audio mode was successfully set to
1543    // any mode other than NORMAL.
1544    int setModeInt(int mode, IBinder cb, int pid) {
1545        int newModeOwnerPid = 0;
1546        if (cb == null) {
1547            Log.e(TAG, "setModeInt() called with null binder");
1548            return newModeOwnerPid;
1549        }
1550
1551        SetModeDeathHandler hdlr = null;
1552        Iterator iter = mSetModeDeathHandlers.iterator();
1553        while (iter.hasNext()) {
1554            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1555            if (h.getPid() == pid) {
1556                hdlr = h;
1557                // Remove from client list so that it is re-inserted at top of list
1558                iter.remove();
1559                hdlr.getBinder().unlinkToDeath(hdlr, 0);
1560                break;
1561            }
1562        }
1563        int status = AudioSystem.AUDIO_STATUS_OK;
1564        do {
1565            if (mode == AudioSystem.MODE_NORMAL) {
1566                // get new mode from client at top the list if any
1567                if (!mSetModeDeathHandlers.isEmpty()) {
1568                    hdlr = mSetModeDeathHandlers.get(0);
1569                    cb = hdlr.getBinder();
1570                    mode = hdlr.getMode();
1571                }
1572            } else {
1573                if (hdlr == null) {
1574                    hdlr = new SetModeDeathHandler(cb, pid);
1575                }
1576                // Register for client death notification
1577                try {
1578                    cb.linkToDeath(hdlr, 0);
1579                } catch (RemoteException e) {
1580                    // Client has died!
1581                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1582                }
1583
1584                // Last client to call setMode() is always at top of client list
1585                // as required by SetModeDeathHandler.binderDied()
1586                mSetModeDeathHandlers.add(0, hdlr);
1587                hdlr.setMode(mode);
1588            }
1589
1590            if (mode != mMode) {
1591                status = AudioSystem.setPhoneState(mode);
1592                if (status == AudioSystem.AUDIO_STATUS_OK) {
1593                    mMode = mode;
1594                } else {
1595                    if (hdlr != null) {
1596                        mSetModeDeathHandlers.remove(hdlr);
1597                        cb.unlinkToDeath(hdlr, 0);
1598                    }
1599                    // force reading new top of mSetModeDeathHandlers stack
1600                    mode = AudioSystem.MODE_NORMAL;
1601                }
1602            } else {
1603                status = AudioSystem.AUDIO_STATUS_OK;
1604            }
1605        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1606
1607        if (status == AudioSystem.AUDIO_STATUS_OK) {
1608            if (mode != AudioSystem.MODE_NORMAL) {
1609                if (mSetModeDeathHandlers.isEmpty()) {
1610                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1611                } else {
1612                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1613                }
1614            }
1615            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
1616            if (streamType == STREAM_REMOTE_MUSIC) {
1617                // here handle remote media playback the same way as local playback
1618                streamType = AudioManager.STREAM_MUSIC;
1619            }
1620            int device = getDeviceForStream(streamType);
1621            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false);
1622            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false);
1623
1624            updateStreamVolumeAlias(true /*updateVolumes*/);
1625        }
1626        return newModeOwnerPid;
1627    }
1628
1629    /** @see AudioManager#getMode() */
1630    public int getMode() {
1631        return mMode;
1632    }
1633
1634    /** @see AudioManager#playSoundEffect(int) */
1635    public void playSoundEffect(int effectType) {
1636        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
1637                effectType, -1, null, 0);
1638    }
1639
1640    /** @see AudioManager#playSoundEffect(int, float) */
1641    public void playSoundEffectVolume(int effectType, float volume) {
1642        loadSoundEffects();
1643        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
1644                effectType, (int) (volume * 1000), null, 0);
1645    }
1646
1647    /**
1648     * Loads samples into the soundpool.
1649     * This method must be called at first when sound effects are enabled
1650     */
1651    public boolean loadSoundEffects() {
1652        int status;
1653
1654        synchronized (mSoundEffectsLock) {
1655            if (!mBootCompleted) {
1656                Log.w(TAG, "loadSoundEffects() called before boot complete");
1657                return false;
1658            }
1659
1660            if (mSoundPool != null) {
1661                return true;
1662            }
1663            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
1664
1665            try {
1666                mSoundPoolCallBack = null;
1667                mSoundPoolListenerThread = new SoundPoolListenerThread();
1668                mSoundPoolListenerThread.start();
1669                // Wait for mSoundPoolCallBack to be set by the other thread
1670                mSoundEffectsLock.wait();
1671            } catch (InterruptedException e) {
1672                Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
1673            }
1674
1675            if (mSoundPoolCallBack == null) {
1676                Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread");
1677                if (mSoundPoolLooper != null) {
1678                    mSoundPoolLooper.quit();
1679                    mSoundPoolLooper = null;
1680                }
1681                mSoundPoolListenerThread = null;
1682                mSoundPool.release();
1683                mSoundPool = null;
1684                return false;
1685            }
1686            /*
1687             * poolId table: The value -1 in this table indicates that corresponding
1688             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
1689             * Once loaded, the value in poolId is the sample ID and the same
1690             * sample can be reused for another effect using the same file.
1691             */
1692            int[] poolId = new int[SOUND_EFFECT_FILES.length];
1693            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
1694                poolId[fileIdx] = -1;
1695            }
1696            /*
1697             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
1698             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
1699             * this indicates we have a valid sample loaded for this effect.
1700             */
1701
1702            int lastSample = 0;
1703            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
1704                // Do not load sample if this effect uses the MediaPlayer
1705                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
1706                    continue;
1707                }
1708                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
1709                    String filePath = Environment.getRootDirectory()
1710                            + SOUND_EFFECTS_PATH
1711                            + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
1712                    int sampleId = mSoundPool.load(filePath, 0);
1713                    if (sampleId <= 0) {
1714                        Log.w(TAG, "Soundpool could not load file: "+filePath);
1715                    } else {
1716                        SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
1717                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
1718                        lastSample = sampleId;
1719                    }
1720                } else {
1721                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
1722                }
1723            }
1724            // wait for all samples to be loaded
1725            if (lastSample != 0) {
1726                mSoundPoolCallBack.setLastSample(lastSample);
1727
1728                try {
1729                    mSoundEffectsLock.wait();
1730                    status = mSoundPoolCallBack.status();
1731                } catch (java.lang.InterruptedException e) {
1732                    Log.w(TAG, "Interrupted while waiting sound pool callback.");
1733                    status = -1;
1734                }
1735            } else {
1736                status = -1;
1737            }
1738
1739            if (mSoundPoolLooper != null) {
1740                mSoundPoolLooper.quit();
1741                mSoundPoolLooper = null;
1742            }
1743            mSoundPoolListenerThread = null;
1744            if (status != 0) {
1745                Log.w(TAG,
1746                        "loadSoundEffects(), Error "
1747                                + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1)
1748                                + " while loading samples");
1749                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
1750                    if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
1751                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
1752                    }
1753                }
1754
1755                mSoundPool.release();
1756                mSoundPool = null;
1757            }
1758        }
1759        return (status == 0);
1760    }
1761
1762    /**
1763     *  Unloads samples from the sound pool.
1764     *  This method can be called to free some memory when
1765     *  sound effects are disabled.
1766     */
1767    public void unloadSoundEffects() {
1768        synchronized (mSoundEffectsLock) {
1769            if (mSoundPool == null) {
1770                return;
1771            }
1772
1773            mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS);
1774            mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT);
1775
1776            int[] poolId = new int[SOUND_EFFECT_FILES.length];
1777            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
1778                poolId[fileIdx] = 0;
1779            }
1780
1781            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
1782                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
1783                    continue;
1784                }
1785                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
1786                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
1787                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
1788                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
1789                }
1790            }
1791            mSoundPool.release();
1792            mSoundPool = null;
1793        }
1794    }
1795
1796    class SoundPoolListenerThread extends Thread {
1797        public SoundPoolListenerThread() {
1798            super("SoundPoolListenerThread");
1799        }
1800
1801        @Override
1802        public void run() {
1803
1804            Looper.prepare();
1805            mSoundPoolLooper = Looper.myLooper();
1806
1807            synchronized (mSoundEffectsLock) {
1808                if (mSoundPool != null) {
1809                    mSoundPoolCallBack = new SoundPoolCallback();
1810                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1811                }
1812                mSoundEffectsLock.notify();
1813            }
1814            Looper.loop();
1815        }
1816    }
1817
1818    private final class SoundPoolCallback implements
1819            android.media.SoundPool.OnLoadCompleteListener {
1820
1821        int mStatus;
1822        int mLastSample;
1823
1824        public int status() {
1825            return mStatus;
1826        }
1827
1828        public void setLastSample(int sample) {
1829            mLastSample = sample;
1830        }
1831
1832        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1833            synchronized (mSoundEffectsLock) {
1834                if (status != 0) {
1835                    mStatus = status;
1836                }
1837                if (sampleId == mLastSample) {
1838                    mSoundEffectsLock.notify();
1839                }
1840            }
1841        }
1842    }
1843
1844    /** @see AudioManager#reloadAudioSettings() */
1845    public void reloadAudioSettings() {
1846        readAudioSettings(false /*userSwitch*/);
1847    }
1848
1849    private void readAudioSettings(boolean userSwitch) {
1850        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
1851        readPersistedSettings();
1852
1853        // restore volume settings
1854        int numStreamTypes = AudioSystem.getNumStreamTypes();
1855        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1856            VolumeStreamState streamState = mStreamStates[streamType];
1857
1858            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1859                continue;
1860            }
1861
1862            synchronized (streamState) {
1863                streamState.readSettings();
1864
1865                // unmute stream that was muted but is not affect by mute anymore
1866                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType) &&
1867                        !isStreamMutedByRingerMode(streamType)) {
1868                    int size = streamState.mDeathHandlers.size();
1869                    for (int i = 0; i < size; i++) {
1870                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
1871                        streamState.mDeathHandlers.get(i).mute(false);
1872                    }
1873                }
1874            }
1875        }
1876
1877        // apply new ringer mode before checking volume for alias streams so that streams
1878        // muted by ringer mode have the correct volume
1879        setRingerModeInt(getRingerMode(), false);
1880
1881        checkAllAliasStreamVolumes();
1882
1883        synchronized (mSafeMediaVolumeState) {
1884            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
1885                enforceSafeMediaVolume();
1886            }
1887        }
1888    }
1889
1890    /** @see AudioManager#setSpeakerphoneOn() */
1891    public void setSpeakerphoneOn(boolean on){
1892        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1893            return;
1894        }
1895        mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
1896
1897        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1898                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1899    }
1900
1901    /** @see AudioManager#isSpeakerphoneOn() */
1902    public boolean isSpeakerphoneOn() {
1903        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
1904    }
1905
1906    /** @see AudioManager#setBluetoothScoOn() */
1907    public void setBluetoothScoOn(boolean on){
1908        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
1909            return;
1910        }
1911        mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
1912
1913        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1914                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1915        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1916                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
1917    }
1918
1919    /** @see AudioManager#isBluetoothScoOn() */
1920    public boolean isBluetoothScoOn() {
1921        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
1922    }
1923
1924    /** @see AudioManager#setBluetoothA2dpOn() */
1925    public void setBluetoothA2dpOn(boolean on) {
1926        synchronized (mBluetoothA2dpEnabledLock) {
1927            mBluetoothA2dpEnabled = on;
1928            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
1929                    AudioSystem.FOR_MEDIA,
1930                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
1931                    null, 0);
1932        }
1933    }
1934
1935    /** @see AudioManager#isBluetoothA2dpOn() */
1936    public boolean isBluetoothA2dpOn() {
1937        synchronized (mBluetoothA2dpEnabledLock) {
1938            return mBluetoothA2dpEnabled;
1939        }
1940    }
1941
1942    /** @see AudioManager#startBluetoothSco() */
1943    public void startBluetoothSco(IBinder cb){
1944        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
1945                !mBootCompleted) {
1946            return;
1947        }
1948        ScoClient client = getScoClient(cb, true);
1949        client.incCount();
1950    }
1951
1952    /** @see AudioManager#stopBluetoothSco() */
1953    public void stopBluetoothSco(IBinder cb){
1954        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
1955                !mBootCompleted) {
1956            return;
1957        }
1958        ScoClient client = getScoClient(cb, false);
1959        if (client != null) {
1960            client.decCount();
1961        }
1962    }
1963
1964
1965    private class ScoClient implements IBinder.DeathRecipient {
1966        private IBinder mCb; // To be notified of client's death
1967        private int mCreatorPid;
1968        private int mStartcount; // number of SCO connections started by this client
1969
1970        ScoClient(IBinder cb) {
1971            mCb = cb;
1972            mCreatorPid = Binder.getCallingPid();
1973            mStartcount = 0;
1974        }
1975
1976        public void binderDied() {
1977            synchronized(mScoClients) {
1978                Log.w(TAG, "SCO client died");
1979                int index = mScoClients.indexOf(this);
1980                if (index < 0) {
1981                    Log.w(TAG, "unregistered SCO client died");
1982                } else {
1983                    clearCount(true);
1984                    mScoClients.remove(this);
1985                }
1986            }
1987        }
1988
1989        public void incCount() {
1990            synchronized(mScoClients) {
1991                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
1992                if (mStartcount == 0) {
1993                    try {
1994                        mCb.linkToDeath(this, 0);
1995                    } catch (RemoteException e) {
1996                        // client has already died!
1997                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
1998                    }
1999                }
2000                mStartcount++;
2001            }
2002        }
2003
2004        public void decCount() {
2005            synchronized(mScoClients) {
2006                if (mStartcount == 0) {
2007                    Log.w(TAG, "ScoClient.decCount() already 0");
2008                } else {
2009                    mStartcount--;
2010                    if (mStartcount == 0) {
2011                        try {
2012                            mCb.unlinkToDeath(this, 0);
2013                        } catch (NoSuchElementException e) {
2014                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2015                        }
2016                    }
2017                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
2018                }
2019            }
2020        }
2021
2022        public void clearCount(boolean stopSco) {
2023            synchronized(mScoClients) {
2024                if (mStartcount != 0) {
2025                    try {
2026                        mCb.unlinkToDeath(this, 0);
2027                    } catch (NoSuchElementException e) {
2028                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2029                    }
2030                }
2031                mStartcount = 0;
2032                if (stopSco) {
2033                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
2034                }
2035            }
2036        }
2037
2038        public int getCount() {
2039            return mStartcount;
2040        }
2041
2042        public IBinder getBinder() {
2043            return mCb;
2044        }
2045
2046        public int getPid() {
2047            return mCreatorPid;
2048        }
2049
2050        public int totalCount() {
2051            synchronized(mScoClients) {
2052                int count = 0;
2053                int size = mScoClients.size();
2054                for (int i = 0; i < size; i++) {
2055                    count += mScoClients.get(i).getCount();
2056                }
2057                return count;
2058            }
2059        }
2060
2061        private void requestScoState(int state) {
2062            checkScoAudioState();
2063            if (totalCount() == 0) {
2064                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2065                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2066                    // the connection.
2067                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2068                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2069                    // currently controlled by the same client process.
2070                    synchronized(mSetModeDeathHandlers) {
2071                        if ((mSetModeDeathHandlers.isEmpty() ||
2072                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2073                                (mScoAudioState == SCO_STATE_INACTIVE ||
2074                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2075                            if (mScoAudioState == SCO_STATE_INACTIVE) {
2076                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2077                                    if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2078                                            mBluetoothHeadsetDevice)) {
2079                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2080                                    } else {
2081                                        broadcastScoConnectionState(
2082                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2083                                    }
2084                                } else if (getBluetoothHeadset()) {
2085                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2086                                }
2087                            } else {
2088                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2089                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2090                            }
2091                        } else {
2092                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2093                        }
2094                    }
2095                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2096                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2097                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2098                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2099                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2100                            if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2101                                    mBluetoothHeadsetDevice)) {
2102                                mScoAudioState = SCO_STATE_INACTIVE;
2103                                broadcastScoConnectionState(
2104                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2105                            }
2106                        } else if (getBluetoothHeadset()) {
2107                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2108                        }
2109                    } else {
2110                        mScoAudioState = SCO_STATE_INACTIVE;
2111                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2112                    }
2113                }
2114            }
2115        }
2116    }
2117
2118    private void checkScoAudioState() {
2119        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2120                mScoAudioState == SCO_STATE_INACTIVE &&
2121                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2122                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2123            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2124        }
2125    }
2126
2127    private ScoClient getScoClient(IBinder cb, boolean create) {
2128        synchronized(mScoClients) {
2129            ScoClient client = null;
2130            int size = mScoClients.size();
2131            for (int i = 0; i < size; i++) {
2132                client = mScoClients.get(i);
2133                if (client.getBinder() == cb)
2134                    return client;
2135            }
2136            if (create) {
2137                client = new ScoClient(cb);
2138                mScoClients.add(client);
2139            }
2140            return client;
2141        }
2142    }
2143
2144    public void clearAllScoClients(int exceptPid, boolean stopSco) {
2145        synchronized(mScoClients) {
2146            ScoClient savedClient = null;
2147            int size = mScoClients.size();
2148            for (int i = 0; i < size; i++) {
2149                ScoClient cl = mScoClients.get(i);
2150                if (cl.getPid() != exceptPid) {
2151                    cl.clearCount(stopSco);
2152                } else {
2153                    savedClient = cl;
2154                }
2155            }
2156            mScoClients.clear();
2157            if (savedClient != null) {
2158                mScoClients.add(savedClient);
2159            }
2160        }
2161    }
2162
2163    private boolean getBluetoothHeadset() {
2164        boolean result = false;
2165        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2166        if (adapter != null) {
2167            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2168                                    BluetoothProfile.HEADSET);
2169        }
2170        // If we could not get a bluetooth headset proxy, send a failure message
2171        // without delay to reset the SCO audio state and clear SCO clients.
2172        // If we could get a proxy, send a delayed failure message that will reset our state
2173        // in case we don't receive onServiceConnected().
2174        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2175                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2176        return result;
2177    }
2178
2179    private void disconnectBluetoothSco(int exceptPid) {
2180        synchronized(mScoClients) {
2181            checkScoAudioState();
2182            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2183                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2184                if (mBluetoothHeadsetDevice != null) {
2185                    if (mBluetoothHeadset != null) {
2186                        if (!mBluetoothHeadset.stopVoiceRecognition(
2187                                mBluetoothHeadsetDevice)) {
2188                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2189                                    SENDMSG_REPLACE, 0, 0, null, 0);
2190                        }
2191                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2192                            getBluetoothHeadset()) {
2193                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2194                    }
2195                }
2196            } else {
2197                clearAllScoClients(exceptPid, true);
2198            }
2199        }
2200    }
2201
2202    private void resetBluetoothSco() {
2203        synchronized(mScoClients) {
2204            clearAllScoClients(0, false);
2205            mScoAudioState = SCO_STATE_INACTIVE;
2206            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2207        }
2208    }
2209
2210    private void broadcastScoConnectionState(int state) {
2211        if (state != mScoConnectionState) {
2212            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2213            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2214            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2215                    mScoConnectionState);
2216            sendStickyBroadcastToAll(newIntent);
2217            mScoConnectionState = state;
2218        }
2219    }
2220
2221    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2222        new BluetoothProfile.ServiceListener() {
2223        public void onServiceConnected(int profile, BluetoothProfile proxy) {
2224            BluetoothDevice btDevice;
2225            List<BluetoothDevice> deviceList;
2226            switch(profile) {
2227            case BluetoothProfile.A2DP:
2228                BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
2229                deviceList = a2dp.getConnectedDevices();
2230                if (deviceList.size() > 0) {
2231                    btDevice = deviceList.get(0);
2232                    synchronized (mConnectedDevices) {
2233                        int state = a2dp.getConnectionState(btDevice);
2234                        int delay = checkSendBecomingNoisyIntent(
2235                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2236                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2237                        queueMsgUnderWakeLock(mAudioHandler,
2238                                MSG_SET_A2DP_CONNECTION_STATE,
2239                                state,
2240                                0,
2241                                btDevice,
2242                                delay);
2243                    }
2244                }
2245                break;
2246
2247            case BluetoothProfile.HEADSET:
2248                synchronized (mScoClients) {
2249                    // Discard timeout message
2250                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2251                    mBluetoothHeadset = (BluetoothHeadset) proxy;
2252                    deviceList = mBluetoothHeadset.getConnectedDevices();
2253                    if (deviceList.size() > 0) {
2254                        mBluetoothHeadsetDevice = deviceList.get(0);
2255                    } else {
2256                        mBluetoothHeadsetDevice = null;
2257                    }
2258                    // Refresh SCO audio state
2259                    checkScoAudioState();
2260                    // Continue pending action if any
2261                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2262                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2263                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2264                        boolean status = false;
2265                        if (mBluetoothHeadsetDevice != null) {
2266                            switch (mScoAudioState) {
2267                            case SCO_STATE_ACTIVATE_REQ:
2268                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2269                                status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2270                                        mBluetoothHeadsetDevice);
2271                                break;
2272                            case SCO_STATE_DEACTIVATE_REQ:
2273                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2274                                        mBluetoothHeadsetDevice);
2275                                break;
2276                            case SCO_STATE_DEACTIVATE_EXT_REQ:
2277                                status = mBluetoothHeadset.stopVoiceRecognition(
2278                                        mBluetoothHeadsetDevice);
2279                            }
2280                        }
2281                        if (!status) {
2282                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2283                                    SENDMSG_REPLACE, 0, 0, null, 0);
2284                        }
2285                    }
2286                }
2287                break;
2288
2289            default:
2290                break;
2291            }
2292        }
2293        public void onServiceDisconnected(int profile) {
2294            switch(profile) {
2295            case BluetoothProfile.A2DP:
2296                synchronized (mConnectedDevices) {
2297                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2298                        makeA2dpDeviceUnavailableNow(
2299                                mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2300                    }
2301                }
2302                break;
2303
2304            case BluetoothProfile.HEADSET:
2305                synchronized (mScoClients) {
2306                    mBluetoothHeadset = null;
2307                }
2308                break;
2309
2310            default:
2311                break;
2312            }
2313        }
2314    };
2315
2316    /** see AudioManager.setRemoteSubmixOn(boolean on) */
2317    public void setRemoteSubmixOn(boolean on, int address) {
2318        sendMsg(mAudioHandler, MSG_SET_RSX_CONNECTION_STATE,
2319                SENDMSG_REPLACE /* replace with QUEUE when multiple addresses are supported */,
2320                on ? 1 : 0 /*arg1*/,
2321                address /*arg2*/,
2322                null/*obj*/, 0/*delay*/);
2323    }
2324
2325    private void onSetRsxConnectionState(int available, int address) {
2326        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX,
2327                available == 1 ?
2328                        AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
2329                String.valueOf(address) /*device_address*/);
2330        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX,
2331                available == 1 ?
2332                        AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE,
2333                String.valueOf(address) /*device_address*/);
2334    }
2335
2336    private void onCheckMusicActive() {
2337        synchronized (mSafeMediaVolumeState) {
2338            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2339                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2340
2341                if ((device & mSafeMediaVolumeDevices) != 0) {
2342                    sendMsg(mAudioHandler,
2343                            MSG_CHECK_MUSIC_ACTIVE,
2344                            SENDMSG_REPLACE,
2345                            0,
2346                            0,
2347                            null,
2348                            MUSIC_ACTIVE_POLL_PERIOD_MS);
2349                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device,
2350                                                                            false /*lastAudible*/);
2351                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2352                            (index > mSafeMediaVolumeIndex)) {
2353                        // Approximate cumulative active music time
2354                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2355                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2356                            setSafeMediaVolumeEnabled(true);
2357                            mMusicActiveMs = 0;
2358                        }
2359                    }
2360                }
2361            }
2362        }
2363    }
2364
2365    private void onConfigureSafeVolume(boolean force) {
2366        synchronized (mSafeMediaVolumeState) {
2367            int mcc = mContext.getResources().getConfiguration().mcc;
2368            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2369                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2370                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2371                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2372                        com.android.internal.R.bool.config_safe_media_volume_enabled);
2373
2374                // The persisted state is either "disabled" or "active": this is the state applied
2375                // next time we boot and cannot be "inactive"
2376                int persistedState;
2377                if (safeMediaVolumeEnabled) {
2378                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2379                    // The state can already be "inactive" here if the user has forced it before
2380                    // the 30 seconds timeout for forced configuration. In this case we don't reset
2381                    // it to "active".
2382                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2383                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2384                        enforceSafeMediaVolume();
2385                    }
2386                } else {
2387                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2388                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2389                }
2390                mMcc = mcc;
2391                sendMsg(mAudioHandler,
2392                        MSG_PERSIST_SAFE_VOLUME_STATE,
2393                        SENDMSG_QUEUE,
2394                        persistedState,
2395                        0,
2396                        null,
2397                        0);
2398            }
2399        }
2400    }
2401
2402    ///////////////////////////////////////////////////////////////////////////
2403    // Internal methods
2404    ///////////////////////////////////////////////////////////////////////////
2405
2406    /**
2407     * Checks if the adjustment should change ringer mode instead of just
2408     * adjusting volume. If so, this will set the proper ringer mode and volume
2409     * indices on the stream states.
2410     */
2411    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
2412        boolean adjustVolumeIndex = true;
2413        int ringerMode = getRingerMode();
2414
2415        switch (ringerMode) {
2416        case RINGER_MODE_NORMAL:
2417            if (direction == AudioManager.ADJUST_LOWER) {
2418                if (mHasVibrator) {
2419                    // "step" is the delta in internal index units corresponding to a
2420                    // change of 1 in UI index units.
2421                    // Because of rounding when rescaling from one stream index range to its alias
2422                    // index range, we cannot simply test oldIndex == step:
2423                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2424                    if (step <= oldIndex && oldIndex < 2 * step) {
2425                        ringerMode = RINGER_MODE_VIBRATE;
2426                    }
2427                } else {
2428                    // (oldIndex < step) is equivalent to (old UI index == 0)
2429                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2430                        ringerMode = RINGER_MODE_SILENT;
2431                    }
2432                }
2433            }
2434            break;
2435        case RINGER_MODE_VIBRATE:
2436            if (!mHasVibrator) {
2437                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2438                        "but no vibrator is present");
2439                break;
2440            }
2441            if ((direction == AudioManager.ADJUST_LOWER)) {
2442                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2443                    ringerMode = RINGER_MODE_SILENT;
2444                }
2445            } else if (direction == AudioManager.ADJUST_RAISE) {
2446                ringerMode = RINGER_MODE_NORMAL;
2447            }
2448            adjustVolumeIndex = false;
2449            break;
2450        case RINGER_MODE_SILENT:
2451            if (direction == AudioManager.ADJUST_RAISE) {
2452                if (mHasVibrator) {
2453                    ringerMode = RINGER_MODE_VIBRATE;
2454                } else {
2455                    ringerMode = RINGER_MODE_NORMAL;
2456                }
2457            }
2458            adjustVolumeIndex = false;
2459            break;
2460        default:
2461            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2462            break;
2463        }
2464
2465        setRingerMode(ringerMode);
2466
2467        mPrevVolDirection = direction;
2468
2469        return adjustVolumeIndex;
2470    }
2471
2472    public boolean isStreamAffectedByRingerMode(int streamType) {
2473        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
2474    }
2475
2476    private boolean isStreamMutedByRingerMode(int streamType) {
2477        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2478    }
2479
2480    public boolean isStreamAffectedByMute(int streamType) {
2481        return (mMuteAffectedStreams & (1 << streamType)) != 0;
2482    }
2483
2484    private void ensureValidDirection(int direction) {
2485        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2486            throw new IllegalArgumentException("Bad direction " + direction);
2487        }
2488    }
2489
2490    private void ensureValidSteps(int steps) {
2491        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2492            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2493        }
2494    }
2495
2496    private void ensureValidStreamType(int streamType) {
2497        if (streamType < 0 || streamType >= mStreamStates.length) {
2498            throw new IllegalArgumentException("Bad stream type " + streamType);
2499        }
2500    }
2501
2502    private boolean isInCommunication() {
2503        boolean isOffhook = false;
2504
2505        if (mVoiceCapable) {
2506            try {
2507                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
2508                if (phone != null) isOffhook = phone.isOffhook();
2509            } catch (RemoteException e) {
2510                Log.w(TAG, "Couldn't connect to phone service", e);
2511            }
2512        }
2513        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
2514    }
2515
2516    private int getActiveStreamType(int suggestedStreamType) {
2517        if (mVoiceCapable) {
2518            if (isInCommunication()) {
2519                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2520                        == AudioSystem.FORCE_BT_SCO) {
2521                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2522                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2523                } else {
2524                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2525                    return AudioSystem.STREAM_VOICE_CALL;
2526                }
2527            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2528                // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
2529                // volume can have priority over STREAM_MUSIC
2530                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
2531                    if (DEBUG_VOL)
2532                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2533                    return STREAM_REMOTE_MUSIC;
2534                } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC,
2535                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2536                    if (DEBUG_VOL)
2537                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2538                    return AudioSystem.STREAM_MUSIC;
2539                } else {
2540                    if (DEBUG_VOL)
2541                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2542                    return AudioSystem.STREAM_RING;
2543                }
2544            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
2545                if (DEBUG_VOL)
2546                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2547                return AudioSystem.STREAM_MUSIC;
2548            } else {
2549                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2550                        + suggestedStreamType);
2551                return suggestedStreamType;
2552            }
2553        } else {
2554            if (isInCommunication()) {
2555                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2556                        == AudioSystem.FORCE_BT_SCO) {
2557                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
2558                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2559                } else {
2560                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
2561                    return AudioSystem.STREAM_VOICE_CALL;
2562                }
2563            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
2564                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
2565                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
2566                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2567                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
2568                return AudioSystem.STREAM_NOTIFICATION;
2569            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2570                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
2571                    // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
2572                    // volume can have priority over STREAM_MUSIC
2573                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2574                    return STREAM_REMOTE_MUSIC;
2575                } else {
2576                    if (DEBUG_VOL)
2577                        Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
2578                    return AudioSystem.STREAM_MUSIC;
2579                }
2580            } else {
2581                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2582                        + suggestedStreamType);
2583                return suggestedStreamType;
2584            }
2585        }
2586    }
2587
2588    private void broadcastRingerMode(int ringerMode) {
2589        // Send sticky broadcast
2590        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2591        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
2592        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2593                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
2594        sendStickyBroadcastToAll(broadcast);
2595    }
2596
2597    private void broadcastVibrateSetting(int vibrateType) {
2598        // Send broadcast
2599        if (ActivityManagerNative.isSystemReady()) {
2600            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
2601            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
2602            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
2603            sendBroadcastToAll(broadcast);
2604        }
2605    }
2606
2607    // Message helper methods
2608    /**
2609     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
2610     * Note that the wake lock needs to be released after the message has been handled.
2611     */
2612    private void queueMsgUnderWakeLock(Handler handler, int msg,
2613            int arg1, int arg2, Object obj, int delay) {
2614        mMediaEventWakeLock.acquire();
2615        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2616    }
2617
2618    private static void sendMsg(Handler handler, int msg,
2619            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
2620
2621        if (existingMsgPolicy == SENDMSG_REPLACE) {
2622            handler.removeMessages(msg);
2623        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2624            return;
2625        }
2626
2627        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
2628    }
2629
2630    boolean checkAudioSettingsPermission(String method) {
2631        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2632                == PackageManager.PERMISSION_GRANTED) {
2633            return true;
2634        }
2635        String msg = "Audio Settings Permission Denial: " + method + " from pid="
2636                + Binder.getCallingPid()
2637                + ", uid=" + Binder.getCallingUid();
2638        Log.w(TAG, msg);
2639        return false;
2640    }
2641
2642    private int getDeviceForStream(int stream) {
2643        int device = AudioSystem.getDevicesForStream(stream);
2644        if ((device & (device - 1)) != 0) {
2645            // Multiple device selection is either:
2646            //  - speaker + one other device: give priority to speaker in this case.
2647            //  - one A2DP device + another device: happens with duplicated output. In this case
2648            // retain the device on the A2DP output as the other must not correspond to an active
2649            // selection if not the speaker.
2650            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2651                device = AudioSystem.DEVICE_OUT_SPEAKER;
2652            } else {
2653                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2654            }
2655        }
2656        return device;
2657    }
2658
2659    public void setWiredDeviceConnectionState(int device, int state, String name) {
2660        synchronized (mConnectedDevices) {
2661            int delay = checkSendBecomingNoisyIntent(device, state);
2662            queueMsgUnderWakeLock(mAudioHandler,
2663                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2664                    device,
2665                    state,
2666                    name,
2667                    delay);
2668        }
2669    }
2670
2671    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2672    {
2673        int delay;
2674        synchronized (mConnectedDevices) {
2675            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2676                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2677            queueMsgUnderWakeLock(mAudioHandler,
2678                    MSG_SET_A2DP_CONNECTION_STATE,
2679                    state,
2680                    0,
2681                    device,
2682                    delay);
2683        }
2684        return delay;
2685    }
2686
2687    ///////////////////////////////////////////////////////////////////////////
2688    // Inner classes
2689    ///////////////////////////////////////////////////////////////////////////
2690
2691    public class VolumeStreamState {
2692        private final int mStreamType;
2693
2694        private String mVolumeIndexSettingName;
2695        private String mLastAudibleVolumeIndexSettingName;
2696        private int mIndexMax;
2697        private final ConcurrentHashMap<Integer, Integer> mIndex =
2698                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2699        private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
2700                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2701        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
2702
2703        private VolumeStreamState(String settingName, int streamType) {
2704
2705            mVolumeIndexSettingName = settingName;
2706            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
2707
2708            mStreamType = streamType;
2709            mIndexMax = MAX_STREAM_VOLUME[streamType];
2710            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2711            mIndexMax *= 10;
2712
2713            // mDeathHandlers must be created before calling readSettings()
2714            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
2715
2716            readSettings();
2717        }
2718
2719        public String getSettingNameForDevice(boolean lastAudible, int device) {
2720            String name = lastAudible ?
2721                            mLastAudibleVolumeIndexSettingName :
2722                            mVolumeIndexSettingName;
2723            String suffix = AudioSystem.getDeviceName(device);
2724            if (suffix.isEmpty()) {
2725                return name;
2726            }
2727            return name + "_" + suffix;
2728        }
2729
2730        public synchronized void readSettings() {
2731            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
2732
2733            // do not read system stream volume from settings: this stream is always aliased
2734            // to another stream type and its volume is never persisted. Values in settings can
2735            // only be stale values
2736            // on first call to readSettings() at init time, muteCount() is always 0 so we will
2737            // always create entries for default device
2738            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2739                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2740                int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2741                synchronized (mCameraSoundForced) {
2742                    if (mCameraSoundForced) {
2743                        index = mIndexMax;
2744                    }
2745                }
2746                if (muteCount() == 0) {
2747                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2748                }
2749                mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2750                return;
2751            }
2752
2753            for (int i = 0; remainingDevices != 0; i++) {
2754                int device = (1 << i);
2755                if ((device & remainingDevices) == 0) {
2756                    continue;
2757                }
2758                remainingDevices &= ~device;
2759
2760                // retrieve current volume for device
2761                String name = getSettingNameForDevice(false /* lastAudible */, device);
2762                // if no volume stored for current stream and device, use default volume if default
2763                // device, continue otherwise
2764                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
2765                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
2766                int index = Settings.System.getIntForUser(
2767                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
2768                if (index == -1) {
2769                    continue;
2770                }
2771
2772                // ignore settings for fixed volume devices: volume should always be at max or 0
2773                if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
2774                        ((device & mFixedVolumeDevices) != 0)) {
2775                    if ((muteCount()) == 0 && (index != 0)) {
2776                        mIndex.put(device, mIndexMax);
2777                    } else {
2778                        mIndex.put(device, 0);
2779                    }
2780                    mLastAudibleIndex.put(device, mIndexMax);
2781                    continue;
2782                }
2783
2784                // retrieve last audible volume for device
2785                name = getSettingNameForDevice(true  /* lastAudible */, device);
2786                // use stored last audible index if present, otherwise use current index if not 0
2787                // or default index
2788                defaultIndex = (index > 0) ?
2789                                    index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2790                int lastAudibleIndex = Settings.System.getIntForUser(
2791                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
2792
2793                // a last audible index of 0 should never be stored for ring and notification
2794                // streams on phones (voice capable devices).
2795                if ((lastAudibleIndex == 0) && mVoiceCapable &&
2796                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
2797                    lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2798                    // Correct the data base
2799                    sendMsg(mAudioHandler,
2800                            MSG_PERSIST_VOLUME,
2801                            SENDMSG_QUEUE,
2802                            PERSIST_LAST_AUDIBLE,
2803                            device,
2804                            this,
2805                            PERSIST_DELAY);
2806                }
2807                mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex));
2808                // the initial index should never be 0 for ring and notification streams on phones
2809                // (voice capable devices) if not in silent or vibrate mode.
2810                if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) &&
2811                        mVoiceCapable &&
2812                        (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
2813                    index = lastAudibleIndex;
2814                    // Correct the data base
2815                    sendMsg(mAudioHandler,
2816                            MSG_PERSIST_VOLUME,
2817                            SENDMSG_QUEUE,
2818                            PERSIST_CURRENT,
2819                            device,
2820                            this,
2821                            PERSIST_DELAY);
2822                }
2823                if (muteCount() == 0) {
2824                    mIndex.put(device, getValidIndex(10 * index));
2825                }
2826            }
2827        }
2828
2829        public void applyDeviceVolume(int device) {
2830            AudioSystem.setStreamVolumeIndex(mStreamType,
2831                                             (getIndex(device, false  /* lastAudible */) + 5)/10,
2832                                             device);
2833        }
2834
2835        public synchronized void applyAllVolumes() {
2836            // apply default volume first: by convention this will reset all
2837            // devices volumes in audio policy manager to the supplied value
2838            AudioSystem.setStreamVolumeIndex(mStreamType,
2839                    (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10,
2840                    AudioSystem.DEVICE_OUT_DEFAULT);
2841            // then apply device specific volumes
2842            Set set = mIndex.entrySet();
2843            Iterator i = set.iterator();
2844            while (i.hasNext()) {
2845                Map.Entry entry = (Map.Entry)i.next();
2846                int device = ((Integer)entry.getKey()).intValue();
2847                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
2848                    AudioSystem.setStreamVolumeIndex(mStreamType,
2849                                                     ((Integer)entry.getValue() + 5)/10,
2850                                                     device);
2851                }
2852            }
2853        }
2854
2855        public boolean adjustIndex(int deltaIndex, int device) {
2856            return setIndex(getIndex(device,
2857                                     false  /* lastAudible */) + deltaIndex,
2858                            device,
2859                            true  /* lastAudible */);
2860        }
2861
2862        public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
2863            int oldIndex = getIndex(device, false  /* lastAudible */);
2864            index = getValidIndex(index);
2865            synchronized (mCameraSoundForced) {
2866                if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
2867                    index = mIndexMax;
2868                }
2869            }
2870            mIndex.put(device, getValidIndex(index));
2871
2872            if (oldIndex != index) {
2873                if (lastAudible) {
2874                    mLastAudibleIndex.put(device, index);
2875                }
2876                // Apply change to all streams using this one as alias
2877                // if changing volume of current device, also change volume of current
2878                // device on aliased stream
2879                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2880                int numStreamTypes = AudioSystem.getNumStreamTypes();
2881                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2882                    if (streamType != mStreamType &&
2883                            mStreamVolumeAlias[streamType] == mStreamType) {
2884                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2885                        mStreamStates[streamType].setIndex(scaledIndex,
2886                                                           device,
2887                                                           lastAudible);
2888                        if (currentDevice) {
2889                            mStreamStates[streamType].setIndex(scaledIndex,
2890                                                               getDeviceForStream(streamType),
2891                                                               lastAudible);
2892                        }
2893                    }
2894                }
2895                return true;
2896            } else {
2897                return false;
2898            }
2899        }
2900
2901        public synchronized int getIndex(int device, boolean lastAudible) {
2902            ConcurrentHashMap <Integer, Integer> indexes;
2903            if (lastAudible) {
2904                indexes = mLastAudibleIndex;
2905            } else {
2906                indexes = mIndex;
2907            }
2908            Integer index = indexes.get(device);
2909            if (index == null) {
2910                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
2911                index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT);
2912            }
2913            return index.intValue();
2914        }
2915
2916        public synchronized void setLastAudibleIndex(int index, int device) {
2917            // Apply change to all streams using this one as alias
2918            // if changing volume of current device, also change volume of current
2919            // device on aliased stream
2920            boolean currentDevice = (device == getDeviceForStream(mStreamType));
2921            int numStreamTypes = AudioSystem.getNumStreamTypes();
2922            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2923                if (streamType != mStreamType &&
2924                        mStreamVolumeAlias[streamType] == mStreamType) {
2925                    int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2926                    mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device);
2927                    if (currentDevice) {
2928                        mStreamStates[streamType].setLastAudibleIndex(scaledIndex,
2929                                                                   getDeviceForStream(streamType));
2930                    }
2931                }
2932            }
2933            mLastAudibleIndex.put(device, getValidIndex(index));
2934        }
2935
2936        public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
2937            setLastAudibleIndex(getIndex(device,
2938                                         true  /* lastAudible */) + deltaIndex,
2939                                device);
2940        }
2941
2942        public int getMaxIndex() {
2943            return mIndexMax;
2944        }
2945
2946        // only called by setAllIndexes() which is already synchronized
2947        public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
2948            if (lastAudible) {
2949                return mLastAudibleIndex;
2950            } else {
2951                return mIndex;
2952            }
2953        }
2954
2955        public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
2956            ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
2957            Set set = indexes.entrySet();
2958            Iterator i = set.iterator();
2959            while (i.hasNext()) {
2960                Map.Entry entry = (Map.Entry)i.next();
2961                int device = ((Integer)entry.getKey()).intValue();
2962                int index = ((Integer)entry.getValue()).intValue();
2963                index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
2964
2965                if (lastAudible) {
2966                    setLastAudibleIndex(index, device);
2967                } else {
2968                    setIndex(index, device, false /* lastAudible */);
2969                }
2970            }
2971        }
2972
2973        public synchronized void setAllIndexesToMax() {
2974            Set set = mIndex.entrySet();
2975            Iterator i = set.iterator();
2976            while (i.hasNext()) {
2977                Map.Entry entry = (Map.Entry)i.next();
2978                entry.setValue(mIndexMax);
2979            }
2980            set = mLastAudibleIndex.entrySet();
2981            i = set.iterator();
2982            while (i.hasNext()) {
2983                Map.Entry entry = (Map.Entry)i.next();
2984                entry.setValue(mIndexMax);
2985            }
2986        }
2987
2988        public synchronized void mute(IBinder cb, boolean state) {
2989            VolumeDeathHandler handler = getDeathHandler(cb, state);
2990            if (handler == null) {
2991                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
2992                return;
2993            }
2994            handler.mute(state);
2995        }
2996
2997        public int getStreamType() {
2998            return mStreamType;
2999        }
3000
3001        private int getValidIndex(int index) {
3002            if (index < 0) {
3003                return 0;
3004            } else if (index > mIndexMax) {
3005                return mIndexMax;
3006            }
3007
3008            return index;
3009        }
3010
3011        private class VolumeDeathHandler implements IBinder.DeathRecipient {
3012            private IBinder mICallback; // To be notified of client's death
3013            private int mMuteCount; // Number of active mutes for this client
3014
3015            VolumeDeathHandler(IBinder cb) {
3016                mICallback = cb;
3017            }
3018
3019            // must be called while synchronized on parent VolumeStreamState
3020            public void mute(boolean state) {
3021                if (state) {
3022                    if (mMuteCount == 0) {
3023                        // Register for client death notification
3024                        try {
3025                            // mICallback can be 0 if muted by AudioService
3026                            if (mICallback != null) {
3027                                mICallback.linkToDeath(this, 0);
3028                            }
3029                            mDeathHandlers.add(this);
3030                            // If the stream is not yet muted by any client, set level to 0
3031                            if (muteCount() == 0) {
3032                                Set set = mIndex.entrySet();
3033                                Iterator i = set.iterator();
3034                                while (i.hasNext()) {
3035                                    Map.Entry entry = (Map.Entry)i.next();
3036                                    int device = ((Integer)entry.getKey()).intValue();
3037                                    setIndex(0, device, false /* lastAudible */);
3038                                }
3039                                sendMsg(mAudioHandler,
3040                                        MSG_SET_ALL_VOLUMES,
3041                                        SENDMSG_QUEUE,
3042                                        0,
3043                                        0,
3044                                        VolumeStreamState.this, 0);
3045                            }
3046                        } catch (RemoteException e) {
3047                            // Client has died!
3048                            binderDied();
3049                            return;
3050                        }
3051                    } else {
3052                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3053                    }
3054                    mMuteCount++;
3055                } else {
3056                    if (mMuteCount == 0) {
3057                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3058                    } else {
3059                        mMuteCount--;
3060                        if (mMuteCount == 0) {
3061                            // Unregister from client death notification
3062                            mDeathHandlers.remove(this);
3063                            // mICallback can be 0 if muted by AudioService
3064                            if (mICallback != null) {
3065                                mICallback.unlinkToDeath(this, 0);
3066                            }
3067                            if (muteCount() == 0) {
3068                                // If the stream is not muted any more, restore its volume if
3069                                // ringer mode allows it
3070                                if (!isStreamAffectedByRingerMode(mStreamType) ||
3071                                        mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
3072                                    Set set = mIndex.entrySet();
3073                                    Iterator i = set.iterator();
3074                                    while (i.hasNext()) {
3075                                        Map.Entry entry = (Map.Entry)i.next();
3076                                        int device = ((Integer)entry.getKey()).intValue();
3077                                        setIndex(getIndex(device,
3078                                                          true  /* lastAudible */),
3079                                                 device,
3080                                                 false  /* lastAudible */);
3081                                    }
3082                                    sendMsg(mAudioHandler,
3083                                            MSG_SET_ALL_VOLUMES,
3084                                            SENDMSG_QUEUE,
3085                                            0,
3086                                            0,
3087                                            VolumeStreamState.this, 0);
3088                                }
3089                            }
3090                        }
3091                    }
3092                }
3093            }
3094
3095            public void binderDied() {
3096                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3097                if (mMuteCount != 0) {
3098                    // Reset all active mute requests from this client.
3099                    mMuteCount = 1;
3100                    mute(false);
3101                }
3102            }
3103        }
3104
3105        private synchronized int muteCount() {
3106            int count = 0;
3107            int size = mDeathHandlers.size();
3108            for (int i = 0; i < size; i++) {
3109                count += mDeathHandlers.get(i).mMuteCount;
3110            }
3111            return count;
3112        }
3113
3114        // only called by mute() which is already synchronized
3115        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
3116            VolumeDeathHandler handler;
3117            int size = mDeathHandlers.size();
3118            for (int i = 0; i < size; i++) {
3119                handler = mDeathHandlers.get(i);
3120                if (cb == handler.mICallback) {
3121                    return handler;
3122                }
3123            }
3124            // If this is the first mute request for this client, create a new
3125            // client death handler. Otherwise, it is an out of sequence unmute request.
3126            if (state) {
3127                handler = new VolumeDeathHandler(cb);
3128            } else {
3129                Log.w(TAG, "stream was not muted by this client");
3130                handler = null;
3131            }
3132            return handler;
3133        }
3134
3135        private void dump(PrintWriter pw) {
3136            pw.print("   Mute count: ");
3137            pw.println(muteCount());
3138            pw.print("   Current: ");
3139            Set set = mIndex.entrySet();
3140            Iterator i = set.iterator();
3141            while (i.hasNext()) {
3142                Map.Entry entry = (Map.Entry)i.next();
3143                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3144                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3145            }
3146            pw.print("\n   Last audible: ");
3147            set = mLastAudibleIndex.entrySet();
3148            i = set.iterator();
3149            while (i.hasNext()) {
3150                Map.Entry entry = (Map.Entry)i.next();
3151                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3152                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3153            }
3154        }
3155    }
3156
3157    /** Thread that handles native AudioSystem control. */
3158    private class AudioSystemThread extends Thread {
3159        AudioSystemThread() {
3160            super("AudioService");
3161        }
3162
3163        @Override
3164        public void run() {
3165            // Set this thread up so the handler will work on it
3166            Looper.prepare();
3167
3168            synchronized(AudioService.this) {
3169                mAudioHandler = new AudioHandler();
3170
3171                // Notify that the handler has been created
3172                AudioService.this.notify();
3173            }
3174
3175            // Listen for volume change requests that are set by VolumePanel
3176            Looper.loop();
3177        }
3178    }
3179
3180    /** Handles internal volume messages in separate volume thread. */
3181    private class AudioHandler extends Handler {
3182
3183        private void setDeviceVolume(VolumeStreamState streamState, int device) {
3184
3185            // Apply volume
3186            streamState.applyDeviceVolume(device);
3187
3188            // Apply change to all streams using this one as alias
3189            int numStreamTypes = AudioSystem.getNumStreamTypes();
3190            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3191                if (streamType != streamState.mStreamType &&
3192                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3193                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
3194                }
3195            }
3196
3197            // Post a persist volume msg
3198            sendMsg(mAudioHandler,
3199                    MSG_PERSIST_VOLUME,
3200                    SENDMSG_QUEUE,
3201                    PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
3202                    device,
3203                    streamState,
3204                    PERSIST_DELAY);
3205
3206        }
3207
3208        private void setAllVolumes(VolumeStreamState streamState) {
3209
3210            // Apply volume
3211            streamState.applyAllVolumes();
3212
3213            // Apply change to all streams using this one as alias
3214            int numStreamTypes = AudioSystem.getNumStreamTypes();
3215            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3216                if (streamType != streamState.mStreamType &&
3217                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3218                    mStreamStates[streamType].applyAllVolumes();
3219                }
3220            }
3221        }
3222
3223        private void persistVolume(VolumeStreamState streamState,
3224                                   int persistType,
3225                                   int device) {
3226            if ((persistType & PERSIST_CURRENT) != 0) {
3227                System.putIntForUser(mContentResolver,
3228                          streamState.getSettingNameForDevice(false /* lastAudible */, device),
3229                          (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10,
3230                          UserHandle.USER_CURRENT);
3231            }
3232            if ((persistType & PERSIST_LAST_AUDIBLE) != 0) {
3233                System.putIntForUser(mContentResolver,
3234                        streamState.getSettingNameForDevice(true /* lastAudible */, device),
3235                        (streamState.getIndex(device, true  /* lastAudible */) + 5) / 10,
3236                        UserHandle.USER_CURRENT);
3237            }
3238        }
3239
3240        private void persistRingerMode(int ringerMode) {
3241            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
3242        }
3243
3244        private void playSoundEffect(int effectType, int volume) {
3245            synchronized (mSoundEffectsLock) {
3246                if (mSoundPool == null) {
3247                    return;
3248                }
3249                float volFloat;
3250                // use default if volume is not specified by caller
3251                if (volume < 0) {
3252                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3253                } else {
3254                    volFloat = (float) volume / 1000.0f;
3255                }
3256
3257                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
3258                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f);
3259                } else {
3260                    MediaPlayer mediaPlayer = new MediaPlayer();
3261                    try {
3262                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
3263                        mediaPlayer.setDataSource(filePath);
3264                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3265                        mediaPlayer.prepare();
3266                        mediaPlayer.setVolume(volFloat);
3267                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3268                            public void onCompletion(MediaPlayer mp) {
3269                                cleanupPlayer(mp);
3270                            }
3271                        });
3272                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
3273                            public boolean onError(MediaPlayer mp, int what, int extra) {
3274                                cleanupPlayer(mp);
3275                                return true;
3276                            }
3277                        });
3278                        mediaPlayer.start();
3279                    } catch (IOException ex) {
3280                        Log.w(TAG, "MediaPlayer IOException: "+ex);
3281                    } catch (IllegalArgumentException ex) {
3282                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3283                    } catch (IllegalStateException ex) {
3284                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3285                    }
3286                }
3287            }
3288        }
3289
3290        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
3291            Settings.System.putStringForUser(mContentResolver,
3292                                             Settings.System.MEDIA_BUTTON_RECEIVER,
3293                                             receiver == null ? "" : receiver.flattenToString(),
3294                                             UserHandle.USER_CURRENT);
3295        }
3296
3297        private void cleanupPlayer(MediaPlayer mp) {
3298            if (mp != null) {
3299                try {
3300                    mp.stop();
3301                    mp.release();
3302                } catch (IllegalStateException ex) {
3303                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3304                }
3305            }
3306        }
3307
3308        private void setForceUse(int usage, int config) {
3309            AudioSystem.setForceUse(usage, config);
3310        }
3311
3312        private void onPersistSafeVolumeState(int state) {
3313            Settings.Global.putInt(mContentResolver,
3314                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3315                    state);
3316        }
3317
3318        @Override
3319        public void handleMessage(Message msg) {
3320
3321            switch (msg.what) {
3322
3323                case MSG_SET_DEVICE_VOLUME:
3324                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3325                    break;
3326
3327                case MSG_SET_ALL_VOLUMES:
3328                    setAllVolumes((VolumeStreamState) msg.obj);
3329                    break;
3330
3331                case MSG_PERSIST_VOLUME:
3332                    persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
3333                    break;
3334
3335                case MSG_PERSIST_MASTER_VOLUME:
3336                    Settings.System.putFloatForUser(mContentResolver,
3337                                                    Settings.System.VOLUME_MASTER,
3338                                                    (float)msg.arg1 / (float)1000.0,
3339                                                    UserHandle.USER_CURRENT);
3340                    break;
3341
3342                case MSG_PERSIST_MASTER_VOLUME_MUTE:
3343                    Settings.System.putIntForUser(mContentResolver,
3344                                                 Settings.System.VOLUME_MASTER_MUTE,
3345                                                 msg.arg1,
3346                                                 UserHandle.USER_CURRENT);
3347                    break;
3348
3349                case MSG_PERSIST_RINGER_MODE:
3350                    // note that the value persisted is the current ringer mode, not the
3351                    // value of ringer mode as of the time the request was made to persist
3352                    persistRingerMode(getRingerMode());
3353                    break;
3354
3355                case MSG_MEDIA_SERVER_DIED:
3356                    if (!mMediaServerOk) {
3357                        Log.e(TAG, "Media server died.");
3358                        // Force creation of new IAudioFlinger interface so that we are notified
3359                        // when new media_server process is back to life.
3360                        AudioSystem.setErrorCallback(mAudioSystemCallback);
3361                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
3362                                null, 500);
3363                    }
3364                    break;
3365
3366                case MSG_MEDIA_SERVER_STARTED:
3367                    Log.e(TAG, "Media server started.");
3368                    // indicate to audio HAL that we start the reconfiguration phase after a media
3369                    // server crash
3370                    // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server
3371                    // process restarts after a crash, not the first time it is started.
3372                    AudioSystem.setParameters("restarting=true");
3373
3374                    // Restore device connection states
3375                    synchronized (mConnectedDevices) {
3376                        Set set = mConnectedDevices.entrySet();
3377                        Iterator i = set.iterator();
3378                        while (i.hasNext()) {
3379                            Map.Entry device = (Map.Entry)i.next();
3380                            AudioSystem.setDeviceConnectionState(
3381                                                            ((Integer)device.getKey()).intValue(),
3382                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
3383                                                            (String)device.getValue());
3384                        }
3385                    }
3386                    // Restore call state
3387                    AudioSystem.setPhoneState(mMode);
3388
3389                    // Restore forced usage for communcations and record
3390                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3391                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3392                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3393                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3394
3395                    // Restore stream volumes
3396                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3397                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3398                        VolumeStreamState streamState = mStreamStates[streamType];
3399                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
3400
3401                        streamState.applyAllVolumes();
3402                    }
3403
3404                    // Restore ringer mode
3405                    setRingerModeInt(getRingerMode(), false);
3406
3407                    // Restore master volume
3408                    restoreMasterVolume();
3409
3410                    // Reset device orientation (if monitored for this device)
3411                    if (mMonitorOrientation) {
3412                        setOrientationForAudioSystem();
3413                    }
3414
3415                    synchronized (mBluetoothA2dpEnabledLock) {
3416                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3417                                mBluetoothA2dpEnabled ?
3418                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3419                    }
3420
3421                    synchronized (mSettingsLock) {
3422                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3423                                mDockAudioMediaEnabled ?
3424                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3425                    }
3426
3427                    // indicate the end of reconfiguration phase to audio HAL
3428                    AudioSystem.setParameters("restarting=false");
3429                    break;
3430
3431                case MSG_LOAD_SOUND_EFFECTS:
3432                    loadSoundEffects();
3433                    break;
3434
3435                case MSG_PLAY_SOUND_EFFECT:
3436                    playSoundEffect(msg.arg1, msg.arg2);
3437                    break;
3438
3439                case MSG_BTA2DP_DOCK_TIMEOUT:
3440                    // msg.obj  == address of BTA2DP device
3441                    synchronized (mConnectedDevices) {
3442                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
3443                    }
3444                    break;
3445
3446                case MSG_SET_FORCE_USE:
3447                case MSG_SET_FORCE_BT_A2DP_USE:
3448                    setForceUse(msg.arg1, msg.arg2);
3449                    break;
3450
3451                case MSG_PERSIST_MEDIABUTTONRECEIVER:
3452                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
3453                    break;
3454
3455                case MSG_RCDISPLAY_CLEAR:
3456                    onRcDisplayClear();
3457                    break;
3458
3459                case MSG_RCDISPLAY_UPDATE:
3460                    // msg.obj is guaranteed to be non null
3461                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
3462                    break;
3463
3464                case MSG_BT_HEADSET_CNCT_FAILED:
3465                    resetBluetoothSco();
3466                    break;
3467
3468                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3469                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3470                    mMediaEventWakeLock.release();
3471                    break;
3472
3473                case MSG_SET_A2DP_CONNECTION_STATE:
3474                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3475                    mMediaEventWakeLock.release();
3476                    break;
3477
3478                case MSG_REPORT_NEW_ROUTES: {
3479                    int N = mRoutesObservers.beginBroadcast();
3480                    if (N > 0) {
3481                        AudioRoutesInfo routes;
3482                        synchronized (mCurAudioRoutes) {
3483                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3484                        }
3485                        while (N > 0) {
3486                            N--;
3487                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3488                            try {
3489                                obs.dispatchAudioRoutesChanged(routes);
3490                            } catch (RemoteException e) {
3491                            }
3492                        }
3493                    }
3494                    mRoutesObservers.finishBroadcast();
3495                    break;
3496                }
3497
3498                case MSG_REEVALUATE_REMOTE:
3499                    onReevaluateRemote();
3500                    break;
3501
3502                case MSG_RCC_NEW_PLAYBACK_INFO:
3503                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
3504                            ((Integer)msg.obj).intValue() /* value */);
3505                    break;
3506                case MSG_RCC_NEW_VOLUME_OBS:
3507                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
3508                            (IRemoteVolumeObserver)msg.obj /* rvo */);
3509                    break;
3510
3511                case MSG_SET_RSX_CONNECTION_STATE:
3512                    onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/);
3513                    break;
3514
3515                case MSG_CHECK_MUSIC_ACTIVE:
3516                    onCheckMusicActive();
3517                    break;
3518
3519                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3520                    onSendBecomingNoisyIntent();
3521                    break;
3522
3523                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3524                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3525                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3526                    break;
3527                case MSG_PERSIST_SAFE_VOLUME_STATE:
3528                    onPersistSafeVolumeState(msg.arg1);
3529                    break;
3530            }
3531        }
3532    }
3533
3534    private class SettingsObserver extends ContentObserver {
3535
3536        SettingsObserver() {
3537            super(new Handler());
3538            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3539                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3540            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3541                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3542        }
3543
3544        @Override
3545        public void onChange(boolean selfChange) {
3546            super.onChange(selfChange);
3547            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3548            //       However there appear to be some missing locks around mRingerModeMutedStreams
3549            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3550            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3551            synchronized (mSettingsLock) {
3552                int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3553                       Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3554                       ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3555                       (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3556                       UserHandle.USER_CURRENT);
3557                if (mVoiceCapable) {
3558                    ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3559                } else {
3560                    ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
3561                }
3562                synchronized (mCameraSoundForced) {
3563                    if (mCameraSoundForced) {
3564                        ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3565                    } else {
3566                        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3567                    }
3568                }
3569                if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3570                    /*
3571                     * Ensure all stream types that should be affected by ringer mode
3572                     * are in the proper state.
3573                     */
3574                    mRingerModeAffectedStreams = ringerModeAffectedStreams;
3575                    setRingerModeInt(getRingerMode(), false);
3576                }
3577                readDockAudioSettings(mContentResolver);
3578            }
3579        }
3580    }
3581
3582    // must be called synchronized on mConnectedDevices
3583    private void makeA2dpDeviceAvailable(String address) {
3584        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3585        // audio policy manager
3586        setBluetoothA2dpOnInt(true);
3587        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3588                AudioSystem.DEVICE_STATE_AVAILABLE,
3589                address);
3590        // Reset A2DP suspend state each time a new sink is connected
3591        AudioSystem.setParameters("A2dpSuspended=false");
3592        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3593                address);
3594    }
3595
3596    private void onSendBecomingNoisyIntent() {
3597        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
3598    }
3599
3600    // must be called synchronized on mConnectedDevices
3601    private void makeA2dpDeviceUnavailableNow(String address) {
3602        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3603                AudioSystem.DEVICE_STATE_UNAVAILABLE,
3604                address);
3605        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3606    }
3607
3608    // must be called synchronized on mConnectedDevices
3609    private void makeA2dpDeviceUnavailableLater(String address) {
3610        // prevent any activity on the A2DP audio output to avoid unwanted
3611        // reconnection of the sink.
3612        AudioSystem.setParameters("A2dpSuspended=true");
3613        // the device will be made unavailable later, so consider it disconnected right away
3614        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3615        // send the delayed message to make the device unavailable later
3616        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3617        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3618
3619    }
3620
3621    // must be called synchronized on mConnectedDevices
3622    private void cancelA2dpDeviceTimeout() {
3623        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3624    }
3625
3626    // must be called synchronized on mConnectedDevices
3627    private boolean hasScheduledA2dpDockTimeout() {
3628        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3629    }
3630
3631    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
3632    {
3633        if (btDevice == null) {
3634            return;
3635        }
3636        String address = btDevice.getAddress();
3637        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3638            address = "";
3639        }
3640        synchronized (mConnectedDevices) {
3641            boolean isConnected =
3642                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
3643                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
3644
3645            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
3646                if (btDevice.isBluetoothDock()) {
3647                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
3648                        // introduction of a delay for transient disconnections of docks when
3649                        // power is rapidly turned off/on, this message will be canceled if
3650                        // we reconnect the dock under a preset delay
3651                        makeA2dpDeviceUnavailableLater(address);
3652                        // the next time isConnected is evaluated, it will be false for the dock
3653                    }
3654                } else {
3655                    makeA2dpDeviceUnavailableNow(address);
3656                }
3657                synchronized (mCurAudioRoutes) {
3658                    if (mCurAudioRoutes.mBluetoothName != null) {
3659                        mCurAudioRoutes.mBluetoothName = null;
3660                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3661                                SENDMSG_NOOP, 0, 0, null, 0);
3662                    }
3663                }
3664            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
3665                if (btDevice.isBluetoothDock()) {
3666                    // this could be a reconnection after a transient disconnection
3667                    cancelA2dpDeviceTimeout();
3668                    mDockAddress = address;
3669                } else {
3670                    // this could be a connection of another A2DP device before the timeout of
3671                    // a dock: cancel the dock timeout, and make the dock unavailable now
3672                    if(hasScheduledA2dpDockTimeout()) {
3673                        cancelA2dpDeviceTimeout();
3674                        makeA2dpDeviceUnavailableNow(mDockAddress);
3675                    }
3676                }
3677                makeA2dpDeviceAvailable(address);
3678                synchronized (mCurAudioRoutes) {
3679                    String name = btDevice.getAliasName();
3680                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3681                        mCurAudioRoutes.mBluetoothName = name;
3682                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3683                                SENDMSG_NOOP, 0, 0, null, 0);
3684                    }
3685                }
3686            }
3687        }
3688    }
3689
3690    private boolean handleDeviceConnection(boolean connected, int device, String params) {
3691        synchronized (mConnectedDevices) {
3692            boolean isConnected = (mConnectedDevices.containsKey(device) &&
3693                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
3694
3695            if (isConnected && !connected) {
3696                AudioSystem.setDeviceConnectionState(device,
3697                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
3698                                              mConnectedDevices.get(device));
3699                 mConnectedDevices.remove(device);
3700                 return true;
3701            } else if (!isConnected && connected) {
3702                 AudioSystem.setDeviceConnectionState(device,
3703                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
3704                                                      params);
3705                 mConnectedDevices.put(new Integer(device), params);
3706                 return true;
3707            }
3708        }
3709        return false;
3710    }
3711
3712    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3713    // sent if none of these devices is connected.
3714    int mBecomingNoisyIntentDevices =
3715            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3716            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL |
3717            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
3718            AudioSystem.DEVICE_OUT_ALL_USB;
3719
3720    // must be called before removing the device from mConnectedDevices
3721    private int checkSendBecomingNoisyIntent(int device, int state) {
3722        int delay = 0;
3723        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3724            int devices = 0;
3725            for (int dev : mConnectedDevices.keySet()) {
3726                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3727                   devices |= dev;
3728                }
3729            }
3730            if (devices == device) {
3731                sendMsg(mAudioHandler,
3732                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
3733                        SENDMSG_REPLACE,
3734                        0,
3735                        0,
3736                        null,
3737                        0);
3738                delay = 1000;
3739            }
3740        }
3741
3742        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3743                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3744            delay = 1000;
3745        }
3746        return delay;
3747    }
3748
3749    private void sendDeviceConnectionIntent(int device, int state, String name)
3750    {
3751        Intent intent = new Intent();
3752
3753        intent.putExtra("state", state);
3754        intent.putExtra("name", name);
3755        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3756
3757        int connType = 0;
3758
3759        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3760            connType = AudioRoutesInfo.MAIN_HEADSET;
3761            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3762            intent.putExtra("microphone", 1);
3763        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3764            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3765            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3766            intent.putExtra("microphone", 0);
3767        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3768            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3769            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3770        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3771            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3772            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3773        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3774            connType = AudioRoutesInfo.MAIN_HDMI;
3775            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3776        }
3777
3778        synchronized (mCurAudioRoutes) {
3779            if (connType != 0) {
3780                int newConn = mCurAudioRoutes.mMainType;
3781                if (state != 0) {
3782                    newConn |= connType;
3783                } else {
3784                    newConn &= ~connType;
3785                }
3786                if (newConn != mCurAudioRoutes.mMainType) {
3787                    mCurAudioRoutes.mMainType = newConn;
3788                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3789                            SENDMSG_NOOP, 0, 0, null, 0);
3790                }
3791            }
3792        }
3793
3794        final long ident = Binder.clearCallingIdentity();
3795        try {
3796            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3797        } finally {
3798            Binder.restoreCallingIdentity(ident);
3799        }
3800    }
3801
3802    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3803    {
3804        synchronized (mConnectedDevices) {
3805            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3806                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3807                setBluetoothA2dpOnInt(true);
3808            }
3809            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
3810            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
3811            if (state != 0) {
3812                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3813                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
3814                    setBluetoothA2dpOnInt(false);
3815                }
3816                if ((device & mSafeMediaVolumeDevices) != 0) {
3817                    sendMsg(mAudioHandler,
3818                            MSG_CHECK_MUSIC_ACTIVE,
3819                            SENDMSG_REPLACE,
3820                            0,
3821                            0,
3822                            null,
3823                            MUSIC_ACTIVE_POLL_PERIOD_MS);
3824                }
3825            }
3826            if (!isUsb) {
3827                sendDeviceConnectionIntent(device, state, name);
3828            }
3829        }
3830    }
3831
3832    /* cache of the address of the last dock the device was connected to */
3833    private String mDockAddress;
3834
3835    /**
3836     * Receiver for misc intent broadcasts the Phone app cares about.
3837     */
3838    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
3839        @Override
3840        public void onReceive(Context context, Intent intent) {
3841            String action = intent.getAction();
3842            int device;
3843            int state;
3844
3845            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
3846                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
3847                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
3848                int config;
3849                switch (dockState) {
3850                    case Intent.EXTRA_DOCK_STATE_DESK:
3851                        config = AudioSystem.FORCE_BT_DESK_DOCK;
3852                        break;
3853                    case Intent.EXTRA_DOCK_STATE_CAR:
3854                        config = AudioSystem.FORCE_BT_CAR_DOCK;
3855                        break;
3856                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
3857                        config = AudioSystem.FORCE_ANALOG_DOCK;
3858                        break;
3859                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
3860                        config = AudioSystem.FORCE_DIGITAL_DOCK;
3861                        break;
3862                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
3863                    default:
3864                        config = AudioSystem.FORCE_NONE;
3865                }
3866                // Low end docks have a menu to enable or disable audio
3867                // (see mDockAudioMediaEnabled)
3868                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
3869                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
3870                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
3871                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
3872                }
3873                mDockState = dockState;
3874            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
3875                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
3876                                               BluetoothProfile.STATE_DISCONNECTED);
3877                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3878                String address = null;
3879
3880                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
3881                if (btDevice == null) {
3882                    return;
3883                }
3884
3885                address = btDevice.getAddress();
3886                BluetoothClass btClass = btDevice.getBluetoothClass();
3887                if (btClass != null) {
3888                    switch (btClass.getDeviceClass()) {
3889                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3890                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3891                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3892                        break;
3893                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3894                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3895                        break;
3896                    }
3897                }
3898
3899                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3900                    address = "";
3901                }
3902
3903                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3904                if (handleDeviceConnection(connected, device, address)) {
3905                    synchronized (mScoClients) {
3906                        if (connected) {
3907                            mBluetoothHeadsetDevice = btDevice;
3908                        } else {
3909                            mBluetoothHeadsetDevice = null;
3910                            resetBluetoothSco();
3911                        }
3912                    }
3913                }
3914            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
3915                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
3916                state = intent.getIntExtra("state", 0);
3917                int alsaCard = intent.getIntExtra("card", -1);
3918                int alsaDevice = intent.getIntExtra("device", -1);
3919                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
3920                                    : "card=" + alsaCard + ";device=" + alsaDevice);
3921                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
3922                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
3923                Log.v(TAG, "Broadcast Receiver: Got "
3924                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
3925                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
3926                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
3927                setWiredDeviceConnectionState(device, state, params);
3928            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
3929                boolean broadcast = false;
3930                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
3931                synchronized (mScoClients) {
3932                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
3933                    // broadcast intent if the connection was initated by AudioService
3934                    if (!mScoClients.isEmpty() &&
3935                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
3936                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3937                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
3938                        broadcast = true;
3939                    }
3940                    switch (btState) {
3941                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
3942                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
3943                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3944                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3945                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
3946                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3947                        }
3948                        break;
3949                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
3950                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
3951                        mScoAudioState = SCO_STATE_INACTIVE;
3952                        clearAllScoClients(0, false);
3953                        break;
3954                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
3955                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3956                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3957                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
3958                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3959                        }
3960                    default:
3961                        // do not broadcast CONNECTING or invalid state
3962                        broadcast = false;
3963                        break;
3964                    }
3965                }
3966                if (broadcast) {
3967                    broadcastScoConnectionState(scoAudioState);
3968                    //FIXME: this is to maintain compatibility with deprecated intent
3969                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
3970                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
3971                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
3972                    sendStickyBroadcastToAll(newIntent);
3973                }
3974            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
3975                mBootCompleted = true;
3976                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP,
3977                        0, 0, null, 0);
3978
3979                mKeyguardManager =
3980                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
3981                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
3982                resetBluetoothSco();
3983                getBluetoothHeadset();
3984                //FIXME: this is to maintain compatibility with deprecated intent
3985                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
3986                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
3987                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
3988                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3989                sendStickyBroadcastToAll(newIntent);
3990
3991                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3992                if (adapter != null) {
3993                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3994                                            BluetoothProfile.A2DP);
3995                }
3996
3997                sendMsg(mAudioHandler,
3998                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
3999                        SENDMSG_REPLACE,
4000                        0,
4001                        0,
4002                        null,
4003                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
4004            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
4005                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
4006                    // a package is being removed, not replaced
4007                    String packageName = intent.getData().getSchemeSpecificPart();
4008                    if (packageName != null) {
4009                        removeMediaButtonReceiverForPackage(packageName);
4010                    }
4011                }
4012            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4013                AudioSystem.setParameters("screen_state=on");
4014            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4015                AudioSystem.setParameters("screen_state=off");
4016            } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) {
4017                handleConfigurationChanged(context);
4018            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4019                // attempt to stop music playback for background user
4020                sendMsg(mAudioHandler,
4021                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4022                        SENDMSG_REPLACE,
4023                        0,
4024                        0,
4025                        null,
4026                        0);
4027                // the current audio focus owner is no longer valid
4028                discardAudioFocusOwner();
4029
4030                // load volume settings for new user
4031                readAudioSettings(true /*userSwitch*/);
4032                // preserve STREAM_MUSIC volume from one user to the next.
4033                sendMsg(mAudioHandler,
4034                        MSG_SET_ALL_VOLUMES,
4035                        SENDMSG_QUEUE,
4036                        0,
4037                        0,
4038                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4039            }
4040        }
4041    }
4042
4043    //==========================================================================================
4044    // AudioFocus
4045    //==========================================================================================
4046
4047    /* constant to identify focus stack entry that is used to hold the focus while the phone
4048     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
4049     * entering and exiting calls.
4050     */
4051    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
4052
4053    private final static Object mAudioFocusLock = new Object();
4054
4055    private final static Object mRingingLock = new Object();
4056
4057    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
4058        @Override
4059        public void onCallStateChanged(int state, String incomingNumber) {
4060            if (state == TelephonyManager.CALL_STATE_RINGING) {
4061                //Log.v(TAG, " CALL_STATE_RINGING");
4062                synchronized(mRingingLock) {
4063                    mIsRinging = true;
4064                }
4065            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
4066                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
4067                synchronized(mRingingLock) {
4068                    mIsRinging = false;
4069                }
4070            }
4071        }
4072    };
4073
4074    /**
4075     * Discard the current audio focus owner.
4076     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
4077     * focus), remove it from the stack, and clear the remote control display.
4078     */
4079    private void discardAudioFocusOwner() {
4080        synchronized(mAudioFocusLock) {
4081            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
4082                // notify the current focus owner it lost focus after removing it from stack
4083                FocusStackEntry focusOwner = mFocusStack.pop();
4084                try {
4085                    focusOwner.mFocusDispatcher.dispatchAudioFocusChange(
4086                            AudioManager.AUDIOFOCUS_LOSS, focusOwner.mClientId);
4087                } catch (RemoteException e) {
4088                    Log.e(TAG, "Failure to signal loss of audio focus due to "+ e);
4089                    e.printStackTrace();
4090                }
4091                focusOwner.unlinkToDeath();
4092                // clear RCD
4093                synchronized(mRCStack) {
4094                    clearRemoteControlDisplay_syncAfRcs();
4095                }
4096            }
4097        }
4098    }
4099
4100    private void notifyTopOfAudioFocusStack() {
4101        // notify the top of the stack it gained focus
4102        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
4103            if (canReassignAudioFocus()) {
4104                try {
4105                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
4106                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
4107                } catch (RemoteException e) {
4108                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
4109                    e.printStackTrace();
4110                }
4111            }
4112        }
4113    }
4114
4115    private static class FocusStackEntry {
4116        public int mStreamType = -1;// no stream type
4117        public IAudioFocusDispatcher mFocusDispatcher = null;
4118        public IBinder mSourceRef = null;
4119        public String mClientId;
4120        public int mFocusChangeType;
4121        public AudioFocusDeathHandler mHandler;
4122        public String mPackageName;
4123        public int mCallingUid;
4124
4125        public FocusStackEntry() {
4126        }
4127
4128        public FocusStackEntry(int streamType, int duration,
4129                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
4130                String pn, int uid) {
4131            mStreamType = streamType;
4132            mFocusDispatcher = afl;
4133            mSourceRef = source;
4134            mClientId = id;
4135            mFocusChangeType = duration;
4136            mHandler = hdlr;
4137            mPackageName = pn;
4138            mCallingUid = uid;
4139        }
4140
4141        public void unlinkToDeath() {
4142            try {
4143                if (mSourceRef != null && mHandler != null) {
4144                    mSourceRef.unlinkToDeath(mHandler, 0);
4145                    mHandler = null;
4146                }
4147            } catch (java.util.NoSuchElementException e) {
4148                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
4149            }
4150        }
4151
4152        @Override
4153        protected void finalize() throws Throwable {
4154            unlinkToDeath(); // unlink exception handled inside method
4155            super.finalize();
4156        }
4157    }
4158
4159    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
4160
4161    /**
4162     * Helper function:
4163     * Display in the log the current entries in the audio focus stack
4164     */
4165    private void dumpFocusStack(PrintWriter pw) {
4166        pw.println("\nAudio Focus stack entries (last is top of stack):");
4167        synchronized(mAudioFocusLock) {
4168            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
4169            while(stackIterator.hasNext()) {
4170                FocusStackEntry fse = stackIterator.next();
4171                pw.println("  source:" + fse.mSourceRef
4172                        + " -- pack: " + fse.mPackageName
4173                        + " -- client: " + fse.mClientId
4174                        + " -- duration: " + fse.mFocusChangeType
4175                        + " -- uid: " + fse.mCallingUid
4176                        + " -- stream: " + fse.mStreamType);
4177            }
4178        }
4179    }
4180
4181    /**
4182     * Helper function:
4183     * Called synchronized on mAudioFocusLock
4184     * Remove a focus listener from the focus stack.
4185     * @param focusListenerToRemove the focus listener
4186     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
4187     *   focus, notify the next item in the stack it gained focus.
4188     */
4189    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
4190        // is the current top of the focus stack abandoning focus? (because of request, not death)
4191        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
4192        {
4193            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
4194            FocusStackEntry fse = mFocusStack.pop();
4195            fse.unlinkToDeath();
4196            if (signal) {
4197                // notify the new top of the stack it gained focus
4198                notifyTopOfAudioFocusStack();
4199                // there's a new top of the stack, let the remote control know
4200                synchronized(mRCStack) {
4201                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
4202                }
4203            }
4204        } else {
4205            // focus is abandoned by a client that's not at the top of the stack,
4206            // no need to update focus.
4207            // (using an iterator on the stack so we can safely remove an entry after having
4208            //  evaluated it, traversal order doesn't matter here)
4209            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
4210            while(stackIterator.hasNext()) {
4211                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
4212                if(fse.mClientId.equals(clientToRemove)) {
4213                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
4214                            + fse.mClientId);
4215                    stackIterator.remove();
4216                    fse.unlinkToDeath();
4217                }
4218            }
4219        }
4220    }
4221
4222    /**
4223     * Helper function:
4224     * Called synchronized on mAudioFocusLock
4225     * Remove focus listeners from the focus stack for a particular client when it has died.
4226     */
4227    private void removeFocusStackEntryForClient(IBinder cb) {
4228        // is the owner of the audio focus part of the client to remove?
4229        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
4230                mFocusStack.peek().mSourceRef.equals(cb);
4231        // (using an iterator on the stack so we can safely remove an entry after having
4232        //  evaluated it, traversal order doesn't matter here)
4233        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
4234        while(stackIterator.hasNext()) {
4235            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
4236            if(fse.mSourceRef.equals(cb)) {
4237                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
4238                        + fse.mClientId);
4239                stackIterator.remove();
4240                // the client just died, no need to unlink to its death
4241            }
4242        }
4243        if (isTopOfStackForClientToRemove) {
4244            // we removed an entry at the top of the stack:
4245            //  notify the new top of the stack it gained focus.
4246            notifyTopOfAudioFocusStack();
4247            // there's a new top of the stack, let the remote control know
4248            synchronized(mRCStack) {
4249                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
4250            }
4251        }
4252    }
4253
4254    /**
4255     * Helper function:
4256     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
4257     */
4258    private boolean canReassignAudioFocus() {
4259        // focus requests are rejected during a phone call or when the phone is ringing
4260        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
4261        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
4262            return false;
4263        }
4264        return true;
4265    }
4266
4267    /**
4268     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
4269     * stack if necessary.
4270     */
4271    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
4272        private IBinder mCb; // To be notified of client's death
4273
4274        AudioFocusDeathHandler(IBinder cb) {
4275            mCb = cb;
4276        }
4277
4278        public void binderDied() {
4279            synchronized(mAudioFocusLock) {
4280                Log.w(TAG, "  AudioFocus   audio focus client died");
4281                removeFocusStackEntryForClient(mCb);
4282            }
4283        }
4284
4285        public IBinder getBinder() {
4286            return mCb;
4287        }
4288    }
4289
4290
4291    /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
4292    public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
4293            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4294        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
4295        // the main stream type for the audio focus request is currently not used. It may
4296        // potentially be used to handle multiple stream type-dependent audio focuses.
4297
4298        // we need a valid binder callback for clients
4299        if (!cb.pingBinder()) {
4300            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
4301            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4302        }
4303
4304        synchronized(mAudioFocusLock) {
4305            if (!canReassignAudioFocus()) {
4306                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4307            }
4308
4309            // handle the potential premature death of the new holder of the focus
4310            // (premature death == death before abandoning focus)
4311            // Register for client death notification
4312            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
4313            try {
4314                cb.linkToDeath(afdh, 0);
4315            } catch (RemoteException e) {
4316                // client has already died!
4317                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
4318                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4319            }
4320
4321            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
4322                // if focus is already owned by this client and the reason for acquiring the focus
4323                // hasn't changed, don't do anything
4324                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
4325                    // unlink death handler so it can be gc'ed.
4326                    // linkToDeath() creates a JNI global reference preventing collection.
4327                    cb.unlinkToDeath(afdh, 0);
4328                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
4329                }
4330                // the reason for the audio focus request has changed: remove the current top of
4331                // stack and respond as if we had a new focus owner
4332                FocusStackEntry fse = mFocusStack.pop();
4333                fse.unlinkToDeath();
4334            }
4335
4336            // notify current top of stack it is losing focus
4337            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
4338                try {
4339                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
4340                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
4341                            mFocusStack.peek().mClientId);
4342                } catch (RemoteException e) {
4343                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
4344                    e.printStackTrace();
4345                }
4346            }
4347
4348            // focus requester might already be somewhere below in the stack, remove it
4349            removeFocusStackEntry(clientId, false /* signal */);
4350
4351            // push focus requester at the top of the audio focus stack
4352            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
4353                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
4354
4355            // there's a new top of the stack, let the remote control know
4356            synchronized(mRCStack) {
4357                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
4358            }
4359        }//synchronized(mAudioFocusLock)
4360
4361        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
4362    }
4363
4364    /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */
4365    public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
4366        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
4367        try {
4368            // this will take care of notifying the new focus owner if needed
4369            synchronized(mAudioFocusLock) {
4370                removeFocusStackEntry(clientId, true);
4371            }
4372        } catch (java.util.ConcurrentModificationException cme) {
4373            // Catching this exception here is temporary. It is here just to prevent
4374            // a crash seen when the "Silent" notification is played. This is believed to be fixed
4375            // but this try catch block is left just to be safe.
4376            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
4377            cme.printStackTrace();
4378        }
4379
4380        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
4381    }
4382
4383
4384    public void unregisterAudioFocusClient(String clientId) {
4385        synchronized(mAudioFocusLock) {
4386            removeFocusStackEntry(clientId, false);
4387        }
4388    }
4389
4390
4391    //==========================================================================================
4392    // RemoteControl
4393    //==========================================================================================
4394    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
4395        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
4396    }
4397
4398    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
4399        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
4400    }
4401
4402    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
4403        // sanity check on the incoming key event
4404        if (!isValidMediaKeyEvent(keyEvent)) {
4405            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
4406            return;
4407        }
4408        // event filtering for telephony
4409        synchronized(mRingingLock) {
4410            synchronized(mRCStack) {
4411                if ((mMediaReceiverForCalls != null) &&
4412                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
4413                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
4414                    return;
4415                }
4416            }
4417        }
4418        // event filtering based on voice-based interactions
4419        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
4420            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
4421        } else {
4422            dispatchMediaKeyEvent(keyEvent, needWakeLock);
4423        }
4424    }
4425
4426    /**
4427     * Handles the dispatching of the media button events to the telephony package.
4428     * Precondition: mMediaReceiverForCalls != null
4429     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
4430     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
4431     *     is dispatched.
4432     */
4433    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
4434        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
4435        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
4436        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
4437        if (needWakeLock) {
4438            mMediaEventWakeLock.acquire();
4439            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
4440        }
4441        final long ident = Binder.clearCallingIdentity();
4442        try {
4443            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
4444                    null, mKeyEventDone, mAudioHandler, Activity.RESULT_OK, null, null);
4445        } finally {
4446            Binder.restoreCallingIdentity(ident);
4447        }
4448    }
4449
4450    /**
4451     * Handles the dispatching of the media button events to one of the registered listeners,
4452     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
4453     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
4454     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
4455     *     is dispatched.
4456     */
4457    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
4458        if (needWakeLock) {
4459            mMediaEventWakeLock.acquire();
4460        }
4461        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
4462        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
4463        synchronized(mRCStack) {
4464            if (!mRCStack.empty()) {
4465                // send the intent that was registered by the client
4466                try {
4467                    mRCStack.peek().mMediaIntent.send(mContext,
4468                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
4469                            keyIntent, AudioService.this, mAudioHandler);
4470                } catch (CanceledException e) {
4471                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
4472                    e.printStackTrace();
4473                }
4474            } else {
4475                // legacy behavior when nobody registered their media button event receiver
4476                //    through AudioManager
4477                if (needWakeLock) {
4478                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
4479                }
4480                final long ident = Binder.clearCallingIdentity();
4481                try {
4482                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
4483                            null, mKeyEventDone,
4484                            mAudioHandler, Activity.RESULT_OK, null, null);
4485                } finally {
4486                    Binder.restoreCallingIdentity(ident);
4487                }
4488            }
4489        }
4490    }
4491
4492    /**
4493     * The different actions performed in response to a voice button key event.
4494     */
4495    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
4496    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
4497    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
4498
4499    private final Object mVoiceEventLock = new Object();
4500    private boolean mVoiceButtonDown;
4501    private boolean mVoiceButtonHandled;
4502
4503    /**
4504     * Filter key events that may be used for voice-based interactions
4505     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
4506     *    media buttons that can be used to trigger voice-based interactions.
4507     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
4508     *     is dispatched.
4509     */
4510    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
4511        if (DEBUG_RC) {
4512            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
4513        }
4514
4515        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
4516        int keyAction = keyEvent.getAction();
4517        synchronized (mVoiceEventLock) {
4518            if (keyAction == KeyEvent.ACTION_DOWN) {
4519                if (keyEvent.getRepeatCount() == 0) {
4520                    // initial down
4521                    mVoiceButtonDown = true;
4522                    mVoiceButtonHandled = false;
4523                } else if (mVoiceButtonDown && !mVoiceButtonHandled
4524                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
4525                    // long-press, start voice-based interactions
4526                    mVoiceButtonHandled = true;
4527                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
4528                }
4529            } else if (keyAction == KeyEvent.ACTION_UP) {
4530                if (mVoiceButtonDown) {
4531                    // voice button up
4532                    mVoiceButtonDown = false;
4533                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
4534                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
4535                    }
4536                }
4537            }
4538        }//synchronized (mVoiceEventLock)
4539
4540        // take action after media button event filtering for voice-based interactions
4541        switch (voiceButtonAction) {
4542            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
4543                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
4544                break;
4545            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
4546                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
4547                // then start the voice-based interactions
4548                startVoiceBasedInteractions(needWakeLock);
4549                break;
4550            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
4551                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
4552                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
4553                break;
4554        }
4555    }
4556
4557    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
4558        // send DOWN event
4559        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
4560        dispatchMediaKeyEvent(keyEvent, needWakeLock);
4561        // send UP event
4562        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
4563        dispatchMediaKeyEvent(keyEvent, needWakeLock);
4564
4565    }
4566
4567
4568    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
4569        if (keyEvent == null) {
4570            return false;
4571        }
4572        final int keyCode = keyEvent.getKeyCode();
4573        switch (keyCode) {
4574            case KeyEvent.KEYCODE_MUTE:
4575            case KeyEvent.KEYCODE_HEADSETHOOK:
4576            case KeyEvent.KEYCODE_MEDIA_PLAY:
4577            case KeyEvent.KEYCODE_MEDIA_PAUSE:
4578            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
4579            case KeyEvent.KEYCODE_MEDIA_STOP:
4580            case KeyEvent.KEYCODE_MEDIA_NEXT:
4581            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
4582            case KeyEvent.KEYCODE_MEDIA_REWIND:
4583            case KeyEvent.KEYCODE_MEDIA_RECORD:
4584            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
4585            case KeyEvent.KEYCODE_MEDIA_CLOSE:
4586            case KeyEvent.KEYCODE_MEDIA_EJECT:
4587                break;
4588            default:
4589                return false;
4590        }
4591        return true;
4592    }
4593
4594    /**
4595     * Checks whether the given key code is one that can trigger the launch of voice-based
4596     *   interactions.
4597     * @param keyCode the key code associated with the key event
4598     * @return true if the key is one of the supported voice-based interaction triggers
4599     */
4600    private static boolean isValidVoiceInputKeyCode(int keyCode) {
4601        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
4602            return true;
4603        } else {
4604            return false;
4605        }
4606    }
4607
4608    /**
4609     * Tell the system to start voice-based interactions / voice commands
4610     */
4611    private void startVoiceBasedInteractions(boolean needWakeLock) {
4612        Intent voiceIntent = null;
4613        // select which type of search to launch:
4614        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
4615        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
4616        //    with EXTRA_SECURE set to true if the device is securely locked
4617        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
4618        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
4619        if (!isLocked && pm.isScreenOn()) {
4620            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
4621        } else {
4622            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
4623            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
4624                    isLocked && mKeyguardManager.isKeyguardSecure());
4625        }
4626        // start the search activity
4627        if (needWakeLock) {
4628            mMediaEventWakeLock.acquire();
4629        }
4630        try {
4631            if (voiceIntent != null) {
4632                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
4633                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
4634                mContext.startActivity(voiceIntent);
4635            }
4636        } catch (ActivityNotFoundException e) {
4637            Log.w(TAG, "No activity for search: " + e);
4638        } finally {
4639            if (needWakeLock) {
4640                mMediaEventWakeLock.release();
4641            }
4642        }
4643    }
4644
4645    private PowerManager.WakeLock mMediaEventWakeLock;
4646
4647    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
4648
4649    // only set when wakelock was acquired, no need to check value when received
4650    private static final String EXTRA_WAKELOCK_ACQUIRED =
4651            "android.media.AudioService.WAKELOCK_ACQUIRED";
4652
4653    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
4654            int resultCode, String resultData, Bundle resultExtras) {
4655        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
4656            mMediaEventWakeLock.release();
4657        }
4658    }
4659
4660    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
4661        public void onReceive(Context context, Intent intent) {
4662            if (intent == null) {
4663                return;
4664            }
4665            Bundle extras = intent.getExtras();
4666            if (extras == null) {
4667                return;
4668            }
4669            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
4670                mMediaEventWakeLock.release();
4671            }
4672        }
4673    };
4674
4675    private final Object mCurrentRcLock = new Object();
4676    /**
4677     * The one remote control client which will receive a request for display information.
4678     * This object may be null.
4679     * Access protected by mCurrentRcLock.
4680     */
4681    private IRemoteControlClient mCurrentRcClient = null;
4682
4683    private final static int RC_INFO_NONE = 0;
4684    private final static int RC_INFO_ALL =
4685        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
4686        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
4687        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
4688        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
4689
4690    /**
4691     * A monotonically increasing generation counter for mCurrentRcClient.
4692     * Only accessed with a lock on mCurrentRcLock.
4693     * No value wrap-around issues as we only act on equal values.
4694     */
4695    private int mCurrentRcClientGen = 0;
4696
4697    /**
4698     * Inner class to monitor remote control client deaths, and remove the client for the
4699     * remote control stack if necessary.
4700     */
4701    private class RcClientDeathHandler implements IBinder.DeathRecipient {
4702        private IBinder mCb; // To be notified of client's death
4703        private PendingIntent mMediaIntent;
4704
4705        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
4706            mCb = cb;
4707            mMediaIntent = pi;
4708        }
4709
4710        public void binderDied() {
4711            Log.w(TAG, "  RemoteControlClient died");
4712            // remote control client died, make sure the displays don't use it anymore
4713            //  by setting its remote control client to null
4714            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
4715            // the dead client was maybe handling remote playback, reevaluate
4716            postReevaluateRemote();
4717        }
4718
4719        public IBinder getBinder() {
4720            return mCb;
4721        }
4722    }
4723
4724    /**
4725     * A global counter for RemoteControlClient identifiers
4726     */
4727    private static int sLastRccId = 0;
4728
4729    private class RemotePlaybackState {
4730        int mRccId;
4731        int mVolume;
4732        int mVolumeMax;
4733        int mVolumeHandling;
4734
4735        private RemotePlaybackState(int id, int vol, int volMax) {
4736            mRccId = id;
4737            mVolume = vol;
4738            mVolumeMax = volMax;
4739            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
4740        }
4741    }
4742
4743    /**
4744     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
4745     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
4746     * every time we need this info.
4747     */
4748    private RemotePlaybackState mMainRemote;
4749    /**
4750     * Indicates whether the "main" RemoteControlClient is considered active.
4751     * Use synchronized on mMainRemote.
4752     */
4753    private boolean mMainRemoteIsActive;
4754    /**
4755     * Indicates whether there is remote playback going on. True even if there is no "active"
4756     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
4757     * handles remote playback.
4758     * Use synchronized on mMainRemote.
4759     */
4760    private boolean mHasRemotePlayback;
4761
4762    private static class RemoteControlStackEntry {
4763        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
4764        /**
4765         * The target for the ACTION_MEDIA_BUTTON events.
4766         * Always non null.
4767         */
4768        public PendingIntent mMediaIntent;
4769        /**
4770         * The registered media button event receiver.
4771         * Always non null.
4772         */
4773        public ComponentName mReceiverComponent;
4774        public String mCallingPackageName;
4775        public int mCallingUid;
4776        /**
4777         * Provides access to the information to display on the remote control.
4778         * May be null (when a media button event receiver is registered,
4779         *     but no remote control client has been registered) */
4780        public IRemoteControlClient mRcClient;
4781        public RcClientDeathHandler mRcClientDeathHandler;
4782        /**
4783         * Information only used for non-local playback
4784         */
4785        public int mPlaybackType;
4786        public int mPlaybackVolume;
4787        public int mPlaybackVolumeMax;
4788        public int mPlaybackVolumeHandling;
4789        public int mPlaybackStream;
4790        public int mPlaybackState;
4791        public IRemoteVolumeObserver mRemoteVolumeObs;
4792
4793        public void resetPlaybackInfo() {
4794            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
4795            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
4796            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
4797            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
4798            mPlaybackStream = AudioManager.STREAM_MUSIC;
4799            mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
4800            mRemoteVolumeObs = null;
4801        }
4802
4803        /** precondition: mediaIntent != null, eventReceiver != null */
4804        public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
4805            mMediaIntent = mediaIntent;
4806            mReceiverComponent = eventReceiver;
4807            mCallingUid = -1;
4808            mRcClient = null;
4809            mRccId = ++sLastRccId;
4810
4811            resetPlaybackInfo();
4812        }
4813
4814        public void unlinkToRcClientDeath() {
4815            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
4816                try {
4817                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
4818                    mRcClientDeathHandler = null;
4819                } catch (java.util.NoSuchElementException e) {
4820                    // not much we can do here
4821                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
4822                    e.printStackTrace();
4823                }
4824            }
4825        }
4826
4827        @Override
4828        protected void finalize() throws Throwable {
4829            unlinkToRcClientDeath();// unlink exception handled inside method
4830            super.finalize();
4831        }
4832    }
4833
4834    /**
4835     *  The stack of remote control event receivers.
4836     *  Code sections and methods that modify the remote control event receiver stack are
4837     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
4838     *  stack, audio focus or RC, can lead to a change in the remote control display
4839     */
4840    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
4841
4842    /**
4843     * The component the telephony package can register so telephony calls have priority to
4844     * handle media button events
4845     */
4846    private ComponentName mMediaReceiverForCalls = null;
4847
4848    /**
4849     * Helper function:
4850     * Display in the log the current entries in the remote control focus stack
4851     */
4852    private void dumpRCStack(PrintWriter pw) {
4853        pw.println("\nRemote Control stack entries (last is top of stack):");
4854        synchronized(mRCStack) {
4855            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4856            while(stackIterator.hasNext()) {
4857                RemoteControlStackEntry rcse = stackIterator.next();
4858                pw.println("  pi: " + rcse.mMediaIntent +
4859                        " -- pack: " + rcse.mCallingPackageName +
4860                        "  -- ercvr: " + rcse.mReceiverComponent +
4861                        "  -- client: " + rcse.mRcClient +
4862                        "  -- uid: " + rcse.mCallingUid +
4863                        "  -- type: " + rcse.mPlaybackType +
4864                        "  state: " + rcse.mPlaybackState);
4865            }
4866        }
4867    }
4868
4869    /**
4870     * Helper function:
4871     * Display in the log the current entries in the remote control stack, focusing
4872     * on RemoteControlClient data
4873     */
4874    private void dumpRCCStack(PrintWriter pw) {
4875        pw.println("\nRemote Control Client stack entries (last is top of stack):");
4876        synchronized(mRCStack) {
4877            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4878            while(stackIterator.hasNext()) {
4879                RemoteControlStackEntry rcse = stackIterator.next();
4880                pw.println("  uid: " + rcse.mCallingUid +
4881                        "  -- id: " + rcse.mRccId +
4882                        "  -- type: " + rcse.mPlaybackType +
4883                        "  -- state: " + rcse.mPlaybackState +
4884                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
4885                        "  -- vol: " + rcse.mPlaybackVolume +
4886                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
4887                        "  -- volObs: " + rcse.mRemoteVolumeObs);
4888
4889            }
4890        }
4891        synchronized (mMainRemote) {
4892            pw.println("\nRemote Volume State:");
4893            pw.println("  has remote: " + mHasRemotePlayback);
4894            pw.println("  is remote active: " + mMainRemoteIsActive);
4895            pw.println("  rccId: " + mMainRemote.mRccId);
4896            pw.println("  volume handling: "
4897                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
4898                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
4899            pw.println("  volume: " + mMainRemote.mVolume);
4900            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
4901        }
4902    }
4903
4904    /**
4905     * Helper function:
4906     * Remove any entry in the remote control stack that has the same package name as packageName
4907     * Pre-condition: packageName != null
4908     */
4909    private void removeMediaButtonReceiverForPackage(String packageName) {
4910        synchronized(mRCStack) {
4911            if (mRCStack.empty()) {
4912                return;
4913            } else {
4914                RemoteControlStackEntry oldTop = mRCStack.peek();
4915                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4916                // iterate over the stack entries
4917                // (using an iterator on the stack so we can safely remove an entry after having
4918                //  evaluated it, traversal order doesn't matter here)
4919                while(stackIterator.hasNext()) {
4920                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
4921                    if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
4922                        // a stack entry is from the package being removed, remove it from the stack
4923                        stackIterator.remove();
4924                        rcse.unlinkToRcClientDeath();
4925                    }
4926                }
4927                if (mRCStack.empty()) {
4928                    // no saved media button receiver
4929                    mAudioHandler.sendMessage(
4930                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4931                                    null));
4932                } else if (oldTop != mRCStack.peek()) {
4933                    // the top of the stack has changed, save it in the system settings
4934                    // by posting a message to persist it
4935                    mAudioHandler.sendMessage(
4936                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4937                                    mRCStack.peek().mReceiverComponent));
4938                }
4939            }
4940        }
4941    }
4942
4943    /**
4944     * Helper function:
4945     * Restore remote control receiver from the system settings.
4946     */
4947    private void restoreMediaButtonReceiver() {
4948        String receiverName = Settings.System.getStringForUser(mContentResolver,
4949                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
4950        if ((null != receiverName) && !receiverName.isEmpty()) {
4951            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
4952            // construct a PendingIntent targeted to the restored component name
4953            // for the media button and register it
4954            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4955            //     the associated intent will be handled by the component being registered
4956            mediaButtonIntent.setComponent(eventReceiver);
4957            PendingIntent pi = PendingIntent.getBroadcast(mContext,
4958                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
4959            registerMediaButtonIntent(pi, eventReceiver);
4960        }
4961    }
4962
4963    /**
4964     * Helper function:
4965     * Set the new remote control receiver at the top of the RC focus stack.
4966     * Called synchronized on mAudioFocusLock, then mRCStack
4967     * precondition: mediaIntent != null, target != null
4968     */
4969    private void pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent, ComponentName target) {
4970        // already at top of stack?
4971        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
4972            return;
4973        }
4974        RemoteControlStackEntry rcse = null;
4975        boolean wasInsideStack = false;
4976        try {
4977            for (int index = mRCStack.size()-1; index >= 0; index--) {
4978                rcse = mRCStack.elementAt(index);
4979                if(rcse.mMediaIntent.equals(mediaIntent)) {
4980                    // ok to remove element while traversing the stack since we're leaving the loop
4981                    mRCStack.removeElementAt(index);
4982                    wasInsideStack = true;
4983                    break;
4984                }
4985            }
4986        } catch (ArrayIndexOutOfBoundsException e) {
4987            // not expected to happen, indicates improper concurrent modification
4988            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
4989        }
4990        if (!wasInsideStack) {
4991            rcse = new RemoteControlStackEntry(mediaIntent, target);
4992        }
4993        mRCStack.push(rcse); // rcse is never null
4994
4995        // post message to persist the default media button receiver
4996        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
4997                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
4998    }
4999
5000    /**
5001     * Helper function:
5002     * Remove the remote control receiver from the RC focus stack.
5003     * Called synchronized on mAudioFocusLock, then mRCStack
5004     * precondition: pi != null
5005     */
5006    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
5007        try {
5008            for (int index = mRCStack.size()-1; index >= 0; index--) {
5009                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
5010                if (rcse.mMediaIntent.equals(pi)) {
5011                    rcse.unlinkToRcClientDeath();
5012                    // ok to remove element while traversing the stack since we're leaving the loop
5013                    mRCStack.removeElementAt(index);
5014                    break;
5015                }
5016            }
5017        } catch (ArrayIndexOutOfBoundsException e) {
5018            // not expected to happen, indicates improper concurrent modification
5019            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
5020        }
5021    }
5022
5023    /**
5024     * Helper function:
5025     * Called synchronized on mRCStack
5026     */
5027    private boolean isCurrentRcController(PendingIntent pi) {
5028        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
5029            return true;
5030        }
5031        return false;
5032    }
5033
5034    //==========================================================================================
5035    // Remote control display / client
5036    //==========================================================================================
5037    /**
5038     * Update the remote control displays with the new "focused" client generation
5039     */
5040    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
5041            PendingIntent newMediaIntent, boolean clearing) {
5042        // NOTE: Only one IRemoteControlDisplay supported in this implementation
5043        if (mRcDisplay != null) {
5044            try {
5045                mRcDisplay.setCurrentClientId(
5046                        newClientGeneration, newMediaIntent, clearing);
5047            } catch (RemoteException e) {
5048                Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
5049                // if we had a display before, stop monitoring its death
5050                rcDisplay_stopDeathMonitor_syncRcStack();
5051                mRcDisplay = null;
5052            }
5053        }
5054    }
5055
5056    /**
5057     * Update the remote control clients with the new "focused" client generation
5058     */
5059    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
5060        // (using an iterator on the stack so we can safely remove an entry if needed,
5061        //  traversal order doesn't matter here as we update all entries)
5062        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5063        while(stackIterator.hasNext()) {
5064            RemoteControlStackEntry se = stackIterator.next();
5065            if ((se != null) && (se.mRcClient != null)) {
5066                try {
5067                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
5068                } catch (RemoteException e) {
5069                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e);
5070                    stackIterator.remove();
5071                    se.unlinkToRcClientDeath();
5072                }
5073            }
5074        }
5075    }
5076
5077    /**
5078     * Update the displays and clients with the new "focused" client generation and name
5079     * @param newClientGeneration the new generation value matching a client update
5080     * @param newClientEventReceiver the media button event receiver associated with the client.
5081     *    May be null, which implies there is no registered media button event receiver.
5082     * @param clearing true if the new client generation value maps to a remote control update
5083     *    where the display should be cleared.
5084     */
5085    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
5086            PendingIntent newMediaIntent, boolean clearing) {
5087        // send the new valid client generation ID to all displays
5088        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
5089        // send the new valid client generation ID to all clients
5090        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
5091    }
5092
5093    /**
5094     * Called when processing MSG_RCDISPLAY_CLEAR event
5095     */
5096    private void onRcDisplayClear() {
5097        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
5098
5099        synchronized(mRCStack) {
5100            synchronized(mCurrentRcLock) {
5101                mCurrentRcClientGen++;
5102                // synchronously update the displays and clients with the new client generation
5103                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
5104                        null /*newMediaIntent*/, true /*clearing*/);
5105            }
5106        }
5107    }
5108
5109    /**
5110     * Called when processing MSG_RCDISPLAY_UPDATE event
5111     */
5112    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
5113        synchronized(mRCStack) {
5114            synchronized(mCurrentRcLock) {
5115                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
5116                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
5117
5118                    mCurrentRcClientGen++;
5119                    // synchronously update the displays and clients with
5120                    //      the new client generation
5121                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
5122                            rcse.mMediaIntent /*newMediaIntent*/,
5123                            false /*clearing*/);
5124
5125                    // tell the current client that it needs to send info
5126                    try {
5127                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
5128                                flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
5129                    } catch (RemoteException e) {
5130                        Log.e(TAG, "Current valid remote client is dead: "+e);
5131                        mCurrentRcClient = null;
5132                    }
5133                } else {
5134                    // the remote control display owner has changed between the
5135                    // the message to update the display was sent, and the time it
5136                    // gets to be processed (now)
5137                }
5138            }
5139        }
5140    }
5141
5142
5143    /**
5144     * Helper function:
5145     * Called synchronized on mRCStack
5146     */
5147    private void clearRemoteControlDisplay_syncAfRcs() {
5148        synchronized(mCurrentRcLock) {
5149            mCurrentRcClient = null;
5150        }
5151        // will cause onRcDisplayClear() to be called in AudioService's handler thread
5152        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
5153    }
5154
5155    /**
5156     * Helper function for code readability: only to be called from
5157     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
5158     *    this method.
5159     * Preconditions:
5160     *    - called synchronized mAudioFocusLock then on mRCStack
5161     *    - mRCStack.isEmpty() is false
5162     */
5163    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
5164        RemoteControlStackEntry rcse = mRCStack.peek();
5165        int infoFlagsAboutToBeUsed = infoChangedFlags;
5166        // this is where we enforce opt-in for information display on the remote controls
5167        //   with the new AudioManager.registerRemoteControlClient() API
5168        if (rcse.mRcClient == null) {
5169            //Log.w(TAG, "Can't update remote control display with null remote control client");
5170            clearRemoteControlDisplay_syncAfRcs();
5171            return;
5172        }
5173        synchronized(mCurrentRcLock) {
5174            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
5175                // new RC client, assume every type of information shall be queried
5176                infoFlagsAboutToBeUsed = RC_INFO_ALL;
5177            }
5178            mCurrentRcClient = rcse.mRcClient;
5179        }
5180        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
5181        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
5182                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
5183    }
5184
5185    /**
5186     * Helper function:
5187     * Called synchronized on mAudioFocusLock, then mRCStack
5188     * Check whether the remote control display should be updated, triggers the update if required
5189     * @param infoChangedFlags the flags corresponding to the remote control client information
5190     *     that has changed, if applicable (checking for the update conditions might trigger a
5191     *     clear, rather than an update event).
5192     */
5193    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
5194        // determine whether the remote control display should be refreshed
5195        // if either stack is empty, there is a mismatch, so clear the RC display
5196        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
5197            clearRemoteControlDisplay_syncAfRcs();
5198            return;
5199        }
5200
5201        // determine which entry in the AudioFocus stack to consider, and compare against the
5202        // top of the stack for the media button event receivers : simply using the top of the
5203        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
5204        // notifications playing during music playback.
5205        // Crawl the AudioFocus stack from the top until an entry is found with the following
5206        // characteristics:
5207        // - focus gain on STREAM_MUSIC stream
5208        // - non-transient focus gain on a stream other than music
5209        FocusStackEntry af = null;
5210        try {
5211            for (int index = mFocusStack.size()-1; index >= 0; index--) {
5212                FocusStackEntry fse = mFocusStack.elementAt(index);
5213                if ((fse.mStreamType == AudioManager.STREAM_MUSIC)
5214                        || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) {
5215                    af = fse;
5216                    break;
5217                }
5218            }
5219        } catch (ArrayIndexOutOfBoundsException e) {
5220            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
5221            af = null;
5222        }
5223        if (af == null) {
5224            clearRemoteControlDisplay_syncAfRcs();
5225            return;
5226        }
5227
5228        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
5229        if ((mRCStack.peek().mCallingPackageName != null)
5230                && (af.mPackageName != null)
5231                && !(mRCStack.peek().mCallingPackageName.compareTo(
5232                        af.mPackageName) == 0)) {
5233            clearRemoteControlDisplay_syncAfRcs();
5234            return;
5235        }
5236        // if the audio focus didn't originate from the same Uid as the one in which the remote
5237        //   control information will be retrieved, clear
5238        if (mRCStack.peek().mCallingUid != af.mCallingUid) {
5239            clearRemoteControlDisplay_syncAfRcs();
5240            return;
5241        }
5242
5243        // refresh conditions were verified: update the remote controls
5244        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
5245        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
5246    }
5247
5248    /**
5249     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
5250     * precondition: mediaIntent != null, target != null
5251     */
5252    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
5253        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
5254
5255        synchronized(mAudioFocusLock) {
5256            synchronized(mRCStack) {
5257                pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver);
5258                // new RC client, assume every type of information shall be queried
5259                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
5260            }
5261        }
5262    }
5263
5264    /**
5265     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
5266     * precondition: mediaIntent != null, eventReceiver != null
5267     */
5268    public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
5269    {
5270        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
5271
5272        synchronized(mAudioFocusLock) {
5273            synchronized(mRCStack) {
5274                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
5275                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
5276                if (topOfStackWillChange) {
5277                    // current RC client will change, assume every type of info needs to be queried
5278                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
5279                }
5280            }
5281        }
5282    }
5283
5284    /**
5285     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
5286     * precondition: c != null
5287     */
5288    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
5289        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
5290                != PackageManager.PERMISSION_GRANTED) {
5291            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
5292            return;
5293        }
5294        synchronized(mRCStack) {
5295            mMediaReceiverForCalls = c;
5296        }
5297    }
5298
5299    /**
5300     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
5301     */
5302    public void unregisterMediaButtonEventReceiverForCalls() {
5303        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
5304                != PackageManager.PERMISSION_GRANTED) {
5305            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
5306            return;
5307        }
5308        synchronized(mRCStack) {
5309            mMediaReceiverForCalls = null;
5310        }
5311    }
5312
5313    /**
5314     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
5315     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
5316     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
5317     *     without modifying the RC stack, but while still causing the display to refresh (will
5318     *     become blank as a result of this)
5319     */
5320    public int registerRemoteControlClient(PendingIntent mediaIntent,
5321            IRemoteControlClient rcClient, String callingPackageName) {
5322        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
5323        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
5324        synchronized(mAudioFocusLock) {
5325            synchronized(mRCStack) {
5326                // store the new display information
5327                try {
5328                    for (int index = mRCStack.size()-1; index >= 0; index--) {
5329                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
5330                        if(rcse.mMediaIntent.equals(mediaIntent)) {
5331                            // already had a remote control client?
5332                            if (rcse.mRcClientDeathHandler != null) {
5333                                // stop monitoring the old client's death
5334                                rcse.unlinkToRcClientDeath();
5335                            }
5336                            // save the new remote control client
5337                            rcse.mRcClient = rcClient;
5338                            rcse.mCallingPackageName = callingPackageName;
5339                            rcse.mCallingUid = Binder.getCallingUid();
5340                            if (rcClient == null) {
5341                                // here rcse.mRcClientDeathHandler is null;
5342                                rcse.resetPlaybackInfo();
5343                                break;
5344                            }
5345                            rccId = rcse.mRccId;
5346
5347                            // there is a new (non-null) client:
5348                            // 1/ give the new client the current display (if any)
5349                            if (mRcDisplay != null) {
5350                                try {
5351                                    rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
5352                                } catch (RemoteException e) {
5353                                    Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
5354                                }
5355                            }
5356                            // 2/ monitor the new client's death
5357                            IBinder b = rcse.mRcClient.asBinder();
5358                            RcClientDeathHandler rcdh =
5359                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
5360                            try {
5361                                b.linkToDeath(rcdh, 0);
5362                            } catch (RemoteException e) {
5363                                // remote control client is DOA, disqualify it
5364                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
5365                                rcse.mRcClient = null;
5366                            }
5367                            rcse.mRcClientDeathHandler = rcdh;
5368                            break;
5369                        }
5370                    }//for
5371                } catch (ArrayIndexOutOfBoundsException e) {
5372                    // not expected to happen, indicates improper concurrent modification
5373                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
5374                }
5375
5376                // if the eventReceiver is at the top of the stack
5377                // then check for potential refresh of the remote controls
5378                if (isCurrentRcController(mediaIntent)) {
5379                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
5380                }
5381            }//synchronized(mRCStack)
5382        }//synchronized(mAudioFocusLock)
5383        return rccId;
5384    }
5385
5386    /**
5387     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
5388     * rcClient is guaranteed non-null
5389     */
5390    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
5391            IRemoteControlClient rcClient) {
5392        synchronized(mAudioFocusLock) {
5393            synchronized(mRCStack) {
5394                boolean topRccChange = false;
5395                try {
5396                    for (int index = mRCStack.size()-1; index >= 0; index--) {
5397                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
5398                        if ((rcse.mMediaIntent.equals(mediaIntent))
5399                                && rcClient.equals(rcse.mRcClient)) {
5400                            // we found the IRemoteControlClient to unregister
5401                            // stop monitoring its death
5402                            rcse.unlinkToRcClientDeath();
5403                            // reset the client-related fields
5404                            rcse.mRcClient = null;
5405                            rcse.mCallingPackageName = null;
5406                            topRccChange = (index == mRCStack.size()-1);
5407                            // there can only be one matching RCC in the RC stack, we're done
5408                            break;
5409                        }
5410                    }
5411                } catch (ArrayIndexOutOfBoundsException e) {
5412                    // not expected to happen, indicates improper concurrent modification
5413                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
5414                }
5415                if (topRccChange) {
5416                    // no more RCC for the RCD, check for potential refresh of the remote controls
5417                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
5418                }
5419            }
5420        }
5421    }
5422
5423    /**
5424     * The remote control displays.
5425     * Access synchronized on mRCStack
5426     * NOTE: Only one IRemoteControlDisplay supported in this implementation
5427     */
5428    private IRemoteControlDisplay mRcDisplay;
5429    private RcDisplayDeathHandler mRcDisplayDeathHandler;
5430    private int mArtworkExpectedWidth = -1;
5431    private int mArtworkExpectedHeight = -1;
5432    /**
5433     * Inner class to monitor remote control display deaths, and unregister them from the list
5434     * of displays if necessary.
5435     */
5436    private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
5437        private IBinder mCb; // To be notified of client's death
5438
5439        public RcDisplayDeathHandler(IBinder b) {
5440            if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
5441            mCb = b;
5442        }
5443
5444        public void binderDied() {
5445            synchronized(mRCStack) {
5446                Log.w(TAG, "RemoteControl: display died");
5447                mRcDisplay = null;
5448            }
5449        }
5450
5451        public void unlinkToRcDisplayDeath() {
5452            if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
5453            try {
5454                mCb.unlinkToDeath(this, 0);
5455            } catch (java.util.NoSuchElementException e) {
5456                // not much we can do here, the display was being unregistered anyway
5457                Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
5458                e.printStackTrace();
5459            }
5460        }
5461
5462    }
5463
5464    private void rcDisplay_stopDeathMonitor_syncRcStack() {
5465        if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
5466            // we had a display before, stop monitoring its death
5467            mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
5468        }
5469    }
5470
5471    private void rcDisplay_startDeathMonitor_syncRcStack() {
5472        if (mRcDisplay != null) {
5473            // new non-null display, monitor its death
5474            IBinder b = mRcDisplay.asBinder();
5475            mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
5476            try {
5477                b.linkToDeath(mRcDisplayDeathHandler, 0);
5478            } catch (RemoteException e) {
5479                // remote control display is DOA, disqualify it
5480                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
5481                mRcDisplay = null;
5482            }
5483        }
5484    }
5485
5486    /**
5487     * Register an IRemoteControlDisplay.
5488     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
5489     * at the top of the stack to update the new display with its information.
5490     * Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
5491     * @param rcd the IRemoteControlDisplay to register. No effect if null.
5492     */
5493    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
5494        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
5495        synchronized(mAudioFocusLock) {
5496            synchronized(mRCStack) {
5497                if ((mRcDisplay == rcd) || (rcd == null)) {
5498                    return;
5499                }
5500                // if we had a display before, stop monitoring its death
5501                rcDisplay_stopDeathMonitor_syncRcStack();
5502                mRcDisplay = rcd;
5503                // new display, start monitoring its death
5504                rcDisplay_startDeathMonitor_syncRcStack();
5505
5506                // let all the remote control clients know there is a new display, so the remote
5507                //   control stack traversal order doesn't matter.
5508                // No need to unplug the previous because we only support one display
5509                // and the clients don't track the death of the display
5510                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5511                while(stackIterator.hasNext()) {
5512                    RemoteControlStackEntry rcse = stackIterator.next();
5513                    if(rcse.mRcClient != null) {
5514                        try {
5515                            rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
5516                        } catch (RemoteException e) {
5517                            Log.e(TAG, "Error connecting remote control display to client: " + e);
5518                            e.printStackTrace();
5519                        }
5520                    }
5521                }
5522
5523                // we have a new display, of which all the clients are now aware: have it be updated
5524                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
5525            }
5526        }
5527    }
5528
5529    /**
5530     * Unregister an IRemoteControlDisplay.
5531     * Since only one IRemoteControlDisplay is supported, this has no effect if the one to
5532     *    unregister is not the current one.
5533     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
5534     */
5535    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
5536        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
5537        synchronized(mRCStack) {
5538            // only one display here, so you can only unregister the current display
5539            if ((rcd == null) || (rcd != mRcDisplay)) {
5540                if (DEBUG_RC) Log.w(TAG, "    trying to unregister unregistered RCD");
5541                return;
5542            }
5543            // if we had a display before, stop monitoring its death
5544            rcDisplay_stopDeathMonitor_syncRcStack();
5545            mRcDisplay = null;
5546
5547            // disconnect this remote control display from all the clients, so the remote
5548            //   control stack traversal order doesn't matter
5549            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5550            while(stackIterator.hasNext()) {
5551                RemoteControlStackEntry rcse = stackIterator.next();
5552                if(rcse.mRcClient != null) {
5553                    try {
5554                        rcse.mRcClient.unplugRemoteControlDisplay(rcd);
5555                    } catch (RemoteException e) {
5556                        Log.e(TAG, "Error disconnecting remote control display to client: " + e);
5557                        e.printStackTrace();
5558                    }
5559                }
5560            }
5561        }
5562    }
5563
5564    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
5565        synchronized(mRCStack) {
5566            // NOTE: Only one IRemoteControlDisplay supported in this implementation
5567            mArtworkExpectedWidth = w;
5568            mArtworkExpectedHeight = h;
5569        }
5570    }
5571
5572    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
5573        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
5574                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
5575    }
5576
5577    // handler for MSG_RCC_NEW_PLAYBACK_INFO
5578    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
5579        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
5580                ", what=" + key + ",val=" + value + ")");
5581        synchronized(mRCStack) {
5582            // iterating from top of stack as playback information changes are more likely
5583            //   on entries at the top of the remote control stack
5584            try {
5585                for (int index = mRCStack.size()-1; index >= 0; index--) {
5586                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
5587                    if (rcse.mRccId == rccId) {
5588                        switch (key) {
5589                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
5590                                rcse.mPlaybackType = value;
5591                                postReevaluateRemote();
5592                                break;
5593                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
5594                                rcse.mPlaybackVolume = value;
5595                                synchronized (mMainRemote) {
5596                                    if (rccId == mMainRemote.mRccId) {
5597                                        mMainRemote.mVolume = value;
5598                                        mVolumePanel.postHasNewRemotePlaybackInfo();
5599                                    }
5600                                }
5601                                break;
5602                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
5603                                rcse.mPlaybackVolumeMax = value;
5604                                synchronized (mMainRemote) {
5605                                    if (rccId == mMainRemote.mRccId) {
5606                                        mMainRemote.mVolumeMax = value;
5607                                        mVolumePanel.postHasNewRemotePlaybackInfo();
5608                                    }
5609                                }
5610                                break;
5611                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
5612                                rcse.mPlaybackVolumeHandling = value;
5613                                synchronized (mMainRemote) {
5614                                    if (rccId == mMainRemote.mRccId) {
5615                                        mMainRemote.mVolumeHandling = value;
5616                                        mVolumePanel.postHasNewRemotePlaybackInfo();
5617                                    }
5618                                }
5619                                break;
5620                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
5621                                rcse.mPlaybackStream = value;
5622                                break;
5623                            case RemoteControlClient.PLAYBACKINFO_PLAYSTATE:
5624                                rcse.mPlaybackState = value;
5625                                synchronized (mMainRemote) {
5626                                    if (rccId == mMainRemote.mRccId) {
5627                                        mMainRemoteIsActive = isPlaystateActive(value);
5628                                        postReevaluateRemote();
5629                                    }
5630                                }
5631                                break;
5632                            default:
5633                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
5634                                break;
5635                        }
5636                        return;
5637                    }
5638                }//for
5639            } catch (ArrayIndexOutOfBoundsException e) {
5640                // not expected to happen, indicates improper concurrent modification
5641                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
5642            }
5643        }
5644    }
5645
5646    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
5647        sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
5648                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
5649    }
5650
5651    // handler for MSG_RCC_NEW_VOLUME_OBS
5652    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
5653        synchronized(mRCStack) {
5654            // The stack traversal order doesn't matter because there is only one stack entry
5655            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
5656            //  ID has been found.
5657            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
5658            //  at the top of the stack
5659            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5660            while(stackIterator.hasNext()) {
5661                RemoteControlStackEntry rcse = stackIterator.next();
5662                if (rcse.mRccId == rccId) {
5663                    rcse.mRemoteVolumeObs = rvo;
5664                    break;
5665                }
5666            }
5667        }
5668    }
5669
5670    /**
5671     * Checks if a remote client is active on the supplied stream type. Update the remote stream
5672     * volume state if found and playing
5673     * @param streamType
5674     * @return false if no remote playing is currently playing
5675     */
5676    private boolean checkUpdateRemoteStateIfActive(int streamType) {
5677        synchronized(mRCStack) {
5678            // iterating from top of stack as active playback is more likely on entries at the top
5679            try {
5680                for (int index = mRCStack.size()-1; index >= 0; index--) {
5681                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
5682                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
5683                            && isPlaystateActive(rcse.mPlaybackState)
5684                            && (rcse.mPlaybackStream == streamType)) {
5685                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
5686                                + ", vol =" + rcse.mPlaybackVolume);
5687                        synchronized (mMainRemote) {
5688                            mMainRemote.mRccId = rcse.mRccId;
5689                            mMainRemote.mVolume = rcse.mPlaybackVolume;
5690                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
5691                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
5692                            mMainRemoteIsActive = true;
5693                        }
5694                        return true;
5695                    }
5696                }
5697            } catch (ArrayIndexOutOfBoundsException e) {
5698                // not expected to happen, indicates improper concurrent modification
5699                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
5700            }
5701        }
5702        synchronized (mMainRemote) {
5703            mMainRemoteIsActive = false;
5704        }
5705        return false;
5706    }
5707
5708    /**
5709     * Returns true if the given playback state is considered "active", i.e. it describes a state
5710     * where playback is happening, or about to
5711     * @param playState the playback state to evaluate
5712     * @return true if active, false otherwise (inactive or unknown)
5713     */
5714    private static boolean isPlaystateActive(int playState) {
5715        switch (playState) {
5716            case RemoteControlClient.PLAYSTATE_PLAYING:
5717            case RemoteControlClient.PLAYSTATE_BUFFERING:
5718            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
5719            case RemoteControlClient.PLAYSTATE_REWINDING:
5720            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
5721            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
5722                return true;
5723            default:
5724                return false;
5725        }
5726    }
5727
5728    private void adjustRemoteVolume(int streamType, int direction, int flags) {
5729        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
5730        boolean volFixed = false;
5731        synchronized (mMainRemote) {
5732            if (!mMainRemoteIsActive) {
5733                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
5734                return;
5735            }
5736            rccId = mMainRemote.mRccId;
5737            volFixed = (mMainRemote.mVolumeHandling ==
5738                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
5739        }
5740        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
5741        // we can only notify the remote that volume needs to be updated, and we'll get an async'
5742        // update through setPlaybackInfoForRcc()
5743        if (!volFixed) {
5744            sendVolumeUpdateToRemote(rccId, direction);
5745        }
5746
5747        // fire up the UI
5748        mVolumePanel.postRemoteVolumeChanged(streamType, flags);
5749    }
5750
5751    private void sendVolumeUpdateToRemote(int rccId, int direction) {
5752        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
5753        if (direction == 0) {
5754            // only handling discrete events
5755            return;
5756        }
5757        IRemoteVolumeObserver rvo = null;
5758        synchronized (mRCStack) {
5759            // The stack traversal order doesn't matter because there is only one stack entry
5760            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
5761            //  ID has been found.
5762            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
5763            //  at the top of the stack
5764            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5765            while(stackIterator.hasNext()) {
5766                RemoteControlStackEntry rcse = stackIterator.next();
5767                //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
5768                if (rcse.mRccId == rccId) {
5769                    rvo = rcse.mRemoteVolumeObs;
5770                    break;
5771                }
5772            }
5773        }
5774        if (rvo != null) {
5775            try {
5776                rvo.dispatchRemoteVolumeUpdate(direction, -1);
5777            } catch (RemoteException e) {
5778                Log.e(TAG, "Error dispatching relative volume update", e);
5779            }
5780        }
5781    }
5782
5783    public int getRemoteStreamMaxVolume() {
5784        synchronized (mMainRemote) {
5785            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
5786                return 0;
5787            }
5788            return mMainRemote.mVolumeMax;
5789        }
5790    }
5791
5792    public int getRemoteStreamVolume() {
5793        synchronized (mMainRemote) {
5794            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
5795                return 0;
5796            }
5797            return mMainRemote.mVolume;
5798        }
5799    }
5800
5801    public void setRemoteStreamVolume(int vol) {
5802        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
5803        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
5804        synchronized (mMainRemote) {
5805            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
5806                return;
5807            }
5808            rccId = mMainRemote.mRccId;
5809        }
5810        IRemoteVolumeObserver rvo = null;
5811        synchronized (mRCStack) {
5812            // The stack traversal order doesn't matter because there is only one stack entry
5813            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
5814            //  ID has been found.
5815            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
5816            //  at the top of the stack
5817            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5818            while(stackIterator.hasNext()) {
5819                RemoteControlStackEntry rcse = stackIterator.next();
5820                if (rcse.mRccId == rccId) {
5821                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
5822                    rvo = rcse.mRemoteVolumeObs;
5823                    break;
5824                }
5825            }
5826        }
5827        if (rvo != null) {
5828            try {
5829                rvo.dispatchRemoteVolumeUpdate(0, vol);
5830            } catch (RemoteException e) {
5831                Log.e(TAG, "Error dispatching absolute volume update", e);
5832            }
5833        }
5834    }
5835
5836    /**
5837     * Call to make AudioService reevaluate whether it's in a mode where remote players should
5838     * have their volume controlled. In this implementation this is only to reset whether
5839     * VolumePanel should display remote volumes
5840     */
5841    private void postReevaluateRemote() {
5842        sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
5843    }
5844
5845    private void onReevaluateRemote() {
5846        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
5847        // is there a registered RemoteControlClient that is handling remote playback
5848        boolean hasRemotePlayback = false;
5849        synchronized (mRCStack) {
5850            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
5851            //   traversal order doesn't matter
5852            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
5853            while(stackIterator.hasNext()) {
5854                RemoteControlStackEntry rcse = stackIterator.next();
5855                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
5856                    hasRemotePlayback = true;
5857                    break;
5858                }
5859            }
5860        }
5861        synchronized (mMainRemote) {
5862            if (mHasRemotePlayback != hasRemotePlayback) {
5863                mHasRemotePlayback = hasRemotePlayback;
5864                mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback);
5865            }
5866        }
5867    }
5868
5869    //==========================================================================================
5870    // Device orientation
5871    //==========================================================================================
5872    /**
5873     * Handles device configuration changes that may map to a change in the orientation.
5874     * This feature is optional, and is defined by the definition and value of the
5875     * "ro.audio.monitorOrientation" system property.
5876     */
5877    private void handleConfigurationChanged(Context context) {
5878        try {
5879            // reading new orientation "safely" (i.e. under try catch) in case anything
5880            // goes wrong when obtaining resources and configuration
5881            Configuration config = context.getResources().getConfiguration();
5882            if (mMonitorOrientation) {
5883                int newOrientation = config.orientation;
5884                if (newOrientation != mDeviceOrientation) {
5885                    mDeviceOrientation = newOrientation;
5886                    setOrientationForAudioSystem();
5887                }
5888            }
5889            sendMsg(mAudioHandler,
5890                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5891                    SENDMSG_REPLACE,
5892                    0,
5893                    0,
5894                    null,
5895                    0);
5896
5897            boolean cameraSoundForced = mContext.getResources().getBoolean(
5898                    com.android.internal.R.bool.config_camera_sound_forced);
5899            synchronized (mSettingsLock) {
5900                synchronized (mCameraSoundForced) {
5901                    if (cameraSoundForced != mCameraSoundForced) {
5902                        mCameraSoundForced = cameraSoundForced;
5903
5904                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5905                        if (cameraSoundForced) {
5906                            s.setAllIndexesToMax();
5907                            mRingerModeAffectedStreams &=
5908                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5909                        } else {
5910                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
5911                                            false /*lastAudible*/);
5912                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM],
5913                                            true /*lastAudible*/);
5914                            mRingerModeAffectedStreams |=
5915                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5916                        }
5917                        // take new state into account for streams muted by ringer mode
5918                        setRingerModeInt(getRingerMode(), false);
5919
5920                        sendMsg(mAudioHandler,
5921                                MSG_SET_FORCE_USE,
5922                                SENDMSG_QUEUE,
5923                                AudioSystem.FOR_SYSTEM,
5924                                cameraSoundForced ?
5925                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5926                                null,
5927                                0);
5928
5929                        sendMsg(mAudioHandler,
5930                                MSG_SET_ALL_VOLUMES,
5931                                SENDMSG_QUEUE,
5932                                0,
5933                                0,
5934                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5935                    }
5936                }
5937            }
5938        } catch (Exception e) {
5939            Log.e(TAG, "Error retrieving device orientation: " + e);
5940        }
5941    }
5942
5943    private void setOrientationForAudioSystem() {
5944        switch (mDeviceOrientation) {
5945            case Configuration.ORIENTATION_LANDSCAPE:
5946                //Log.i(TAG, "orientation is landscape");
5947                AudioSystem.setParameters("orientation=landscape");
5948                break;
5949            case Configuration.ORIENTATION_PORTRAIT:
5950                //Log.i(TAG, "orientation is portrait");
5951                AudioSystem.setParameters("orientation=portrait");
5952                break;
5953            case Configuration.ORIENTATION_SQUARE:
5954                //Log.i(TAG, "orientation is square");
5955                AudioSystem.setParameters("orientation=square");
5956                break;
5957            case Configuration.ORIENTATION_UNDEFINED:
5958                //Log.i(TAG, "orientation is undefined");
5959                AudioSystem.setParameters("orientation=undefined");
5960                break;
5961            default:
5962                Log.e(TAG, "Unknown orientation");
5963        }
5964    }
5965
5966
5967    // Handles request to override default use of A2DP for media.
5968    public void setBluetoothA2dpOnInt(boolean on) {
5969        synchronized (mBluetoothA2dpEnabledLock) {
5970            mBluetoothA2dpEnabled = on;
5971            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5972            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
5973                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5974        }
5975    }
5976
5977    @Override
5978    public void setRingtonePlayer(IRingtonePlayer player) {
5979        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5980        mRingtonePlayer = player;
5981    }
5982
5983    @Override
5984    public IRingtonePlayer getRingtonePlayer() {
5985        return mRingtonePlayer;
5986    }
5987
5988    @Override
5989    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5990        synchronized (mCurAudioRoutes) {
5991            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5992            mRoutesObservers.register(observer);
5993            return routes;
5994        }
5995    }
5996
5997
5998    //==========================================================================================
5999    // Safe media volume management.
6000    // MUSIC stream volume level is limited when headphones are connected according to safety
6001    // regulation. When the user attempts to raise the volume above the limit, a warning is
6002    // displayed and the user has to acknowlegde before the volume is actually changed.
6003    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
6004    // property. Platforms with a different limit must set this property accordingly in their
6005    // overlay.
6006    //==========================================================================================
6007
6008    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
6009    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
6010    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
6011    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
6012    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
6013    // (when user opts out).
6014    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
6015    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
6016    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
6017    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
6018    private Integer mSafeMediaVolumeState;
6019
6020    private int mMcc = 0;
6021    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
6022    private int mSafeMediaVolumeIndex;
6023    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
6024    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
6025                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
6026    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
6027    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
6028    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
6029    private int mMusicActiveMs;
6030    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
6031    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
6032    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
6033
6034    private void setSafeMediaVolumeEnabled(boolean on) {
6035        synchronized (mSafeMediaVolumeState) {
6036            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
6037                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
6038                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
6039                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
6040                    enforceSafeMediaVolume();
6041                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
6042                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
6043                    mMusicActiveMs = 0;
6044                    sendMsg(mAudioHandler,
6045                            MSG_CHECK_MUSIC_ACTIVE,
6046                            SENDMSG_REPLACE,
6047                            0,
6048                            0,
6049                            null,
6050                            MUSIC_ACTIVE_POLL_PERIOD_MS);
6051                }
6052            }
6053        }
6054    }
6055
6056    private void enforceSafeMediaVolume() {
6057        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
6058        boolean lastAudible = (streamState.muteCount() != 0);
6059        int devices = mSafeMediaVolumeDevices;
6060        int i = 0;
6061
6062        while (devices != 0) {
6063            int device = 1 << i++;
6064            if ((device & devices) == 0) {
6065                continue;
6066            }
6067            int index = streamState.getIndex(device, lastAudible);
6068            if (index > mSafeMediaVolumeIndex) {
6069                if (lastAudible) {
6070                    streamState.setLastAudibleIndex(mSafeMediaVolumeIndex, device);
6071                    sendMsg(mAudioHandler,
6072                            MSG_PERSIST_VOLUME,
6073                            SENDMSG_QUEUE,
6074                            PERSIST_LAST_AUDIBLE,
6075                            device,
6076                            streamState,
6077                            PERSIST_DELAY);
6078                } else {
6079                    streamState.setIndex(mSafeMediaVolumeIndex, device, true);
6080                    sendMsg(mAudioHandler,
6081                            MSG_SET_DEVICE_VOLUME,
6082                            SENDMSG_QUEUE,
6083                            device,
6084                            0,
6085                            streamState,
6086                            0);
6087                }
6088            }
6089            devices &= ~device;
6090        }
6091    }
6092
6093    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
6094        synchronized (mSafeMediaVolumeState) {
6095            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
6096                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
6097                    ((device & mSafeMediaVolumeDevices) != 0) &&
6098                    (index > mSafeMediaVolumeIndex)) {
6099                return false;
6100            }
6101            return true;
6102        }
6103    }
6104
6105    public void disableSafeMediaVolume() {
6106        synchronized (mSafeMediaVolumeState) {
6107            setSafeMediaVolumeEnabled(false);
6108            if (mPendingVolumeCommand != null) {
6109                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
6110                                  mPendingVolumeCommand.mIndex,
6111                                  mPendingVolumeCommand.mFlags,
6112                                  mPendingVolumeCommand.mDevice);
6113                mPendingVolumeCommand = null;
6114            }
6115        }
6116    }
6117
6118
6119    //==========================================================================================
6120    // Camera shutter sound policy.
6121    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
6122    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
6123    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
6124    //==========================================================================================
6125
6126    // cached value of com.android.internal.R.bool.config_camera_sound_forced
6127    private Boolean mCameraSoundForced;
6128
6129    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
6130    public boolean isCameraSoundForced() {
6131        synchronized (mCameraSoundForced) {
6132            return mCameraSoundForced;
6133        }
6134    }
6135
6136    private static final String[] RINGER_MODE_NAMES = new String[] {
6137            "SILENT",
6138            "VIBRATE",
6139            "NORMAL"
6140    };
6141
6142    private void dumpRingerMode(PrintWriter pw) {
6143        pw.println("\nRinger mode: ");
6144        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
6145        pw.print("- ringer mode affected streams = 0x");
6146        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
6147        pw.print("- ringer mode muted streams = 0x");
6148        pw.println(Integer.toHexString(mRingerModeMutedStreams));
6149    }
6150
6151    @Override
6152    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
6153        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
6154
6155        dumpFocusStack(pw);
6156        dumpRCStack(pw);
6157        dumpRCCStack(pw);
6158        dumpStreamStates(pw);
6159        dumpRingerMode(pw);
6160        pw.println("\nAudio routes:");
6161        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
6162        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
6163    }
6164}
6165