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