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