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