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