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