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