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