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