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.ActivityManager;
26import android.app.ActivityManagerNative;
27import android.app.AppOpsManager;
28import android.app.KeyguardManager;
29import android.app.PendingIntent;
30import android.app.PendingIntent.CanceledException;
31import android.bluetooth.BluetoothA2dp;
32import android.bluetooth.BluetoothAdapter;
33import android.bluetooth.BluetoothClass;
34import android.bluetooth.BluetoothDevice;
35import android.bluetooth.BluetoothHeadset;
36import android.bluetooth.BluetoothProfile;
37import android.content.ActivityNotFoundException;
38import android.content.BroadcastReceiver;
39import android.content.ComponentName;
40import android.content.ContentResolver;
41import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
44import android.content.pm.PackageManager;
45import android.content.res.Configuration;
46import android.content.res.Resources;
47import android.content.res.XmlResourceParser;
48import android.database.ContentObserver;
49import android.media.MediaPlayer.OnCompletionListener;
50import android.media.MediaPlayer.OnErrorListener;
51import android.net.Uri;
52import android.os.Binder;
53import android.os.Build;
54import android.os.Bundle;
55import android.os.Environment;
56import android.os.Handler;
57import android.os.IBinder;
58import android.os.Looper;
59import android.os.Message;
60import android.os.PowerManager;
61import android.os.RemoteCallbackList;
62import android.os.RemoteException;
63import android.os.ServiceManager;
64import android.os.SystemProperties;
65import android.os.UserHandle;
66import android.os.Vibrator;
67import android.provider.Settings;
68import android.provider.Settings.System;
69import android.speech.RecognizerIntent;
70import android.telephony.PhoneStateListener;
71import android.telephony.TelephonyManager;
72import android.text.TextUtils;
73import android.util.Log;
74import android.view.KeyEvent;
75import android.view.Surface;
76import android.view.VolumePanel;
77import android.view.WindowManager;
78
79import com.android.internal.telephony.ITelephony;
80import com.android.internal.util.XmlUtils;
81
82import org.xmlpull.v1.XmlPullParserException;
83
84import java.io.FileDescriptor;
85import java.io.IOException;
86import java.io.PrintWriter;
87import java.lang.reflect.Field;
88import java.util.ArrayList;
89import java.util.concurrent.ConcurrentHashMap;
90import java.util.HashMap;
91import java.util.HashSet;
92import java.util.Iterator;
93import java.util.List;
94import java.util.Map;
95import java.util.NoSuchElementException;
96import java.util.Set;
97import java.util.Stack;
98
99/**
100 * The implementation of the volume manager service.
101 * <p>
102 * This implementation focuses on delivering a responsive UI. Most methods are
103 * asynchronous to external calls. For example, the task of setting a volume
104 * will update our internal state, but in a separate thread will set the system
105 * volume and later persist to the database. Similarly, setting the ringer mode
106 * will update the state and broadcast a change and in a separate thread later
107 * persist the ringer mode.
108 *
109 * @hide
110 */
111public class AudioService extends IAudioService.Stub {
112
113    private static final String TAG = "AudioService";
114
115    /** Debug remote control client/display feature */
116    protected static final boolean DEBUG_RC = false;
117    /** Debug volumes */
118    protected static final boolean DEBUG_VOL = false;
119
120    /** How long to delay before persisting a change in volume/ringer mode. */
121    private static final int PERSIST_DELAY = 500;
122
123    private final Context mContext;
124    private final ContentResolver mContentResolver;
125    private final AppOpsManager mAppOps;
126    private final boolean mVoiceCapable;
127
128    /** The UI */
129    private VolumePanel mVolumePanel;
130
131    // sendMsg() flags
132    /** If the msg is already queued, replace it with this one. */
133    private static final int SENDMSG_REPLACE = 0;
134    /** If the msg is already queued, ignore this one and leave the old. */
135    private static final int SENDMSG_NOOP = 1;
136    /** If the msg is already queued, queue this one and leave the old. */
137    private static final int SENDMSG_QUEUE = 2;
138
139    // AudioHandler messages
140    private static final int MSG_SET_DEVICE_VOLUME = 0;
141    private static final int MSG_PERSIST_VOLUME = 1;
142    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
143    private static final int MSG_PERSIST_RINGER_MODE = 3;
144    private static final int MSG_MEDIA_SERVER_DIED = 4;
145    private static final int MSG_PLAY_SOUND_EFFECT = 5;
146    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
147    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
148    private static final int MSG_SET_FORCE_USE = 8;
149    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
150    private static final int MSG_SET_ALL_VOLUMES = 10;
151    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
152    private static final int MSG_REPORT_NEW_ROUTES = 12;
153    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
154    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
155    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
156    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
157    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
158    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
159    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
160    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
161    // start of messages handled under wakelock
162    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
163    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
164    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
165    private static final int MSG_SET_A2DP_CONNECTION_STATE = 101;
166    // end of messages handled under wakelock
167
168    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
169    // Timeout for connection to bluetooth headset service
170    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
171
172    /** @see AudioSystemThread */
173    private AudioSystemThread mAudioSystemThread;
174    /** @see AudioHandler */
175    private AudioHandler mAudioHandler;
176    /** @see VolumeStreamState */
177    private VolumeStreamState[] mStreamStates;
178    private SettingsObserver mSettingsObserver;
179
180    private int mMode = AudioSystem.MODE_NORMAL;
181    // protects mRingerMode
182    private final Object mSettingsLock = new Object();
183
184    private SoundPool mSoundPool;
185    private final Object mSoundEffectsLock = new Object();
186    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
187
188    // Internally master volume is a float in the 0.0 - 1.0 range,
189    // but to support integer based AudioManager API we translate it to 0 - 100
190    private static final int MAX_MASTER_VOLUME = 100;
191
192    // Maximum volume adjust steps allowed in a single batch call.
193    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
194
195    /* Sound effect file names  */
196    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
197    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
198
199    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
200     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
201     * uses soundpool (second column) */
202    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
203
204   /** @hide Maximum volume index values for audio streams */
205    private static final int[] MAX_STREAM_VOLUME = new int[] {
206        5,  // STREAM_VOICE_CALL
207        7,  // STREAM_SYSTEM
208        7,  // STREAM_RING
209        15, // STREAM_MUSIC
210        7,  // STREAM_ALARM
211        7,  // STREAM_NOTIFICATION
212        15, // STREAM_BLUETOOTH_SCO
213        7,  // STREAM_SYSTEM_ENFORCED
214        15, // STREAM_DTMF
215        15  // STREAM_TTS
216    };
217    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
218     * of another stream: This avoids multiplying the volume settings for hidden
219     * stream types that follow other stream behavior for volume settings
220     * NOTE: do not create loops in aliases!
221     * Some streams alias to different streams according to device category (phone or tablet) or
222     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
223     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
224     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
225    private final int[] STREAM_VOLUME_ALIAS = new int[] {
226        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
227        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
228        AudioSystem.STREAM_RING,            // STREAM_RING
229        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
230        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
231        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
232        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
233        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
234        AudioSystem.STREAM_RING,            // STREAM_DTMF
235        AudioSystem.STREAM_MUSIC            // STREAM_TTS
236    };
237    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
238        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
239        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
240        AudioSystem.STREAM_RING,            // STREAM_RING
241        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
242        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
243        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
244        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
245        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
246        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
247        AudioSystem.STREAM_MUSIC            // STREAM_TTS
248    };
249    private int[] mStreamVolumeAlias;
250
251    /**
252     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
253     * after mapping through mStreamVolumeAlias.
254     */
255    private static final int[] STEAM_VOLUME_OPS = new int[] {
256        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
257        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
258        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
259        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
260        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
261        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
262        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
263        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
264        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
265        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
266    };
267
268    private final boolean mUseFixedVolume;
269
270    // stream names used by dumpStreamStates()
271    private final String[] STREAM_NAMES = new String[] {
272            "STREAM_VOICE_CALL",
273            "STREAM_SYSTEM",
274            "STREAM_RING",
275            "STREAM_MUSIC",
276            "STREAM_ALARM",
277            "STREAM_NOTIFICATION",
278            "STREAM_BLUETOOTH_SCO",
279            "STREAM_SYSTEM_ENFORCED",
280            "STREAM_DTMF",
281            "STREAM_TTS"
282    };
283
284    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
285        public void onError(int error) {
286            switch (error) {
287            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
288                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
289                        SENDMSG_NOOP, 0, 0, null, 0);
290                break;
291            default:
292                break;
293            }
294        }
295    };
296
297    /**
298     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
299     * {@link AudioManager#RINGER_MODE_SILENT}, or
300     * {@link AudioManager#RINGER_MODE_VIBRATE}.
301     */
302    // protected by mSettingsLock
303    private int mRingerMode;
304
305    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
306    private int mRingerModeAffectedStreams = 0;
307
308    // Streams currently muted by ringer mode
309    private int mRingerModeMutedStreams;
310
311    /** @see System#MUTE_STREAMS_AFFECTED */
312    private int mMuteAffectedStreams;
313
314    /**
315     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
316     * mVibrateSetting is just maintained during deprecation period but vibration policy is
317     * now only controlled by mHasVibrator and mRingerMode
318     */
319    private int mVibrateSetting;
320
321    // Is there a vibrator
322    private final boolean mHasVibrator;
323
324    // Broadcast receiver for device connections intent broadcasts
325    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
326
327    // Devices currently connected
328    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
329
330    // Forced device usage for communications
331    private int mForcedUseForComm;
332
333    // True if we have master volume support
334    private final boolean mUseMasterVolume;
335
336    private final int[] mMasterVolumeRamp;
337
338    // List of binder death handlers for setMode() client processes.
339    // The last process to have called setMode() is at the top of the list.
340    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
341
342    // List of clients having issued a SCO start request
343    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
344
345    // BluetoothHeadset API to control SCO connection
346    private BluetoothHeadset mBluetoothHeadset;
347
348    // Bluetooth headset device
349    private BluetoothDevice mBluetoothHeadsetDevice;
350
351    // Indicate if SCO audio connection is currently active and if the initiator is
352    // audio service (internal) or bluetooth headset (external)
353    private int mScoAudioState;
354    // SCO audio state is not active
355    private static final int SCO_STATE_INACTIVE = 0;
356    // SCO audio activation request waiting for headset service to connect
357    private static final int SCO_STATE_ACTIVATE_REQ = 1;
358    // SCO audio state is active or starting due to a request from AudioManager API
359    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
360    // SCO audio deactivation request waiting for headset service to connect
361    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
362
363    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
364    // in call audio)
365    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
366    // Deactivation request for all SCO connections (initiated by audio mode change)
367    // waiting for headset service to connect
368    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
369
370    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
371    // originated from an app targeting an API version before JB MR2 and raw audio after that.
372    private int mScoAudioMode;
373    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
374    private static final int SCO_MODE_VIRTUAL_CALL = 0;
375    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
376    private static final int SCO_MODE_RAW = 1;
377
378    // Current connection state indicated by bluetooth headset
379    private int mScoConnectionState;
380
381    // true if boot sequence has been completed
382    private boolean mBootCompleted;
383    // listener for SoundPool sample load completion indication
384    private SoundPoolCallback mSoundPoolCallBack;
385    // thread for SoundPool listener
386    private SoundPoolListenerThread mSoundPoolListenerThread;
387    // message looper for SoundPool listener
388    private Looper mSoundPoolLooper = null;
389    // volume applied to sound played with playSoundEffect()
390    private static int sSoundEffectVolumeDb;
391    // getActiveStreamType() will return:
392    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
393    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
394    // stopped
395    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
396    // previous volume adjustment direction received by checkForRingerModeChange()
397    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
398    // Keyguard manager proxy
399    private KeyguardManager mKeyguardManager;
400    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
401    // is controlled by Vol keys.
402    private int  mVolumeControlStream = -1;
403    private final Object mForceControlStreamLock = new Object();
404    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
405    // server process so in theory it is not necessary to monitor the client death.
406    // However it is good to be ready for future evolutions.
407    private ForceControlStreamClient mForceControlStreamClient = null;
408    // Used to play ringtones outside system_server
409    private volatile IRingtonePlayer mRingtonePlayer;
410
411    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
412    private int mDeviceRotation = Surface.ROTATION_0;
413
414    // Request to override default use of A2DP for media.
415    private boolean mBluetoothA2dpEnabled;
416    private final Object mBluetoothA2dpEnabledLock = new Object();
417
418    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
419    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
420    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
421            = new RemoteCallbackList<IAudioRoutesObserver>();
422
423    /**
424     * A fake stream type to match the notion of remote media playback
425     */
426    public final static int STREAM_REMOTE_MUSIC = -200;
427
428    // Devices for which the volume is fixed and VolumePanel slider should be disabled
429    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL |
430            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
431            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
432            AudioSystem.DEVICE_OUT_ALL_USB;
433
434    // TODO merge orientation and rotation
435    private final boolean mMonitorOrientation;
436    private final boolean mMonitorRotation;
437
438    private boolean mDockAudioMediaEnabled = true;
439
440    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
441
442    // Used when safe volume warning message display is requested by setStreamVolume(). In this
443    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
444    // and used later when/if disableSafeMediaVolume() is called.
445    private StreamVolumeCommand mPendingVolumeCommand;
446
447    private PowerManager.WakeLock mAudioEventWakeLock;
448
449    private final MediaFocusControl mMediaFocusControl;
450
451    // Reference to BluetoothA2dp to query for AbsoluteVolume.
452    private BluetoothA2dp mA2dp;
453    private final Object mA2dpAvrcpLock = new Object();
454    // If absolute volume is supported in AVRCP device
455    private boolean mAvrcpAbsVolSupported = false;
456
457    ///////////////////////////////////////////////////////////////////////////
458    // Construction
459    ///////////////////////////////////////////////////////////////////////////
460
461    /** @hide */
462    public AudioService(Context context) {
463        mContext = context;
464        mContentResolver = context.getContentResolver();
465        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
466        mVoiceCapable = mContext.getResources().getBoolean(
467                com.android.internal.R.bool.config_voice_capable);
468
469        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
470        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
471
472        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
473        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
474
475       // Intialized volume
476        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
477            "ro.config.vc_call_vol_steps",
478           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
479
480        sSoundEffectVolumeDb = context.getResources().getInteger(
481                com.android.internal.R.integer.config_soundEffectVolumeDb);
482
483        mVolumePanel = new VolumePanel(context, this);
484        mForcedUseForComm = AudioSystem.FORCE_NONE;
485
486        createAudioSystemThread();
487
488        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
489                mContext, /*VolumeController*/ mVolumePanel, this);
490
491        AudioSystem.setErrorCallback(mAudioSystemCallback);
492
493        boolean cameraSoundForced = mContext.getResources().getBoolean(
494                com.android.internal.R.bool.config_camera_sound_forced);
495        mCameraSoundForced = new Boolean(cameraSoundForced);
496        sendMsg(mAudioHandler,
497                MSG_SET_FORCE_USE,
498                SENDMSG_QUEUE,
499                AudioSystem.FOR_SYSTEM,
500                cameraSoundForced ?
501                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
502                null,
503                0);
504
505        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
506                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
507                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
508        // The default safe volume index read here will be replaced by the actual value when
509        // the mcc is read by onConfigureSafeVolume()
510        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
511                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
512
513        mUseFixedVolume = mContext.getResources().getBoolean(
514                com.android.internal.R.bool.config_useFixedVolume);
515
516        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
517        // array initialized by updateStreamVolumeAlias()
518        updateStreamVolumeAlias(false /*updateVolumes*/);
519        readPersistedSettings();
520        mSettingsObserver = new SettingsObserver();
521        createStreamStates();
522
523        readAndSetLowRamDevice();
524
525        // Call setRingerModeInt() to apply correct mute
526        // state on streams affected by ringer mode.
527        mRingerModeMutedStreams = 0;
528        setRingerModeInt(getRingerMode(), false);
529
530        // Register for device connection intent broadcasts.
531        IntentFilter intentFilter =
532                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
533        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
534        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
535        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
536        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
537        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
538        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
539        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
540        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
541
542        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
543        // TODO merge orientation and rotation
544        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
545        if (mMonitorOrientation) {
546            Log.v(TAG, "monitoring device orientation");
547            // initialize orientation in AudioSystem
548            setOrientationForAudioSystem();
549        }
550        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
551        if (mMonitorRotation) {
552            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
553                    .getDefaultDisplay().getRotation();
554            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
555            // initialize rotation in AudioSystem
556            setRotationForAudioSystem();
557        }
558
559        context.registerReceiver(mReceiver, intentFilter);
560
561        mUseMasterVolume = context.getResources().getBoolean(
562                com.android.internal.R.bool.config_useMasterVolume);
563        restoreMasterVolume();
564
565        mMasterVolumeRamp = context.getResources().getIntArray(
566                com.android.internal.R.array.config_masterVolumeRamp);
567
568    }
569
570    private void createAudioSystemThread() {
571        mAudioSystemThread = new AudioSystemThread();
572        mAudioSystemThread.start();
573        waitForAudioHandlerCreation();
574    }
575
576    /** Waits for the volume handler to be created by the other thread. */
577    private void waitForAudioHandlerCreation() {
578        synchronized(this) {
579            while (mAudioHandler == null) {
580                try {
581                    // Wait for mAudioHandler to be set by the other thread
582                    wait();
583                } catch (InterruptedException e) {
584                    Log.e(TAG, "Interrupted while waiting on volume handler.");
585                }
586            }
587        }
588    }
589
590    private void checkAllAliasStreamVolumes() {
591        int numStreamTypes = AudioSystem.getNumStreamTypes();
592        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
593            if (streamType != mStreamVolumeAlias[streamType]) {
594                mStreamStates[streamType].
595                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
596            }
597            // apply stream volume
598            if (!mStreamStates[streamType].isMuted()) {
599                mStreamStates[streamType].applyAllVolumes();
600            }
601        }
602    }
603
604    private void createStreamStates() {
605        int numStreamTypes = AudioSystem.getNumStreamTypes();
606        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
607
608        for (int i = 0; i < numStreamTypes; i++) {
609            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
610        }
611
612        checkAllAliasStreamVolumes();
613    }
614
615    private void dumpStreamStates(PrintWriter pw) {
616        pw.println("\nStream volumes (device: index)");
617        int numStreamTypes = AudioSystem.getNumStreamTypes();
618        for (int i = 0; i < numStreamTypes; i++) {
619            pw.println("- "+STREAM_NAMES[i]+":");
620            mStreamStates[i].dump(pw);
621            pw.println("");
622        }
623        pw.print("\n- mute affected streams = 0x");
624        pw.println(Integer.toHexString(mMuteAffectedStreams));
625    }
626
627
628    private void updateStreamVolumeAlias(boolean updateVolumes) {
629        int dtmfStreamAlias;
630        if (mVoiceCapable) {
631            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
632            dtmfStreamAlias = AudioSystem.STREAM_RING;
633        } else {
634            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
635            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
636        }
637        if (isInCommunication()) {
638            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
639            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
640        } else {
641            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
642        }
643        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
644        if (updateVolumes) {
645            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
646            // apply stream mute states according to new value of mRingerModeAffectedStreams
647            setRingerModeInt(getRingerMode(), false);
648            sendMsg(mAudioHandler,
649                    MSG_SET_ALL_VOLUMES,
650                    SENDMSG_QUEUE,
651                    0,
652                    0,
653                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
654        }
655    }
656
657    private void readDockAudioSettings(ContentResolver cr)
658    {
659        mDockAudioMediaEnabled = Settings.Global.getInt(
660                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
661
662        if (mDockAudioMediaEnabled) {
663            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
664        } else {
665            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
666        }
667
668        sendMsg(mAudioHandler,
669                MSG_SET_FORCE_USE,
670                SENDMSG_QUEUE,
671                AudioSystem.FOR_DOCK,
672                mDockAudioMediaEnabled ?
673                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
674                null,
675                0);
676    }
677
678    private void readPersistedSettings() {
679        final ContentResolver cr = mContentResolver;
680
681        int ringerModeFromSettings =
682                Settings.Global.getInt(
683                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
684        int ringerMode = ringerModeFromSettings;
685        // sanity check in case the settings are restored from a device with incompatible
686        // ringer modes
687        if (!AudioManager.isValidRingerMode(ringerMode)) {
688            ringerMode = AudioManager.RINGER_MODE_NORMAL;
689        }
690        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
691            ringerMode = AudioManager.RINGER_MODE_SILENT;
692        }
693        if (ringerMode != ringerModeFromSettings) {
694            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
695        }
696        if (mUseFixedVolume) {
697            ringerMode = AudioManager.RINGER_MODE_NORMAL;
698        }
699        synchronized(mSettingsLock) {
700            mRingerMode = ringerMode;
701
702            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
703            // are still needed while setVibrateSetting() and getVibrateSetting() are being
704            // deprecated.
705            mVibrateSetting = getValueForVibrateSetting(0,
706                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
707                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
708                                                            : AudioManager.VIBRATE_SETTING_OFF);
709            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
710                                            AudioManager.VIBRATE_TYPE_RINGER,
711                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
712                                                            : AudioManager.VIBRATE_SETTING_OFF);
713
714            updateRingerModeAffectedStreams();
715            readDockAudioSettings(cr);
716        }
717
718        mMuteAffectedStreams = System.getIntForUser(cr,
719                System.MUTE_STREAMS_AFFECTED,
720                ((1 << AudioSystem.STREAM_MUSIC)|
721                 (1 << AudioSystem.STREAM_RING)|
722                 (1 << AudioSystem.STREAM_SYSTEM)),
723                 UserHandle.USER_CURRENT);
724
725        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
726                                                  0, UserHandle.USER_CURRENT) == 1;
727        if (mUseFixedVolume) {
728            masterMute = false;
729            AudioSystem.setMasterVolume(1.0f);
730        }
731        AudioSystem.setMasterMute(masterMute);
732        broadcastMasterMuteStatus(masterMute);
733
734        // Each stream will read its own persisted settings
735
736        // Broadcast the sticky intent
737        broadcastRingerMode(ringerMode);
738
739        // Broadcast vibrate settings
740        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
741        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
742
743        // Restore the default media button receiver from the system settings
744        mMediaFocusControl.restoreMediaButtonReceiver();
745    }
746
747    private int rescaleIndex(int index, int srcStream, int dstStream) {
748        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
749    }
750
751    ///////////////////////////////////////////////////////////////////////////
752    // IPC methods
753    ///////////////////////////////////////////////////////////////////////////
754    /** @see AudioManager#isLocalOrRemoteMusicActive() */
755    public boolean isLocalOrRemoteMusicActive() {
756        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
757            // local / wired / BT playback active
758            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
759            return true;
760        }
761        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
762            // remote "cast-like" playback active
763            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
764            return true;
765        }
766        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
767            // remote submix playback active
768            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
769            return true;
770        }
771        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
772        return false;
773    }
774
775    /** @see AudioManager#adjustVolume(int, int) */
776    public void adjustVolume(int direction, int flags, String callingPackage) {
777        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
778                callingPackage);
779    }
780
781    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
782     *  on streamType: fixed to STREAM_MUSIC */
783    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
784            String callingPackage) {
785        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
786        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
787            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
788        } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
789            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
790        }
791    }
792
793    /** @see AudioManager#adjustVolume(int, int) */
794    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
795            String callingPackage) {
796        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
797        int streamType;
798        if (mVolumeControlStream != -1) {
799            streamType = mVolumeControlStream;
800        } else {
801            streamType = getActiveStreamType(suggestedStreamType);
802        }
803
804        // Play sounds on STREAM_RING only and if lock screen is not on.
805        if ((streamType != STREAM_REMOTE_MUSIC) &&
806                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
807                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
808                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
809            flags &= ~AudioManager.FLAG_PLAY_SOUND;
810        }
811
812        if (streamType == STREAM_REMOTE_MUSIC) {
813            // don't play sounds for remote
814            flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
815            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
816            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
817        } else {
818            adjustStreamVolume(streamType, direction, flags, callingPackage);
819        }
820    }
821
822    /** @see AudioManager#adjustStreamVolume(int, int, int) */
823    public void adjustStreamVolume(int streamType, int direction, int flags,
824            String callingPackage) {
825        if (mUseFixedVolume) {
826            return;
827        }
828        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
829
830        ensureValidDirection(direction);
831        ensureValidStreamType(streamType);
832
833        // use stream type alias here so that streams with same alias have the same behavior,
834        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
835        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
836        int streamTypeAlias = mStreamVolumeAlias[streamType];
837        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
838
839        final int device = getDeviceForStream(streamTypeAlias);
840
841        int aliasIndex = streamState.getIndex(device);
842        boolean adjustVolume = true;
843        int step;
844
845        // skip a2dp absolute volume control request when the device
846        // is not an a2dp device
847        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
848            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
849            return;
850        }
851
852        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
853                callingPackage) != AppOpsManager.MODE_ALLOWED) {
854            return;
855        }
856
857        // reset any pending volume command
858        synchronized (mSafeMediaVolumeState) {
859            mPendingVolumeCommand = null;
860        }
861
862        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
863        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
864               ((device & mFixedVolumeDevices) != 0)) {
865            flags |= AudioManager.FLAG_FIXED_VOLUME;
866
867            // Always toggle between max safe volume and 0 for fixed volume devices where safe
868            // volume is enforced, and max and 0 for the others.
869            // This is simulated by stepping by the full allowed volume range
870            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
871                    (device & mSafeMediaVolumeDevices) != 0) {
872                step = mSafeMediaVolumeIndex;
873            } else {
874                step = streamState.getMaxIndex();
875            }
876            if (aliasIndex != 0) {
877                aliasIndex = step;
878            }
879        } else {
880            // convert one UI step (+/-1) into a number of internal units on the stream alias
881            step = rescaleIndex(10, streamType, streamTypeAlias);
882        }
883
884        // If either the client forces allowing ringer modes for this adjustment,
885        // or the stream type is one that is affected by ringer modes
886        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
887                (streamTypeAlias == getMasterStreamType())) {
888            int ringerMode = getRingerMode();
889            // do not vibrate if already in vibrate mode
890            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
891                flags &= ~AudioManager.FLAG_VIBRATE;
892            }
893            // Check if the ringer mode changes with this volume adjustment. If
894            // it does, it will handle adjusting the volume, so we won't below
895            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
896        }
897
898        int oldIndex = mStreamStates[streamType].getIndex(device);
899
900        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
901
902            // Check if volume update should be send to AVRCP
903            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
904                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
905                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
906                synchronized (mA2dpAvrcpLock) {
907                    if (mA2dp != null && mAvrcpAbsVolSupported) {
908                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
909                    }
910                }
911            }
912
913            if ((direction == AudioManager.ADJUST_RAISE) &&
914                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
915                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
916                mVolumePanel.postDisplaySafeVolumeWarning(flags);
917            } else if (streamState.adjustIndex(direction * step, device)) {
918                // Post message to set system volume (it in turn will post a message
919                // to persist). Do not change volume if stream is muted.
920                sendMsg(mAudioHandler,
921                        MSG_SET_DEVICE_VOLUME,
922                        SENDMSG_QUEUE,
923                        device,
924                        0,
925                        streamState,
926                        0);
927            }
928        }
929        int index = mStreamStates[streamType].getIndex(device);
930        sendVolumeUpdate(streamType, oldIndex, index, flags);
931    }
932
933    /** @see AudioManager#adjustMasterVolume(int, int) */
934    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
935        if (mUseFixedVolume) {
936            return;
937        }
938        ensureValidSteps(steps);
939        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
940        int delta = 0;
941        int numSteps = Math.abs(steps);
942        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
943        for (int i = 0; i < numSteps; ++i) {
944            delta = findVolumeDelta(direction, volume);
945            volume += delta;
946        }
947
948        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
949        setMasterVolume(volume, flags, callingPackage);
950    }
951
952    // StreamVolumeCommand contains the information needed to defer the process of
953    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
954    class StreamVolumeCommand {
955        public final int mStreamType;
956        public final int mIndex;
957        public final int mFlags;
958        public final int mDevice;
959
960        StreamVolumeCommand(int streamType, int index, int flags, int device) {
961            mStreamType = streamType;
962            mIndex = index;
963            mFlags = flags;
964            mDevice = device;
965        }
966    };
967
968    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
969        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
970        // setting volume on master stream type also controls silent mode
971        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
972                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
973            int newRingerMode;
974            if (index == 0) {
975                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
976                                              : AudioManager.RINGER_MODE_SILENT;
977            } else {
978                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
979            }
980            setRingerMode(newRingerMode);
981        }
982    }
983
984    /** @see AudioManager#setStreamVolume(int, int, int) */
985    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
986        if (mUseFixedVolume) {
987            return;
988        }
989
990        ensureValidStreamType(streamType);
991        int streamTypeAlias = mStreamVolumeAlias[streamType];
992        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
993
994        final int device = getDeviceForStream(streamType);
995        int oldIndex;
996
997        // skip a2dp absolute volume control request when the device
998        // is not an a2dp device
999        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1000            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1001            return;
1002        }
1003
1004        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1005                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1006            return;
1007        }
1008
1009        synchronized (mSafeMediaVolumeState) {
1010            // reset any pending volume command
1011            mPendingVolumeCommand = null;
1012
1013            oldIndex = streamState.getIndex(device);
1014
1015            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1016
1017            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1018                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1019                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1020                synchronized (mA2dpAvrcpLock) {
1021                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1022                        mA2dp.setAvrcpAbsoluteVolume(index);
1023                    }
1024                }
1025            }
1026
1027            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1028            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1029                    ((device & mFixedVolumeDevices) != 0)) {
1030                flags |= AudioManager.FLAG_FIXED_VOLUME;
1031
1032                // volume is either 0 or max allowed for fixed volume devices
1033                if (index != 0) {
1034                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1035                            (device & mSafeMediaVolumeDevices) != 0) {
1036                        index = mSafeMediaVolumeIndex;
1037                    } else {
1038                        index = streamState.getMaxIndex();
1039                    }
1040                }
1041            }
1042
1043            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
1044                mVolumePanel.postDisplaySafeVolumeWarning(flags);
1045                mPendingVolumeCommand = new StreamVolumeCommand(
1046                                                    streamType, index, flags, device);
1047            } else {
1048                onSetStreamVolume(streamType, index, flags, device);
1049                index = mStreamStates[streamType].getIndex(device);
1050            }
1051        }
1052        sendVolumeUpdate(streamType, oldIndex, index, flags);
1053    }
1054
1055    /** @see AudioManager#forceVolumeControlStream(int) */
1056    public void forceVolumeControlStream(int streamType, IBinder cb) {
1057        synchronized(mForceControlStreamLock) {
1058            mVolumeControlStream = streamType;
1059            if (mVolumeControlStream == -1) {
1060                if (mForceControlStreamClient != null) {
1061                    mForceControlStreamClient.release();
1062                    mForceControlStreamClient = null;
1063                }
1064            } else {
1065                mForceControlStreamClient = new ForceControlStreamClient(cb);
1066            }
1067        }
1068    }
1069
1070    private class ForceControlStreamClient implements IBinder.DeathRecipient {
1071        private IBinder mCb; // To be notified of client's death
1072
1073        ForceControlStreamClient(IBinder cb) {
1074            if (cb != null) {
1075                try {
1076                    cb.linkToDeath(this, 0);
1077                } catch (RemoteException e) {
1078                    // Client has died!
1079                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1080                    cb = null;
1081                }
1082            }
1083            mCb = cb;
1084        }
1085
1086        public void binderDied() {
1087            synchronized(mForceControlStreamLock) {
1088                Log.w(TAG, "SCO client died");
1089                if (mForceControlStreamClient != this) {
1090                    Log.w(TAG, "unregistered control stream client died");
1091                } else {
1092                    mForceControlStreamClient = null;
1093                    mVolumeControlStream = -1;
1094                }
1095            }
1096        }
1097
1098        public void release() {
1099            if (mCb != null) {
1100                mCb.unlinkToDeath(this, 0);
1101                mCb = null;
1102            }
1103        }
1104    }
1105
1106    private int findVolumeDelta(int direction, int volume) {
1107        int delta = 0;
1108        if (direction == AudioManager.ADJUST_RAISE) {
1109            if (volume == MAX_MASTER_VOLUME) {
1110                return 0;
1111            }
1112            // This is the default value if we make it to the end
1113            delta = mMasterVolumeRamp[1];
1114            // If we're raising the volume move down the ramp array until we
1115            // find the volume we're above and use that groups delta.
1116            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1117                if (volume >= mMasterVolumeRamp[i - 1]) {
1118                    delta = mMasterVolumeRamp[i];
1119                    break;
1120                }
1121            }
1122        } else if (direction == AudioManager.ADJUST_LOWER){
1123            if (volume == 0) {
1124                return 0;
1125            }
1126            int length = mMasterVolumeRamp.length;
1127            // This is the default value if we make it to the end
1128            delta = -mMasterVolumeRamp[length - 1];
1129            // If we're lowering the volume move up the ramp array until we
1130            // find the volume we're below and use the group below it's delta
1131            for (int i = 2; i < length; i += 2) {
1132                if (volume <= mMasterVolumeRamp[i]) {
1133                    delta = -mMasterVolumeRamp[i - 1];
1134                    break;
1135                }
1136            }
1137        }
1138        return delta;
1139    }
1140
1141    private void sendBroadcastToAll(Intent intent) {
1142        final long ident = Binder.clearCallingIdentity();
1143        try {
1144            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1145        } finally {
1146            Binder.restoreCallingIdentity(ident);
1147        }
1148    }
1149
1150    private void sendStickyBroadcastToAll(Intent intent) {
1151        final long ident = Binder.clearCallingIdentity();
1152        try {
1153            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1154        } finally {
1155            Binder.restoreCallingIdentity(ident);
1156        }
1157    }
1158
1159    // UI update and Broadcast Intent
1160    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1161        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
1162            streamType = AudioSystem.STREAM_NOTIFICATION;
1163        }
1164
1165        mVolumePanel.postVolumeChanged(streamType, flags);
1166
1167        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1168            oldIndex = (oldIndex + 5) / 10;
1169            index = (index + 5) / 10;
1170            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1171            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1172            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1173            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1174            sendBroadcastToAll(intent);
1175        }
1176    }
1177
1178    // UI update and Broadcast Intent
1179    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
1180        mVolumePanel.postMasterVolumeChanged(flags);
1181
1182        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1183        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1184        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
1185        sendBroadcastToAll(intent);
1186    }
1187
1188    // UI update and Broadcast Intent
1189    private void sendMasterMuteUpdate(boolean muted, int flags) {
1190        mVolumePanel.postMasterMuteChanged(flags);
1191        broadcastMasterMuteStatus(muted);
1192    }
1193
1194    private void broadcastMasterMuteStatus(boolean muted) {
1195        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1196        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
1197        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1198                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
1199        sendStickyBroadcastToAll(intent);
1200    }
1201
1202    /**
1203     * Sets the stream state's index, and posts a message to set system volume.
1204     * This will not call out to the UI. Assumes a valid stream type.
1205     *
1206     * @param streamType Type of the stream
1207     * @param index Desired volume index of the stream
1208     * @param device the device whose volume must be changed
1209     * @param force If true, set the volume even if the desired volume is same
1210     * as the current volume.
1211     */
1212    private void setStreamVolumeInt(int streamType,
1213                                    int index,
1214                                    int device,
1215                                    boolean force) {
1216        VolumeStreamState streamState = mStreamStates[streamType];
1217
1218        if (streamState.setIndex(index, device) || force) {
1219            // Post message to set system volume (it in turn will post a message
1220            // to persist).
1221            sendMsg(mAudioHandler,
1222                    MSG_SET_DEVICE_VOLUME,
1223                    SENDMSG_QUEUE,
1224                    device,
1225                    0,
1226                    streamState,
1227                    0);
1228        }
1229    }
1230
1231    /** @see AudioManager#setStreamSolo(int, boolean) */
1232    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
1233        if (mUseFixedVolume) {
1234            return;
1235        }
1236
1237        for (int stream = 0; stream < mStreamStates.length; stream++) {
1238            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
1239            mStreamStates[stream].mute(cb, state);
1240         }
1241    }
1242
1243    /** @see AudioManager#setStreamMute(int, boolean) */
1244    public void setStreamMute(int streamType, boolean state, IBinder cb) {
1245        if (mUseFixedVolume) {
1246            return;
1247        }
1248
1249        if (isStreamAffectedByMute(streamType)) {
1250            mStreamStates[streamType].mute(cb, state);
1251        }
1252    }
1253
1254    /** get stream mute state. */
1255    public boolean isStreamMute(int streamType) {
1256        return mStreamStates[streamType].isMuted();
1257    }
1258
1259    /** @see AudioManager#setMasterMute(boolean, int) */
1260    public void setMasterMute(boolean state, int flags, IBinder cb) {
1261        if (mUseFixedVolume) {
1262            return;
1263        }
1264
1265        if (state != AudioSystem.getMasterMute()) {
1266            AudioSystem.setMasterMute(state);
1267            // Post a persist master volume msg
1268            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
1269                    : 0, 0, null, PERSIST_DELAY);
1270            sendMasterMuteUpdate(state, flags);
1271        }
1272    }
1273
1274    /** get master mute state. */
1275    public boolean isMasterMute() {
1276        return AudioSystem.getMasterMute();
1277    }
1278
1279    protected static int getMaxStreamVolume(int streamType) {
1280        return MAX_STREAM_VOLUME[streamType];
1281    }
1282
1283    /** @see AudioManager#getStreamVolume(int) */
1284    public int getStreamVolume(int streamType) {
1285        ensureValidStreamType(streamType);
1286        int device = getDeviceForStream(streamType);
1287        int index = mStreamStates[streamType].getIndex(device);
1288
1289        // by convention getStreamVolume() returns 0 when a stream is muted.
1290        if (mStreamStates[streamType].isMuted()) {
1291            index = 0;
1292        }
1293        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1294                (device & mFixedVolumeDevices) != 0) {
1295            index = mStreamStates[streamType].getMaxIndex();
1296        }
1297        return (index + 5) / 10;
1298    }
1299
1300    public int getMasterVolume() {
1301        if (isMasterMute()) return 0;
1302        return getLastAudibleMasterVolume();
1303    }
1304
1305    public void setMasterVolume(int volume, int flags, String callingPackage) {
1306        if (mUseFixedVolume) {
1307            return;
1308        }
1309
1310        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1311                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1312            return;
1313        }
1314
1315        if (volume < 0) {
1316            volume = 0;
1317        } else if (volume > MAX_MASTER_VOLUME) {
1318            volume = MAX_MASTER_VOLUME;
1319        }
1320        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1321    }
1322
1323    private void doSetMasterVolume(float volume, int flags) {
1324        // don't allow changing master volume when muted
1325        if (!AudioSystem.getMasterMute()) {
1326            int oldVolume = getMasterVolume();
1327            AudioSystem.setMasterVolume(volume);
1328
1329            int newVolume = getMasterVolume();
1330            if (newVolume != oldVolume) {
1331                // Post a persist master volume msg
1332                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1333                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
1334            }
1335            // Send the volume update regardless whether there was a change.
1336            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
1337        }
1338    }
1339
1340    /** @see AudioManager#getStreamMaxVolume(int) */
1341    public int getStreamMaxVolume(int streamType) {
1342        ensureValidStreamType(streamType);
1343        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
1344    }
1345
1346    public int getMasterMaxVolume() {
1347        return MAX_MASTER_VOLUME;
1348    }
1349
1350    /** Get last audible volume before stream was muted. */
1351    public int getLastAudibleStreamVolume(int streamType) {
1352        ensureValidStreamType(streamType);
1353        int device = getDeviceForStream(streamType);
1354        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
1355    }
1356
1357    /** Get last audible master volume before it was muted. */
1358    public int getLastAudibleMasterVolume() {
1359        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1360    }
1361
1362    /** @see AudioManager#getMasterStreamType()  */
1363    public int getMasterStreamType() {
1364        if (mVoiceCapable) {
1365            return AudioSystem.STREAM_RING;
1366        } else {
1367            return AudioSystem.STREAM_MUSIC;
1368        }
1369    }
1370
1371    /** @see AudioManager#getRingerMode() */
1372    public int getRingerMode() {
1373        synchronized(mSettingsLock) {
1374            return mRingerMode;
1375        }
1376    }
1377
1378    private void ensureValidRingerMode(int ringerMode) {
1379        if (!AudioManager.isValidRingerMode(ringerMode)) {
1380            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1381        }
1382    }
1383
1384    /** @see AudioManager#setRingerMode(int) */
1385    public void setRingerMode(int ringerMode) {
1386        if (mUseFixedVolume) {
1387            return;
1388        }
1389
1390        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1391            ringerMode = AudioManager.RINGER_MODE_SILENT;
1392        }
1393        if (ringerMode != getRingerMode()) {
1394            setRingerModeInt(ringerMode, true);
1395            // Send sticky broadcast
1396            broadcastRingerMode(ringerMode);
1397        }
1398    }
1399
1400    private void setRingerModeInt(int ringerMode, boolean persist) {
1401        synchronized(mSettingsLock) {
1402            mRingerMode = ringerMode;
1403        }
1404
1405        // Mute stream if not previously muted by ringer mode and ringer mode
1406        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1407        // Unmute stream if previously muted by ringer mode and ringer mode
1408        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1409        int numStreamTypes = AudioSystem.getNumStreamTypes();
1410        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1411            if (isStreamMutedByRingerMode(streamType)) {
1412                if (!isStreamAffectedByRingerMode(streamType) ||
1413                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1414                    // ring and notifications volume should never be 0 when not silenced
1415                    // on voice capable devices
1416                    if (mVoiceCapable &&
1417                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1418                        synchronized (mStreamStates[streamType]) {
1419                            Set set = mStreamStates[streamType].mIndex.entrySet();
1420                            Iterator i = set.iterator();
1421                            while (i.hasNext()) {
1422                                Map.Entry entry = (Map.Entry)i.next();
1423                                if ((Integer)entry.getValue() == 0) {
1424                                    entry.setValue(10);
1425                                }
1426                            }
1427                        }
1428                    }
1429                    mStreamStates[streamType].mute(null, false);
1430                    mRingerModeMutedStreams &= ~(1 << streamType);
1431                }
1432            } else {
1433                if (isStreamAffectedByRingerMode(streamType) &&
1434                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
1435                   mStreamStates[streamType].mute(null, true);
1436                   mRingerModeMutedStreams |= (1 << streamType);
1437               }
1438            }
1439        }
1440
1441        // Post a persist ringer mode msg
1442        if (persist) {
1443            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
1444                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1445        }
1446    }
1447
1448    private void restoreMasterVolume() {
1449        if (mUseFixedVolume) {
1450            AudioSystem.setMasterVolume(1.0f);
1451            return;
1452        }
1453        if (mUseMasterVolume) {
1454            float volume = Settings.System.getFloatForUser(mContentResolver,
1455                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
1456            if (volume >= 0.0f) {
1457                AudioSystem.setMasterVolume(volume);
1458            }
1459        }
1460    }
1461
1462    /** @see AudioManager#shouldVibrate(int) */
1463    public boolean shouldVibrate(int vibrateType) {
1464        if (!mHasVibrator) return false;
1465
1466        switch (getVibrateSetting(vibrateType)) {
1467
1468            case AudioManager.VIBRATE_SETTING_ON:
1469                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
1470
1471            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1472                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
1473
1474            case AudioManager.VIBRATE_SETTING_OFF:
1475                // return false, even for incoming calls
1476                return false;
1477
1478            default:
1479                return false;
1480        }
1481    }
1482
1483    /** @see AudioManager#getVibrateSetting(int) */
1484    public int getVibrateSetting(int vibrateType) {
1485        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
1486        return (mVibrateSetting >> (vibrateType * 2)) & 3;
1487    }
1488
1489    /** @see AudioManager#setVibrateSetting(int, int) */
1490    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1491
1492        if (!mHasVibrator) return;
1493
1494        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1495
1496        // Broadcast change
1497        broadcastVibrateSetting(vibrateType);
1498
1499    }
1500
1501    /**
1502     * @see #setVibrateSetting(int, int)
1503     */
1504    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1505            int vibrateSetting) {
1506
1507        // First clear the existing setting. Each vibrate type has two bits in
1508        // the value. Note '3' is '11' in binary.
1509        existingValue &= ~(3 << (vibrateType * 2));
1510
1511        // Set into the old value
1512        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1513
1514        return existingValue;
1515    }
1516
1517    private class SetModeDeathHandler implements IBinder.DeathRecipient {
1518        private IBinder mCb; // To be notified of client's death
1519        private int mPid;
1520        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1521
1522        SetModeDeathHandler(IBinder cb, int pid) {
1523            mCb = cb;
1524            mPid = pid;
1525        }
1526
1527        public void binderDied() {
1528            int newModeOwnerPid = 0;
1529            synchronized(mSetModeDeathHandlers) {
1530                Log.w(TAG, "setMode() client died");
1531                int index = mSetModeDeathHandlers.indexOf(this);
1532                if (index < 0) {
1533                    Log.w(TAG, "unregistered setMode() client died");
1534                } else {
1535                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
1536                }
1537            }
1538            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1539            // SCO connections not started by the application changing the mode
1540            if (newModeOwnerPid != 0) {
1541                final long ident = Binder.clearCallingIdentity();
1542                disconnectBluetoothSco(newModeOwnerPid);
1543                Binder.restoreCallingIdentity(ident);
1544            }
1545        }
1546
1547        public int getPid() {
1548            return mPid;
1549        }
1550
1551        public void setMode(int mode) {
1552            mMode = mode;
1553        }
1554
1555        public int getMode() {
1556            return mMode;
1557        }
1558
1559        public IBinder getBinder() {
1560            return mCb;
1561        }
1562    }
1563
1564    /** @see AudioManager#setMode(int) */
1565    public void setMode(int mode, IBinder cb) {
1566        if (!checkAudioSettingsPermission("setMode()")) {
1567            return;
1568        }
1569
1570        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1571            return;
1572        }
1573
1574        int newModeOwnerPid = 0;
1575        synchronized(mSetModeDeathHandlers) {
1576            if (mode == AudioSystem.MODE_CURRENT) {
1577                mode = mMode;
1578            }
1579            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
1580        }
1581        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1582        // SCO connections not started by the application changing the mode
1583        if (newModeOwnerPid != 0) {
1584             disconnectBluetoothSco(newModeOwnerPid);
1585        }
1586    }
1587
1588    // must be called synchronized on mSetModeDeathHandlers
1589    // setModeInt() returns a valid PID if the audio mode was successfully set to
1590    // any mode other than NORMAL.
1591    int setModeInt(int mode, IBinder cb, int pid) {
1592        int newModeOwnerPid = 0;
1593        if (cb == null) {
1594            Log.e(TAG, "setModeInt() called with null binder");
1595            return newModeOwnerPid;
1596        }
1597
1598        SetModeDeathHandler hdlr = null;
1599        Iterator iter = mSetModeDeathHandlers.iterator();
1600        while (iter.hasNext()) {
1601            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1602            if (h.getPid() == pid) {
1603                hdlr = h;
1604                // Remove from client list so that it is re-inserted at top of list
1605                iter.remove();
1606                hdlr.getBinder().unlinkToDeath(hdlr, 0);
1607                break;
1608            }
1609        }
1610        int status = AudioSystem.AUDIO_STATUS_OK;
1611        do {
1612            if (mode == AudioSystem.MODE_NORMAL) {
1613                // get new mode from client at top the list if any
1614                if (!mSetModeDeathHandlers.isEmpty()) {
1615                    hdlr = mSetModeDeathHandlers.get(0);
1616                    cb = hdlr.getBinder();
1617                    mode = hdlr.getMode();
1618                }
1619            } else {
1620                if (hdlr == null) {
1621                    hdlr = new SetModeDeathHandler(cb, pid);
1622                }
1623                // Register for client death notification
1624                try {
1625                    cb.linkToDeath(hdlr, 0);
1626                } catch (RemoteException e) {
1627                    // Client has died!
1628                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1629                }
1630
1631                // Last client to call setMode() is always at top of client list
1632                // as required by SetModeDeathHandler.binderDied()
1633                mSetModeDeathHandlers.add(0, hdlr);
1634                hdlr.setMode(mode);
1635            }
1636
1637            if (mode != mMode) {
1638                status = AudioSystem.setPhoneState(mode);
1639                if (status == AudioSystem.AUDIO_STATUS_OK) {
1640                    mMode = mode;
1641                } else {
1642                    if (hdlr != null) {
1643                        mSetModeDeathHandlers.remove(hdlr);
1644                        cb.unlinkToDeath(hdlr, 0);
1645                    }
1646                    // force reading new top of mSetModeDeathHandlers stack
1647                    mode = AudioSystem.MODE_NORMAL;
1648                }
1649            } else {
1650                status = AudioSystem.AUDIO_STATUS_OK;
1651            }
1652        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1653
1654        if (status == AudioSystem.AUDIO_STATUS_OK) {
1655            if (mode != AudioSystem.MODE_NORMAL) {
1656                if (mSetModeDeathHandlers.isEmpty()) {
1657                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1658                } else {
1659                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1660                }
1661            }
1662            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
1663            if (streamType == STREAM_REMOTE_MUSIC) {
1664                // here handle remote media playback the same way as local playback
1665                streamType = AudioManager.STREAM_MUSIC;
1666            }
1667            int device = getDeviceForStream(streamType);
1668            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1669            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
1670
1671            updateStreamVolumeAlias(true /*updateVolumes*/);
1672        }
1673        return newModeOwnerPid;
1674    }
1675
1676    /** @see AudioManager#getMode() */
1677    public int getMode() {
1678        return mMode;
1679    }
1680
1681    //==========================================================================================
1682    // Sound Effects
1683    //==========================================================================================
1684
1685    private static final String TAG_AUDIO_ASSETS = "audio_assets";
1686    private static final String ATTR_VERSION = "version";
1687    private static final String TAG_GROUP = "group";
1688    private static final String ATTR_GROUP_NAME = "name";
1689    private static final String TAG_ASSET = "asset";
1690    private static final String ATTR_ASSET_ID = "id";
1691    private static final String ATTR_ASSET_FILE = "file";
1692
1693    private static final String ASSET_FILE_VERSION = "1.0";
1694    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1695
1696    private static final int SOUND_EFECTS_LOAD_TIMEOUT_MS = 5000;
1697
1698    class LoadSoundEffectReply {
1699        public int mStatus = 1;
1700    };
1701
1702    private void loadTouchSoundAssetDefaults() {
1703        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1704        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1705            SOUND_EFFECT_FILES_MAP[i][0] = 0;
1706            SOUND_EFFECT_FILES_MAP[i][1] = -1;
1707        }
1708    }
1709
1710    private void loadTouchSoundAssets() {
1711        XmlResourceParser parser = null;
1712
1713        // only load assets once.
1714        if (!SOUND_EFFECT_FILES.isEmpty()) {
1715            return;
1716        }
1717
1718        loadTouchSoundAssetDefaults();
1719
1720        try {
1721            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1722
1723            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1724            String version = parser.getAttributeValue(null, ATTR_VERSION);
1725            boolean inTouchSoundsGroup = false;
1726
1727            if (ASSET_FILE_VERSION.equals(version)) {
1728                while (true) {
1729                    XmlUtils.nextElement(parser);
1730                    String element = parser.getName();
1731                    if (element == null) {
1732                        break;
1733                    }
1734                    if (element.equals(TAG_GROUP)) {
1735                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1736                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
1737                            inTouchSoundsGroup = true;
1738                            break;
1739                        }
1740                    }
1741                }
1742                while (inTouchSoundsGroup) {
1743                    XmlUtils.nextElement(parser);
1744                    String element = parser.getName();
1745                    if (element == null) {
1746                        break;
1747                    }
1748                    if (element.equals(TAG_ASSET)) {
1749                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1750                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1751                        int fx;
1752
1753                        try {
1754                            Field field = AudioManager.class.getField(id);
1755                            fx = field.getInt(null);
1756                        } catch (Exception e) {
1757                            Log.w(TAG, "Invalid touch sound ID: "+id);
1758                            continue;
1759                        }
1760
1761                        int i = SOUND_EFFECT_FILES.indexOf(file);
1762                        if (i == -1) {
1763                            i = SOUND_EFFECT_FILES.size();
1764                            SOUND_EFFECT_FILES.add(file);
1765                        }
1766                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
1767                    } else {
1768                        break;
1769                    }
1770                }
1771            }
1772        } catch (Resources.NotFoundException e) {
1773            Log.w(TAG, "audio assets file not found", e);
1774        } catch (XmlPullParserException e) {
1775            Log.w(TAG, "XML parser exception reading touch sound assets", e);
1776        } catch (IOException e) {
1777            Log.w(TAG, "I/O exception reading touch sound assets", e);
1778        } finally {
1779            if (parser != null) {
1780                parser.close();
1781            }
1782        }
1783    }
1784
1785    /** @see AudioManager#playSoundEffect(int) */
1786    public void playSoundEffect(int effectType) {
1787        playSoundEffectVolume(effectType, -1.0f);
1788    }
1789
1790    /** @see AudioManager#playSoundEffect(int, float) */
1791    public void playSoundEffectVolume(int effectType, float volume) {
1792        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
1793                effectType, (int) (volume * 1000), null, 0);
1794    }
1795
1796    /**
1797     * Loads samples into the soundpool.
1798     * This method must be called at first when sound effects are enabled
1799     */
1800    public boolean loadSoundEffects() {
1801        int attempts = 3;
1802        LoadSoundEffectReply reply = new LoadSoundEffectReply();
1803
1804        synchronized (reply) {
1805            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
1806            while ((reply.mStatus == 1) && (attempts-- > 0)) {
1807                try {
1808                    reply.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
1809                } catch (InterruptedException e) {
1810                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
1811                }
1812            }
1813        }
1814        return (reply.mStatus == 0);
1815    }
1816
1817    /**
1818     *  Unloads samples from the sound pool.
1819     *  This method can be called to free some memory when
1820     *  sound effects are disabled.
1821     */
1822    public void unloadSoundEffects() {
1823        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
1824    }
1825
1826    class SoundPoolListenerThread extends Thread {
1827        public SoundPoolListenerThread() {
1828            super("SoundPoolListenerThread");
1829        }
1830
1831        @Override
1832        public void run() {
1833
1834            Looper.prepare();
1835            mSoundPoolLooper = Looper.myLooper();
1836
1837            synchronized (mSoundEffectsLock) {
1838                if (mSoundPool != null) {
1839                    mSoundPoolCallBack = new SoundPoolCallback();
1840                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1841                }
1842                mSoundEffectsLock.notify();
1843            }
1844            Looper.loop();
1845        }
1846    }
1847
1848    private final class SoundPoolCallback implements
1849            android.media.SoundPool.OnLoadCompleteListener {
1850
1851        int mStatus = 1; // 1 means neither error nor last sample loaded yet
1852        List<Integer> mSamples = new ArrayList<Integer>();
1853
1854        public int status() {
1855            return mStatus;
1856        }
1857
1858        public void setSamples(int[] samples) {
1859            for (int i = 0; i < samples.length; i++) {
1860                // do not wait ack for samples rejected upfront by SoundPool
1861                if (samples[i] > 0) {
1862                    mSamples.add(samples[i]);
1863                }
1864            }
1865        }
1866
1867        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1868            synchronized (mSoundEffectsLock) {
1869                int i = mSamples.indexOf(sampleId);
1870                if (i >= 0) {
1871                    mSamples.remove(i);
1872                }
1873                if ((status != 0) || mSamples. isEmpty()) {
1874                    mStatus = status;
1875                    mSoundEffectsLock.notify();
1876                }
1877            }
1878        }
1879    }
1880
1881    /** @see AudioManager#reloadAudioSettings() */
1882    public void reloadAudioSettings() {
1883        readAudioSettings(false /*userSwitch*/);
1884    }
1885
1886    private void readAudioSettings(boolean userSwitch) {
1887        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
1888        readPersistedSettings();
1889
1890        // restore volume settings
1891        int numStreamTypes = AudioSystem.getNumStreamTypes();
1892        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1893            VolumeStreamState streamState = mStreamStates[streamType];
1894
1895            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1896                continue;
1897            }
1898
1899            synchronized (streamState) {
1900                streamState.readSettings();
1901
1902                // unmute stream that was muted but is not affect by mute anymore
1903                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
1904                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
1905                    int size = streamState.mDeathHandlers.size();
1906                    for (int i = 0; i < size; i++) {
1907                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
1908                        streamState.mDeathHandlers.get(i).mute(false);
1909                    }
1910                }
1911            }
1912        }
1913
1914        // apply new ringer mode before checking volume for alias streams so that streams
1915        // muted by ringer mode have the correct volume
1916        setRingerModeInt(getRingerMode(), false);
1917
1918        checkAllAliasStreamVolumes();
1919
1920        synchronized (mSafeMediaVolumeState) {
1921            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
1922                enforceSafeMediaVolume();
1923            }
1924        }
1925    }
1926
1927    /** @see AudioManager#setSpeakerphoneOn(boolean) */
1928    public void setSpeakerphoneOn(boolean on){
1929        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1930            return;
1931        }
1932
1933        if (on) {
1934            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
1935                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1936                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
1937            }
1938            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
1939        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
1940            mForcedUseForComm = AudioSystem.FORCE_NONE;
1941        }
1942
1943        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1944                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1945    }
1946
1947    /** @see AudioManager#isSpeakerphoneOn() */
1948    public boolean isSpeakerphoneOn() {
1949        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
1950    }
1951
1952    /** @see AudioManager#setBluetoothScoOn(boolean) */
1953    public void setBluetoothScoOn(boolean on){
1954        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
1955            return;
1956        }
1957
1958        if (on) {
1959            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
1960        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
1961            mForcedUseForComm = AudioSystem.FORCE_NONE;
1962        }
1963
1964        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1965                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1966        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1967                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
1968    }
1969
1970    /** @see AudioManager#isBluetoothScoOn() */
1971    public boolean isBluetoothScoOn() {
1972        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
1973    }
1974
1975    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
1976    public void setBluetoothA2dpOn(boolean on) {
1977        synchronized (mBluetoothA2dpEnabledLock) {
1978            mBluetoothA2dpEnabled = on;
1979            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
1980                    AudioSystem.FOR_MEDIA,
1981                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
1982                    null, 0);
1983        }
1984    }
1985
1986    /** @see AudioManager#isBluetoothA2dpOn() */
1987    public boolean isBluetoothA2dpOn() {
1988        synchronized (mBluetoothA2dpEnabledLock) {
1989            return mBluetoothA2dpEnabled;
1990        }
1991    }
1992
1993    /** @see AudioManager#startBluetoothSco() */
1994    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
1995        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
1996                !mBootCompleted) {
1997            return;
1998        }
1999        ScoClient client = getScoClient(cb, true);
2000        // The calling identity must be cleared before calling ScoClient.incCount().
2001        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2002        // and this must be done on behalf of system server to make sure permissions are granted.
2003        // The caller identity must be cleared after getScoClient() because it is needed if a new
2004        // client is created.
2005        final long ident = Binder.clearCallingIdentity();
2006        client.incCount(targetSdkVersion);
2007        Binder.restoreCallingIdentity(ident);
2008    }
2009
2010    /** @see AudioManager#stopBluetoothSco() */
2011    public void stopBluetoothSco(IBinder cb){
2012        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
2013                !mBootCompleted) {
2014            return;
2015        }
2016        ScoClient client = getScoClient(cb, false);
2017        // The calling identity must be cleared before calling ScoClient.decCount().
2018        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2019        // and this must be done on behalf of system server to make sure permissions are granted.
2020        final long ident = Binder.clearCallingIdentity();
2021        if (client != null) {
2022            client.decCount();
2023        }
2024        Binder.restoreCallingIdentity(ident);
2025    }
2026
2027
2028    private class ScoClient implements IBinder.DeathRecipient {
2029        private IBinder mCb; // To be notified of client's death
2030        private int mCreatorPid;
2031        private int mStartcount; // number of SCO connections started by this client
2032
2033        ScoClient(IBinder cb) {
2034            mCb = cb;
2035            mCreatorPid = Binder.getCallingPid();
2036            mStartcount = 0;
2037        }
2038
2039        public void binderDied() {
2040            synchronized(mScoClients) {
2041                Log.w(TAG, "SCO client died");
2042                int index = mScoClients.indexOf(this);
2043                if (index < 0) {
2044                    Log.w(TAG, "unregistered SCO client died");
2045                } else {
2046                    clearCount(true);
2047                    mScoClients.remove(this);
2048                }
2049            }
2050        }
2051
2052        public void incCount(int targetSdkVersion) {
2053            synchronized(mScoClients) {
2054                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
2055                if (mStartcount == 0) {
2056                    try {
2057                        mCb.linkToDeath(this, 0);
2058                    } catch (RemoteException e) {
2059                        // client has already died!
2060                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
2061                    }
2062                }
2063                mStartcount++;
2064            }
2065        }
2066
2067        public void decCount() {
2068            synchronized(mScoClients) {
2069                if (mStartcount == 0) {
2070                    Log.w(TAG, "ScoClient.decCount() already 0");
2071                } else {
2072                    mStartcount--;
2073                    if (mStartcount == 0) {
2074                        try {
2075                            mCb.unlinkToDeath(this, 0);
2076                        } catch (NoSuchElementException e) {
2077                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2078                        }
2079                    }
2080                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2081                }
2082            }
2083        }
2084
2085        public void clearCount(boolean stopSco) {
2086            synchronized(mScoClients) {
2087                if (mStartcount != 0) {
2088                    try {
2089                        mCb.unlinkToDeath(this, 0);
2090                    } catch (NoSuchElementException e) {
2091                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2092                    }
2093                }
2094                mStartcount = 0;
2095                if (stopSco) {
2096                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
2097                }
2098            }
2099        }
2100
2101        public int getCount() {
2102            return mStartcount;
2103        }
2104
2105        public IBinder getBinder() {
2106            return mCb;
2107        }
2108
2109        public int getPid() {
2110            return mCreatorPid;
2111        }
2112
2113        public int totalCount() {
2114            synchronized(mScoClients) {
2115                int count = 0;
2116                int size = mScoClients.size();
2117                for (int i = 0; i < size; i++) {
2118                    count += mScoClients.get(i).getCount();
2119                }
2120                return count;
2121            }
2122        }
2123
2124        private void requestScoState(int state, int targetSdkVersion) {
2125            checkScoAudioState();
2126            if (totalCount() == 0) {
2127                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2128                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2129                    // the connection.
2130                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2131                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2132                    // currently controlled by the same client process.
2133                    synchronized(mSetModeDeathHandlers) {
2134                        if ((mSetModeDeathHandlers.isEmpty() ||
2135                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2136                                (mScoAudioState == SCO_STATE_INACTIVE ||
2137                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2138                            if (mScoAudioState == SCO_STATE_INACTIVE) {
2139                                mScoAudioMode =
2140                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2141                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
2142                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2143                                    boolean status;
2144                                    if (mScoAudioMode == SCO_MODE_RAW) {
2145                                        status = mBluetoothHeadset.connectAudio();
2146                                    } else {
2147                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2148                                                                            mBluetoothHeadsetDevice);
2149                                    }
2150                                    if (status) {
2151                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2152                                    } else {
2153                                        broadcastScoConnectionState(
2154                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2155                                    }
2156                                } else if (getBluetoothHeadset()) {
2157                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2158                                }
2159                            } else {
2160                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2161                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2162                            }
2163                        } else {
2164                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2165                        }
2166                    }
2167                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2168                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2169                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2170                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2171                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2172                            boolean status;
2173                            if (mScoAudioMode == SCO_MODE_RAW) {
2174                                status = mBluetoothHeadset.disconnectAudio();
2175                            } else {
2176                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2177                                                                        mBluetoothHeadsetDevice);
2178                            }
2179                            if (!status) {
2180                                mScoAudioState = SCO_STATE_INACTIVE;
2181                                broadcastScoConnectionState(
2182                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2183                            }
2184                        } else if (getBluetoothHeadset()) {
2185                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2186                        }
2187                    } else {
2188                        mScoAudioState = SCO_STATE_INACTIVE;
2189                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2190                    }
2191                }
2192            }
2193        }
2194    }
2195
2196    private void checkScoAudioState() {
2197        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2198                mScoAudioState == SCO_STATE_INACTIVE &&
2199                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2200                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2201            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2202        }
2203    }
2204
2205    private ScoClient getScoClient(IBinder cb, boolean create) {
2206        synchronized(mScoClients) {
2207            ScoClient client = null;
2208            int size = mScoClients.size();
2209            for (int i = 0; i < size; i++) {
2210                client = mScoClients.get(i);
2211                if (client.getBinder() == cb)
2212                    return client;
2213            }
2214            if (create) {
2215                client = new ScoClient(cb);
2216                mScoClients.add(client);
2217            }
2218            return client;
2219        }
2220    }
2221
2222    public void clearAllScoClients(int exceptPid, boolean stopSco) {
2223        synchronized(mScoClients) {
2224            ScoClient savedClient = null;
2225            int size = mScoClients.size();
2226            for (int i = 0; i < size; i++) {
2227                ScoClient cl = mScoClients.get(i);
2228                if (cl.getPid() != exceptPid) {
2229                    cl.clearCount(stopSco);
2230                } else {
2231                    savedClient = cl;
2232                }
2233            }
2234            mScoClients.clear();
2235            if (savedClient != null) {
2236                mScoClients.add(savedClient);
2237            }
2238        }
2239    }
2240
2241    private boolean getBluetoothHeadset() {
2242        boolean result = false;
2243        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2244        if (adapter != null) {
2245            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2246                                    BluetoothProfile.HEADSET);
2247        }
2248        // If we could not get a bluetooth headset proxy, send a failure message
2249        // without delay to reset the SCO audio state and clear SCO clients.
2250        // If we could get a proxy, send a delayed failure message that will reset our state
2251        // in case we don't receive onServiceConnected().
2252        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2253                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2254        return result;
2255    }
2256
2257    private void disconnectBluetoothSco(int exceptPid) {
2258        synchronized(mScoClients) {
2259            checkScoAudioState();
2260            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2261                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2262                if (mBluetoothHeadsetDevice != null) {
2263                    if (mBluetoothHeadset != null) {
2264                        if (!mBluetoothHeadset.stopVoiceRecognition(
2265                                mBluetoothHeadsetDevice)) {
2266                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2267                                    SENDMSG_REPLACE, 0, 0, null, 0);
2268                        }
2269                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2270                            getBluetoothHeadset()) {
2271                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2272                    }
2273                }
2274            } else {
2275                clearAllScoClients(exceptPid, true);
2276            }
2277        }
2278    }
2279
2280    private void resetBluetoothSco() {
2281        synchronized(mScoClients) {
2282            clearAllScoClients(0, false);
2283            mScoAudioState = SCO_STATE_INACTIVE;
2284            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2285        }
2286    }
2287
2288    private void broadcastScoConnectionState(int state) {
2289        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2290                SENDMSG_QUEUE, state, 0, null, 0);
2291    }
2292
2293    private void onBroadcastScoConnectionState(int state) {
2294        if (state != mScoConnectionState) {
2295            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2296            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2297            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2298                    mScoConnectionState);
2299            sendStickyBroadcastToAll(newIntent);
2300            mScoConnectionState = state;
2301        }
2302    }
2303
2304    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2305        new BluetoothProfile.ServiceListener() {
2306        public void onServiceConnected(int profile, BluetoothProfile proxy) {
2307            BluetoothDevice btDevice;
2308            List<BluetoothDevice> deviceList;
2309            switch(profile) {
2310            case BluetoothProfile.A2DP:
2311                synchronized (mA2dpAvrcpLock) {
2312                    mA2dp = (BluetoothA2dp) proxy;
2313                    deviceList = mA2dp.getConnectedDevices();
2314                    if (deviceList.size() > 0) {
2315                        btDevice = deviceList.get(0);
2316                        synchronized (mConnectedDevices) {
2317                            int state = mA2dp.getConnectionState(btDevice);
2318                            int delay = checkSendBecomingNoisyIntent(
2319                                                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2320                                                    (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2321                            queueMsgUnderWakeLock(mAudioHandler,
2322                                    MSG_SET_A2DP_CONNECTION_STATE,
2323                                    state,
2324                                    0,
2325                                    btDevice,
2326                                    delay);
2327                        }
2328                    }
2329                }
2330                break;
2331
2332            case BluetoothProfile.HEADSET:
2333                synchronized (mScoClients) {
2334                    // Discard timeout message
2335                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2336                    mBluetoothHeadset = (BluetoothHeadset) proxy;
2337                    deviceList = mBluetoothHeadset.getConnectedDevices();
2338                    if (deviceList.size() > 0) {
2339                        mBluetoothHeadsetDevice = deviceList.get(0);
2340                    } else {
2341                        mBluetoothHeadsetDevice = null;
2342                    }
2343                    // Refresh SCO audio state
2344                    checkScoAudioState();
2345                    // Continue pending action if any
2346                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2347                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2348                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2349                        boolean status = false;
2350                        if (mBluetoothHeadsetDevice != null) {
2351                            switch (mScoAudioState) {
2352                            case SCO_STATE_ACTIVATE_REQ:
2353                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2354                                if (mScoAudioMode == SCO_MODE_RAW) {
2355                                    status = mBluetoothHeadset.connectAudio();
2356                                } else {
2357                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2358                                                                        mBluetoothHeadsetDevice);
2359                                }
2360                                break;
2361                            case SCO_STATE_DEACTIVATE_REQ:
2362                                if (mScoAudioMode == SCO_MODE_RAW) {
2363                                    status = mBluetoothHeadset.disconnectAudio();
2364                                } else {
2365                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2366                                                                        mBluetoothHeadsetDevice);
2367                                }
2368                                break;
2369                            case SCO_STATE_DEACTIVATE_EXT_REQ:
2370                                status = mBluetoothHeadset.stopVoiceRecognition(
2371                                        mBluetoothHeadsetDevice);
2372                            }
2373                        }
2374                        if (!status) {
2375                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2376                                    SENDMSG_REPLACE, 0, 0, null, 0);
2377                        }
2378                    }
2379                }
2380                break;
2381
2382            default:
2383                break;
2384            }
2385        }
2386        public void onServiceDisconnected(int profile) {
2387            switch(profile) {
2388            case BluetoothProfile.A2DP:
2389                synchronized (mA2dpAvrcpLock) {
2390                    mA2dp = null;
2391                    synchronized (mConnectedDevices) {
2392                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2393                            makeA2dpDeviceUnavailableNow(
2394                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2395                        }
2396                    }
2397                }
2398                break;
2399
2400            case BluetoothProfile.HEADSET:
2401                synchronized (mScoClients) {
2402                    mBluetoothHeadset = null;
2403                }
2404                break;
2405
2406            default:
2407                break;
2408            }
2409        }
2410    };
2411
2412    private void onCheckMusicActive() {
2413        synchronized (mSafeMediaVolumeState) {
2414            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2415                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2416
2417                if ((device & mSafeMediaVolumeDevices) != 0) {
2418                    sendMsg(mAudioHandler,
2419                            MSG_CHECK_MUSIC_ACTIVE,
2420                            SENDMSG_REPLACE,
2421                            0,
2422                            0,
2423                            null,
2424                            MUSIC_ACTIVE_POLL_PERIOD_MS);
2425                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2426                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2427                            (index > mSafeMediaVolumeIndex)) {
2428                        // Approximate cumulative active music time
2429                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2430                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2431                            setSafeMediaVolumeEnabled(true);
2432                            mMusicActiveMs = 0;
2433                        }
2434                    }
2435                }
2436            }
2437        }
2438    }
2439
2440    private void onConfigureSafeVolume(boolean force) {
2441        synchronized (mSafeMediaVolumeState) {
2442            int mcc = mContext.getResources().getConfiguration().mcc;
2443            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2444                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2445                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2446                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2447                        com.android.internal.R.bool.config_safe_media_volume_enabled);
2448
2449                // The persisted state is either "disabled" or "active": this is the state applied
2450                // next time we boot and cannot be "inactive"
2451                int persistedState;
2452                if (safeMediaVolumeEnabled) {
2453                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2454                    // The state can already be "inactive" here if the user has forced it before
2455                    // the 30 seconds timeout for forced configuration. In this case we don't reset
2456                    // it to "active".
2457                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2458                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2459                        enforceSafeMediaVolume();
2460                    }
2461                } else {
2462                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2463                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2464                }
2465                mMcc = mcc;
2466                sendMsg(mAudioHandler,
2467                        MSG_PERSIST_SAFE_VOLUME_STATE,
2468                        SENDMSG_QUEUE,
2469                        persistedState,
2470                        0,
2471                        null,
2472                        0);
2473            }
2474        }
2475    }
2476
2477    ///////////////////////////////////////////////////////////////////////////
2478    // Internal methods
2479    ///////////////////////////////////////////////////////////////////////////
2480
2481    /**
2482     * Checks if the adjustment should change ringer mode instead of just
2483     * adjusting volume. If so, this will set the proper ringer mode and volume
2484     * indices on the stream states.
2485     */
2486    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
2487        boolean adjustVolumeIndex = true;
2488        int ringerMode = getRingerMode();
2489
2490        switch (ringerMode) {
2491        case RINGER_MODE_NORMAL:
2492            if (direction == AudioManager.ADJUST_LOWER) {
2493                if (mHasVibrator) {
2494                    // "step" is the delta in internal index units corresponding to a
2495                    // change of 1 in UI index units.
2496                    // Because of rounding when rescaling from one stream index range to its alias
2497                    // index range, we cannot simply test oldIndex == step:
2498                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2499                    if (step <= oldIndex && oldIndex < 2 * step) {
2500                        ringerMode = RINGER_MODE_VIBRATE;
2501                    }
2502                } else {
2503                    // (oldIndex < step) is equivalent to (old UI index == 0)
2504                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2505                        ringerMode = RINGER_MODE_SILENT;
2506                    }
2507                }
2508            }
2509            break;
2510        case RINGER_MODE_VIBRATE:
2511            if (!mHasVibrator) {
2512                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2513                        "but no vibrator is present");
2514                break;
2515            }
2516            if ((direction == AudioManager.ADJUST_LOWER)) {
2517                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2518                    ringerMode = RINGER_MODE_SILENT;
2519                }
2520            } else if (direction == AudioManager.ADJUST_RAISE) {
2521                ringerMode = RINGER_MODE_NORMAL;
2522            }
2523            adjustVolumeIndex = false;
2524            break;
2525        case RINGER_MODE_SILENT:
2526            if (direction == AudioManager.ADJUST_RAISE) {
2527                if (mHasVibrator) {
2528                    ringerMode = RINGER_MODE_VIBRATE;
2529                } else {
2530                    ringerMode = RINGER_MODE_NORMAL;
2531                }
2532            }
2533            adjustVolumeIndex = false;
2534            break;
2535        default:
2536            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2537            break;
2538        }
2539
2540        setRingerMode(ringerMode);
2541
2542        mPrevVolDirection = direction;
2543
2544        return adjustVolumeIndex;
2545    }
2546
2547    public boolean isStreamAffectedByRingerMode(int streamType) {
2548        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
2549    }
2550
2551    private boolean isStreamMutedByRingerMode(int streamType) {
2552        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2553    }
2554
2555    boolean updateRingerModeAffectedStreams() {
2556        int ringerModeAffectedStreams;
2557        // make sure settings for ringer mode are consistent with device type: non voice capable
2558        // devices (tablets) include media stream in silent mode whereas phones don't.
2559        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2560                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2561                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2562                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2563                 UserHandle.USER_CURRENT);
2564
2565        // ringtone, notification and system streams are always affected by ringer mode
2566        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2567                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
2568                                        (1 << AudioSystem.STREAM_SYSTEM);
2569
2570        if (mVoiceCapable) {
2571            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
2572        } else {
2573            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
2574        }
2575        synchronized (mCameraSoundForced) {
2576            if (mCameraSoundForced) {
2577                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2578            } else {
2579                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2580            }
2581        }
2582        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2583            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2584        } else {
2585            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2586        }
2587
2588        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2589            Settings.System.putIntForUser(mContentResolver,
2590                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2591                    ringerModeAffectedStreams,
2592                    UserHandle.USER_CURRENT);
2593            mRingerModeAffectedStreams = ringerModeAffectedStreams;
2594            return true;
2595        }
2596        return false;
2597    }
2598
2599    public boolean isStreamAffectedByMute(int streamType) {
2600        return (mMuteAffectedStreams & (1 << streamType)) != 0;
2601    }
2602
2603    private void ensureValidDirection(int direction) {
2604        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2605            throw new IllegalArgumentException("Bad direction " + direction);
2606        }
2607    }
2608
2609    private void ensureValidSteps(int steps) {
2610        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2611            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2612        }
2613    }
2614
2615    private void ensureValidStreamType(int streamType) {
2616        if (streamType < 0 || streamType >= mStreamStates.length) {
2617            throw new IllegalArgumentException("Bad stream type " + streamType);
2618        }
2619    }
2620
2621    private boolean isInCommunication() {
2622        boolean isOffhook = false;
2623
2624        if (mVoiceCapable) {
2625            try {
2626                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
2627                if (phone != null) isOffhook = phone.isOffhook();
2628            } catch (RemoteException e) {
2629                Log.w(TAG, "Couldn't connect to phone service", e);
2630            }
2631        }
2632        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
2633    }
2634
2635    /**
2636     * For code clarity for getActiveStreamType(int)
2637     * @param delay_ms max time since last STREAM_MUSIC activity to consider
2638     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2639     *     in the last "delay_ms" ms.
2640     */
2641    private boolean isAfMusicActiveRecently(int delay_ms) {
2642        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2643                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2644    }
2645
2646    private int getActiveStreamType(int suggestedStreamType) {
2647        if (mVoiceCapable) {
2648            if (isInCommunication()) {
2649                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2650                        == AudioSystem.FORCE_BT_SCO) {
2651                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2652                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2653                } else {
2654                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2655                    return AudioSystem.STREAM_VOICE_CALL;
2656                }
2657            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2658                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2659                    if (DEBUG_VOL)
2660                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2661                    return AudioSystem.STREAM_MUSIC;
2662                } else
2663                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2664                    {
2665                        if (DEBUG_VOL)
2666                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2667                        return STREAM_REMOTE_MUSIC;
2668                    } else {
2669                        if (DEBUG_VOL)
2670                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2671                        return AudioSystem.STREAM_RING;
2672                }
2673            } else if (isAfMusicActiveRecently(0)) {
2674                if (DEBUG_VOL)
2675                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2676                return AudioSystem.STREAM_MUSIC;
2677            } else {
2678                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2679                        + suggestedStreamType);
2680                return suggestedStreamType;
2681            }
2682        } else {
2683            if (isInCommunication()) {
2684                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2685                        == AudioSystem.FORCE_BT_SCO) {
2686                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
2687                    return AudioSystem.STREAM_BLUETOOTH_SCO;
2688                } else {
2689                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
2690                    return AudioSystem.STREAM_VOICE_CALL;
2691                }
2692            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
2693                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
2694                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
2695                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2696                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
2697                return AudioSystem.STREAM_NOTIFICATION;
2698            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2699                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2700                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2701                    return AudioSystem.STREAM_MUSIC;
2702                } else
2703                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2704                    {
2705                        if (DEBUG_VOL)
2706                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2707                        return STREAM_REMOTE_MUSIC;
2708                } else {
2709                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
2710                    return AudioSystem.STREAM_MUSIC;
2711                }
2712            } else {
2713                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2714                        + suggestedStreamType);
2715                return suggestedStreamType;
2716            }
2717        }
2718    }
2719
2720    private void broadcastRingerMode(int ringerMode) {
2721        // Send sticky broadcast
2722        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2723        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
2724        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2725                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
2726        sendStickyBroadcastToAll(broadcast);
2727    }
2728
2729    private void broadcastVibrateSetting(int vibrateType) {
2730        // Send broadcast
2731        if (ActivityManagerNative.isSystemReady()) {
2732            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
2733            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
2734            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
2735            sendBroadcastToAll(broadcast);
2736        }
2737    }
2738
2739    // Message helper methods
2740    /**
2741     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
2742     * Note that the wake lock needs to be released after the message has been handled.
2743     */
2744    private void queueMsgUnderWakeLock(Handler handler, int msg,
2745            int arg1, int arg2, Object obj, int delay) {
2746        final long ident = Binder.clearCallingIdentity();
2747        // Always acquire the wake lock as AudioService because it is released by the
2748        // message handler.
2749        mAudioEventWakeLock.acquire();
2750        Binder.restoreCallingIdentity(ident);
2751        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2752    }
2753
2754    private static void sendMsg(Handler handler, int msg,
2755            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
2756
2757        if (existingMsgPolicy == SENDMSG_REPLACE) {
2758            handler.removeMessages(msg);
2759        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2760            return;
2761        }
2762
2763        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
2764    }
2765
2766    boolean checkAudioSettingsPermission(String method) {
2767        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2768                == PackageManager.PERMISSION_GRANTED) {
2769            return true;
2770        }
2771        String msg = "Audio Settings Permission Denial: " + method + " from pid="
2772                + Binder.getCallingPid()
2773                + ", uid=" + Binder.getCallingUid();
2774        Log.w(TAG, msg);
2775        return false;
2776    }
2777
2778    private int getDeviceForStream(int stream) {
2779        int device = AudioSystem.getDevicesForStream(stream);
2780        if ((device & (device - 1)) != 0) {
2781            // Multiple device selection is either:
2782            //  - speaker + one other device: give priority to speaker in this case.
2783            //  - one A2DP device + another device: happens with duplicated output. In this case
2784            // retain the device on the A2DP output as the other must not correspond to an active
2785            // selection if not the speaker.
2786            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2787                device = AudioSystem.DEVICE_OUT_SPEAKER;
2788            } else {
2789                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2790            }
2791        }
2792        return device;
2793    }
2794
2795    public void setWiredDeviceConnectionState(int device, int state, String name) {
2796        synchronized (mConnectedDevices) {
2797            int delay = checkSendBecomingNoisyIntent(device, state);
2798            queueMsgUnderWakeLock(mAudioHandler,
2799                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2800                    device,
2801                    state,
2802                    name,
2803                    delay);
2804        }
2805    }
2806
2807    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2808    {
2809        int delay;
2810        synchronized (mConnectedDevices) {
2811            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2812                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2813            queueMsgUnderWakeLock(mAudioHandler,
2814                    MSG_SET_A2DP_CONNECTION_STATE,
2815                    state,
2816                    0,
2817                    device,
2818                    delay);
2819        }
2820        return delay;
2821    }
2822
2823    ///////////////////////////////////////////////////////////////////////////
2824    // Inner classes
2825    ///////////////////////////////////////////////////////////////////////////
2826
2827    public class VolumeStreamState {
2828        private final int mStreamType;
2829
2830        private String mVolumeIndexSettingName;
2831        private int mIndexMax;
2832        private final ConcurrentHashMap<Integer, Integer> mIndex =
2833                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
2834        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
2835
2836        private VolumeStreamState(String settingName, int streamType) {
2837
2838            mVolumeIndexSettingName = settingName;
2839
2840            mStreamType = streamType;
2841            mIndexMax = MAX_STREAM_VOLUME[streamType];
2842            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2843            mIndexMax *= 10;
2844
2845            // mDeathHandlers must be created before calling readSettings()
2846            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
2847
2848            readSettings();
2849        }
2850
2851        public String getSettingNameForDevice(int device) {
2852            String name = mVolumeIndexSettingName;
2853            String suffix = AudioSystem.getDeviceName(device);
2854            if (suffix.isEmpty()) {
2855                return name;
2856            }
2857            return name + "_" + suffix;
2858        }
2859
2860        public synchronized void readSettings() {
2861            // force maximum volume on all streams if fixed volume property is set
2862            if (mUseFixedVolume) {
2863                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
2864                return;
2865            }
2866            // do not read system stream volume from settings: this stream is always aliased
2867            // to another stream type and its volume is never persisted. Values in settings can
2868            // only be stale values
2869            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2870                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2871                int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2872                synchronized (mCameraSoundForced) {
2873                    if (mCameraSoundForced) {
2874                        index = mIndexMax;
2875                    }
2876                }
2877                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2878                return;
2879            }
2880
2881            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
2882
2883            for (int i = 0; remainingDevices != 0; i++) {
2884                int device = (1 << i);
2885                if ((device & remainingDevices) == 0) {
2886                    continue;
2887                }
2888                remainingDevices &= ~device;
2889
2890                // retrieve current volume for device
2891                String name = getSettingNameForDevice(device);
2892                // if no volume stored for current stream and device, use default volume if default
2893                // device, continue otherwise
2894                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
2895                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
2896                int index = Settings.System.getIntForUser(
2897                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
2898                if (index == -1) {
2899                    continue;
2900                }
2901
2902                // ignore settings for fixed volume devices: volume should always be at max or 0
2903                if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
2904                        ((device & mFixedVolumeDevices) != 0)) {
2905                    mIndex.put(device, (index != 0) ? mIndexMax : 0);
2906                } else {
2907                    mIndex.put(device, getValidIndex(10 * index));
2908                }
2909            }
2910        }
2911
2912        public void applyDeviceVolume(int device) {
2913            int index;
2914            if (isMuted()) {
2915                index = 0;
2916            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
2917                       mAvrcpAbsVolSupported) {
2918                index = (mIndexMax + 5)/10;
2919            } else {
2920                index = (getIndex(device) + 5)/10;
2921            }
2922            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
2923        }
2924
2925        public synchronized void applyAllVolumes() {
2926            // apply default volume first: by convention this will reset all
2927            // devices volumes in audio policy manager to the supplied value
2928            int index;
2929            if (isMuted()) {
2930                index = 0;
2931            } else {
2932                index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
2933            }
2934            AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
2935            // then apply device specific volumes
2936            Set set = mIndex.entrySet();
2937            Iterator i = set.iterator();
2938            while (i.hasNext()) {
2939                Map.Entry entry = (Map.Entry)i.next();
2940                int device = ((Integer)entry.getKey()).intValue();
2941                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
2942                    if (isMuted()) {
2943                        index = 0;
2944                    } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
2945                            mAvrcpAbsVolSupported) {
2946                        index = (mIndexMax + 5)/10;
2947                    } else {
2948                        index = ((Integer)entry.getValue() + 5)/10;
2949                    }
2950                    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
2951                }
2952            }
2953        }
2954
2955        public boolean adjustIndex(int deltaIndex, int device) {
2956            return setIndex(getIndex(device) + deltaIndex,
2957                            device);
2958        }
2959
2960        public synchronized boolean setIndex(int index, int device) {
2961            int oldIndex = getIndex(device);
2962            index = getValidIndex(index);
2963            synchronized (mCameraSoundForced) {
2964                if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
2965                    index = mIndexMax;
2966                }
2967            }
2968            mIndex.put(device, index);
2969
2970            if (oldIndex != index) {
2971                // Apply change to all streams using this one as alias
2972                // if changing volume of current device, also change volume of current
2973                // device on aliased stream
2974                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2975                int numStreamTypes = AudioSystem.getNumStreamTypes();
2976                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2977                    if (streamType != mStreamType &&
2978                            mStreamVolumeAlias[streamType] == mStreamType) {
2979                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2980                        mStreamStates[streamType].setIndex(scaledIndex,
2981                                                           device);
2982                        if (currentDevice) {
2983                            mStreamStates[streamType].setIndex(scaledIndex,
2984                                                               getDeviceForStream(streamType));
2985                        }
2986                    }
2987                }
2988                return true;
2989            } else {
2990                return false;
2991            }
2992        }
2993
2994        public synchronized int getIndex(int device) {
2995            Integer index = mIndex.get(device);
2996            if (index == null) {
2997                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
2998                index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
2999            }
3000            return index.intValue();
3001        }
3002
3003        public int getMaxIndex() {
3004            return mIndexMax;
3005        }
3006
3007        public synchronized void setAllIndexes(VolumeStreamState srcStream) {
3008            int srcStreamType = srcStream.getStreamType();
3009            // apply default device volume from source stream to all devices first in case
3010            // some devices are present in this stream state but not in source stream state
3011            int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
3012            index = rescaleIndex(index, srcStreamType, mStreamType);
3013            Set set = mIndex.entrySet();
3014            Iterator i = set.iterator();
3015            while (i.hasNext()) {
3016                Map.Entry entry = (Map.Entry)i.next();
3017                entry.setValue(index);
3018            }
3019            // Now apply actual volume for devices in source stream state
3020            set = srcStream.mIndex.entrySet();
3021            i = set.iterator();
3022            while (i.hasNext()) {
3023                Map.Entry entry = (Map.Entry)i.next();
3024                int device = ((Integer)entry.getKey()).intValue();
3025                index = ((Integer)entry.getValue()).intValue();
3026                index = rescaleIndex(index, srcStreamType, mStreamType);
3027
3028                setIndex(index, device);
3029            }
3030        }
3031
3032        public synchronized void setAllIndexesToMax() {
3033            Set set = mIndex.entrySet();
3034            Iterator i = set.iterator();
3035            while (i.hasNext()) {
3036                Map.Entry entry = (Map.Entry)i.next();
3037                entry.setValue(mIndexMax);
3038            }
3039        }
3040
3041        public synchronized void mute(IBinder cb, boolean state) {
3042            VolumeDeathHandler handler = getDeathHandler(cb, state);
3043            if (handler == null) {
3044                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3045                return;
3046            }
3047            handler.mute(state);
3048        }
3049
3050        public int getStreamType() {
3051            return mStreamType;
3052        }
3053
3054        private int getValidIndex(int index) {
3055            if (index < 0) {
3056                return 0;
3057            } else if (mUseFixedVolume || index > mIndexMax) {
3058                return mIndexMax;
3059            }
3060
3061            return index;
3062        }
3063
3064        private class VolumeDeathHandler implements IBinder.DeathRecipient {
3065            private IBinder mICallback; // To be notified of client's death
3066            private int mMuteCount; // Number of active mutes for this client
3067
3068            VolumeDeathHandler(IBinder cb) {
3069                mICallback = cb;
3070            }
3071
3072            // must be called while synchronized on parent VolumeStreamState
3073            public void mute(boolean state) {
3074                boolean updateVolume = false;
3075                if (state) {
3076                    if (mMuteCount == 0) {
3077                        // Register for client death notification
3078                        try {
3079                            // mICallback can be 0 if muted by AudioService
3080                            if (mICallback != null) {
3081                                mICallback.linkToDeath(this, 0);
3082                            }
3083                            VolumeStreamState.this.mDeathHandlers.add(this);
3084                            // If the stream is not yet muted by any client, set level to 0
3085                            if (!VolumeStreamState.this.isMuted()) {
3086                                updateVolume = true;
3087                            }
3088                        } catch (RemoteException e) {
3089                            // Client has died!
3090                            binderDied();
3091                            return;
3092                        }
3093                    } else {
3094                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3095                    }
3096                    mMuteCount++;
3097                } else {
3098                    if (mMuteCount == 0) {
3099                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3100                    } else {
3101                        mMuteCount--;
3102                        if (mMuteCount == 0) {
3103                            // Unregister from client death notification
3104                            VolumeStreamState.this.mDeathHandlers.remove(this);
3105                            // mICallback can be 0 if muted by AudioService
3106                            if (mICallback != null) {
3107                                mICallback.unlinkToDeath(this, 0);
3108                            }
3109                            if (!VolumeStreamState.this.isMuted()) {
3110                                updateVolume = true;
3111                            }
3112                        }
3113                    }
3114                }
3115                if (updateVolume) {
3116                    sendMsg(mAudioHandler,
3117                            MSG_SET_ALL_VOLUMES,
3118                            SENDMSG_QUEUE,
3119                            0,
3120                            0,
3121                            VolumeStreamState.this, 0);
3122                }
3123            }
3124
3125            public void binderDied() {
3126                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3127                if (mMuteCount != 0) {
3128                    // Reset all active mute requests from this client.
3129                    mMuteCount = 1;
3130                    mute(false);
3131                }
3132            }
3133        }
3134
3135        private synchronized int muteCount() {
3136            int count = 0;
3137            int size = mDeathHandlers.size();
3138            for (int i = 0; i < size; i++) {
3139                count += mDeathHandlers.get(i).mMuteCount;
3140            }
3141            return count;
3142        }
3143
3144        private synchronized boolean isMuted() {
3145            return muteCount() != 0;
3146        }
3147
3148        // only called by mute() which is already synchronized
3149        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
3150            VolumeDeathHandler handler;
3151            int size = mDeathHandlers.size();
3152            for (int i = 0; i < size; i++) {
3153                handler = mDeathHandlers.get(i);
3154                if (cb == handler.mICallback) {
3155                    return handler;
3156                }
3157            }
3158            // If this is the first mute request for this client, create a new
3159            // client death handler. Otherwise, it is an out of sequence unmute request.
3160            if (state) {
3161                handler = new VolumeDeathHandler(cb);
3162            } else {
3163                Log.w(TAG, "stream was not muted by this client");
3164                handler = null;
3165            }
3166            return handler;
3167        }
3168
3169        private void dump(PrintWriter pw) {
3170            pw.print("   Mute count: ");
3171            pw.println(muteCount());
3172            pw.print("   Current: ");
3173            Set set = mIndex.entrySet();
3174            Iterator i = set.iterator();
3175            while (i.hasNext()) {
3176                Map.Entry entry = (Map.Entry)i.next();
3177                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3178                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3179            }
3180        }
3181    }
3182
3183    /** Thread that handles native AudioSystem control. */
3184    private class AudioSystemThread extends Thread {
3185        AudioSystemThread() {
3186            super("AudioService");
3187        }
3188
3189        @Override
3190        public void run() {
3191            // Set this thread up so the handler will work on it
3192            Looper.prepare();
3193
3194            synchronized(AudioService.this) {
3195                mAudioHandler = new AudioHandler();
3196
3197                // Notify that the handler has been created
3198                AudioService.this.notify();
3199            }
3200
3201            // Listen for volume change requests that are set by VolumePanel
3202            Looper.loop();
3203        }
3204    }
3205
3206    /** Handles internal volume messages in separate volume thread. */
3207    private class AudioHandler extends Handler {
3208
3209        private void setDeviceVolume(VolumeStreamState streamState, int device) {
3210
3211            // Apply volume
3212            streamState.applyDeviceVolume(device);
3213
3214            // Apply change to all streams using this one as alias
3215            int numStreamTypes = AudioSystem.getNumStreamTypes();
3216            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3217                if (streamType != streamState.mStreamType &&
3218                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3219                    // Make sure volume is also maxed out on A2DP device for aliased stream
3220                    // that may have a different device selected
3221                    int streamDevice = getDeviceForStream(streamType);
3222                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3223                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3224                        mStreamStates[streamType].applyDeviceVolume(device);
3225                    }
3226                    mStreamStates[streamType].applyDeviceVolume(streamDevice);
3227                }
3228            }
3229
3230            // Post a persist volume msg
3231            sendMsg(mAudioHandler,
3232                    MSG_PERSIST_VOLUME,
3233                    SENDMSG_QUEUE,
3234                    device,
3235                    0,
3236                    streamState,
3237                    PERSIST_DELAY);
3238
3239        }
3240
3241        private void setAllVolumes(VolumeStreamState streamState) {
3242
3243            // Apply volume
3244            streamState.applyAllVolumes();
3245
3246            // Apply change to all streams using this one as alias
3247            int numStreamTypes = AudioSystem.getNumStreamTypes();
3248            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3249                if (streamType != streamState.mStreamType &&
3250                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3251                    mStreamStates[streamType].applyAllVolumes();
3252                }
3253            }
3254        }
3255
3256        private void persistVolume(VolumeStreamState streamState, int device) {
3257            if (mUseFixedVolume) {
3258                return;
3259            }
3260            System.putIntForUser(mContentResolver,
3261                      streamState.getSettingNameForDevice(device),
3262                      (streamState.getIndex(device) + 5)/ 10,
3263                      UserHandle.USER_CURRENT);
3264        }
3265
3266        private void persistRingerMode(int ringerMode) {
3267            if (mUseFixedVolume) {
3268                return;
3269            }
3270            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
3271        }
3272
3273        private boolean onLoadSoundEffects() {
3274            int status;
3275
3276            synchronized (mSoundEffectsLock) {
3277                if (!mBootCompleted) {
3278                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3279                    return false;
3280                }
3281
3282                if (mSoundPool != null) {
3283                    return true;
3284                }
3285
3286                loadTouchSoundAssets();
3287
3288                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
3289                mSoundPoolCallBack = null;
3290                mSoundPoolListenerThread = new SoundPoolListenerThread();
3291                mSoundPoolListenerThread.start();
3292                int attempts = 3;
3293                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3294                    try {
3295                        // Wait for mSoundPoolCallBack to be set by the other thread
3296                        mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
3297                    } catch (InterruptedException e) {
3298                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3299                    }
3300                }
3301
3302                if (mSoundPoolCallBack == null) {
3303                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3304                    if (mSoundPoolLooper != null) {
3305                        mSoundPoolLooper.quit();
3306                        mSoundPoolLooper = null;
3307                    }
3308                    mSoundPoolListenerThread = null;
3309                    mSoundPool.release();
3310                    mSoundPool = null;
3311                    return false;
3312                }
3313                /*
3314                 * poolId table: The value -1 in this table indicates that corresponding
3315                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3316                 * Once loaded, the value in poolId is the sample ID and the same
3317                 * sample can be reused for another effect using the same file.
3318                 */
3319                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3320                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3321                    poolId[fileIdx] = -1;
3322                }
3323                /*
3324                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3325                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3326                 * this indicates we have a valid sample loaded for this effect.
3327                 */
3328
3329                int numSamples = 0;
3330                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3331                    // Do not load sample if this effect uses the MediaPlayer
3332                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3333                        continue;
3334                    }
3335                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3336                        String filePath = Environment.getRootDirectory()
3337                                + SOUND_EFFECTS_PATH
3338                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3339                        int sampleId = mSoundPool.load(filePath, 0);
3340                        if (sampleId <= 0) {
3341                            Log.w(TAG, "Soundpool could not load file: "+filePath);
3342                        } else {
3343                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3344                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3345                            numSamples++;
3346                        }
3347                    } else {
3348                        SOUND_EFFECT_FILES_MAP[effect][1] =
3349                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3350                    }
3351                }
3352                // wait for all samples to be loaded
3353                if (numSamples > 0) {
3354                    mSoundPoolCallBack.setSamples(poolId);
3355
3356                    attempts = 3;
3357                    status = 1;
3358                    while ((status == 1) && (attempts-- > 0)) {
3359                        try {
3360                            mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
3361                            status = mSoundPoolCallBack.status();
3362                        } catch (InterruptedException e) {
3363                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
3364                        }
3365                    }
3366                } else {
3367                    status = -1;
3368                }
3369
3370                if (mSoundPoolLooper != null) {
3371                    mSoundPoolLooper.quit();
3372                    mSoundPoolLooper = null;
3373                }
3374                mSoundPoolListenerThread = null;
3375                if (status != 0) {
3376                    Log.w(TAG,
3377                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
3378                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3379                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3380                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3381                        }
3382                    }
3383
3384                    mSoundPool.release();
3385                    mSoundPool = null;
3386                }
3387            }
3388            return (status == 0);
3389        }
3390
3391        /**
3392         *  Unloads samples from the sound pool.
3393         *  This method can be called to free some memory when
3394         *  sound effects are disabled.
3395         */
3396        private void onUnloadSoundEffects() {
3397            synchronized (mSoundEffectsLock) {
3398                if (mSoundPool == null) {
3399                    return;
3400                }
3401
3402                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3403                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3404                    poolId[fileIdx] = 0;
3405                }
3406
3407                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3408                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3409                        continue;
3410                    }
3411                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3412                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3413                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3414                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3415                    }
3416                }
3417                mSoundPool.release();
3418                mSoundPool = null;
3419            }
3420        }
3421
3422        private void onPlaySoundEffect(int effectType, int volume) {
3423            synchronized (mSoundEffectsLock) {
3424
3425                onLoadSoundEffects();
3426
3427                if (mSoundPool == null) {
3428                    return;
3429                }
3430                float volFloat;
3431                // use default if volume is not specified by caller
3432                if (volume < 0) {
3433                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3434                } else {
3435                    volFloat = (float) volume / 1000.0f;
3436                }
3437
3438                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
3439                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3440                                        volFloat, volFloat, 0, 0, 1.0f);
3441                } else {
3442                    MediaPlayer mediaPlayer = new MediaPlayer();
3443                    try {
3444                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3445                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
3446                        mediaPlayer.setDataSource(filePath);
3447                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3448                        mediaPlayer.prepare();
3449                        mediaPlayer.setVolume(volFloat);
3450                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3451                            public void onCompletion(MediaPlayer mp) {
3452                                cleanupPlayer(mp);
3453                            }
3454                        });
3455                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
3456                            public boolean onError(MediaPlayer mp, int what, int extra) {
3457                                cleanupPlayer(mp);
3458                                return true;
3459                            }
3460                        });
3461                        mediaPlayer.start();
3462                    } catch (IOException ex) {
3463                        Log.w(TAG, "MediaPlayer IOException: "+ex);
3464                    } catch (IllegalArgumentException ex) {
3465                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3466                    } catch (IllegalStateException ex) {
3467                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3468                    }
3469                }
3470            }
3471        }
3472
3473        private void cleanupPlayer(MediaPlayer mp) {
3474            if (mp != null) {
3475                try {
3476                    mp.stop();
3477                    mp.release();
3478                } catch (IllegalStateException ex) {
3479                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3480                }
3481            }
3482        }
3483
3484        private void setForceUse(int usage, int config) {
3485            AudioSystem.setForceUse(usage, config);
3486        }
3487
3488        private void onPersistSafeVolumeState(int state) {
3489            Settings.Global.putInt(mContentResolver,
3490                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3491                    state);
3492        }
3493
3494        @Override
3495        public void handleMessage(Message msg) {
3496
3497            switch (msg.what) {
3498
3499                case MSG_SET_DEVICE_VOLUME:
3500                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3501                    break;
3502
3503                case MSG_SET_ALL_VOLUMES:
3504                    setAllVolumes((VolumeStreamState) msg.obj);
3505                    break;
3506
3507                case MSG_PERSIST_VOLUME:
3508                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
3509                    break;
3510
3511                case MSG_PERSIST_MASTER_VOLUME:
3512                    if (mUseFixedVolume) {
3513                        return;
3514                    }
3515                    Settings.System.putFloatForUser(mContentResolver,
3516                                                    Settings.System.VOLUME_MASTER,
3517                                                    (float)msg.arg1 / (float)1000.0,
3518                                                    UserHandle.USER_CURRENT);
3519                    break;
3520
3521                case MSG_PERSIST_MASTER_VOLUME_MUTE:
3522                    if (mUseFixedVolume) {
3523                        return;
3524                    }
3525                    Settings.System.putIntForUser(mContentResolver,
3526                                                 Settings.System.VOLUME_MASTER_MUTE,
3527                                                 msg.arg1,
3528                                                 UserHandle.USER_CURRENT);
3529                    break;
3530
3531                case MSG_PERSIST_RINGER_MODE:
3532                    // note that the value persisted is the current ringer mode, not the
3533                    // value of ringer mode as of the time the request was made to persist
3534                    persistRingerMode(getRingerMode());
3535                    break;
3536
3537                case MSG_MEDIA_SERVER_DIED:
3538                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
3539                        Log.e(TAG, "Media server died.");
3540                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
3541                                null, 500);
3542                        break;
3543                    }
3544                    Log.e(TAG, "Media server started.");
3545
3546                    // indicate to audio HAL that we start the reconfiguration phase after a media
3547                    // server crash
3548                    // Note that we only execute this when the media server
3549                    // process restarts after a crash, not the first time it is started.
3550                    AudioSystem.setParameters("restarting=true");
3551
3552                    readAndSetLowRamDevice();
3553
3554                    // Restore device connection states
3555                    synchronized (mConnectedDevices) {
3556                        Set set = mConnectedDevices.entrySet();
3557                        Iterator i = set.iterator();
3558                        while (i.hasNext()) {
3559                            Map.Entry device = (Map.Entry)i.next();
3560                            AudioSystem.setDeviceConnectionState(
3561                                                            ((Integer)device.getKey()).intValue(),
3562                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
3563                                                            (String)device.getValue());
3564                        }
3565                    }
3566                    // Restore call state
3567                    AudioSystem.setPhoneState(mMode);
3568
3569                    // Restore forced usage for communcations and record
3570                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3571                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3572                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3573                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3574
3575                    // Restore stream volumes
3576                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3577                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3578                        VolumeStreamState streamState = mStreamStates[streamType];
3579                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
3580
3581                        streamState.applyAllVolumes();
3582                    }
3583
3584                    // Restore ringer mode
3585                    setRingerModeInt(getRingerMode(), false);
3586
3587                    // Restore master volume
3588                    restoreMasterVolume();
3589
3590                    // Reset device orientation (if monitored for this device)
3591                    if (mMonitorOrientation) {
3592                        setOrientationForAudioSystem();
3593                    }
3594                    if (mMonitorRotation) {
3595                        setRotationForAudioSystem();
3596                    }
3597
3598                    synchronized (mBluetoothA2dpEnabledLock) {
3599                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3600                                mBluetoothA2dpEnabled ?
3601                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3602                    }
3603
3604                    synchronized (mSettingsLock) {
3605                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3606                                mDockAudioMediaEnabled ?
3607                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3608                    }
3609
3610                    // indicate the end of reconfiguration phase to audio HAL
3611                    AudioSystem.setParameters("restarting=false");
3612                    break;
3613
3614                case MSG_UNLOAD_SOUND_EFFECTS:
3615                    onUnloadSoundEffects();
3616                    break;
3617
3618                case MSG_LOAD_SOUND_EFFECTS:
3619                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3620                    // can take several dozens of milliseconds to complete
3621                    boolean loaded = onLoadSoundEffects();
3622                    if (msg.obj != null) {
3623                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3624                        synchronized (reply) {
3625                            reply.mStatus = loaded ? 0 : -1;
3626                            reply.notify();
3627                        }
3628                    }
3629                    break;
3630
3631                case MSG_PLAY_SOUND_EFFECT:
3632                    onPlaySoundEffect(msg.arg1, msg.arg2);
3633                    break;
3634
3635                case MSG_BTA2DP_DOCK_TIMEOUT:
3636                    // msg.obj  == address of BTA2DP device
3637                    synchronized (mConnectedDevices) {
3638                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
3639                    }
3640                    break;
3641
3642                case MSG_SET_FORCE_USE:
3643                case MSG_SET_FORCE_BT_A2DP_USE:
3644                    setForceUse(msg.arg1, msg.arg2);
3645                    break;
3646
3647                case MSG_BT_HEADSET_CNCT_FAILED:
3648                    resetBluetoothSco();
3649                    break;
3650
3651                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3652                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3653                    mAudioEventWakeLock.release();
3654                    break;
3655
3656                case MSG_SET_A2DP_CONNECTION_STATE:
3657                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3658                    mAudioEventWakeLock.release();
3659                    break;
3660
3661                case MSG_REPORT_NEW_ROUTES: {
3662                    int N = mRoutesObservers.beginBroadcast();
3663                    if (N > 0) {
3664                        AudioRoutesInfo routes;
3665                        synchronized (mCurAudioRoutes) {
3666                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3667                        }
3668                        while (N > 0) {
3669                            N--;
3670                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3671                            try {
3672                                obs.dispatchAudioRoutesChanged(routes);
3673                            } catch (RemoteException e) {
3674                            }
3675                        }
3676                    }
3677                    mRoutesObservers.finishBroadcast();
3678                    break;
3679                }
3680
3681                case MSG_CHECK_MUSIC_ACTIVE:
3682                    onCheckMusicActive();
3683                    break;
3684
3685                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3686                    onSendBecomingNoisyIntent();
3687                    break;
3688
3689                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3690                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3691                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3692                    break;
3693                case MSG_PERSIST_SAFE_VOLUME_STATE:
3694                    onPersistSafeVolumeState(msg.arg1);
3695                    break;
3696
3697                case MSG_BROADCAST_BT_CONNECTION_STATE:
3698                    onBroadcastScoConnectionState(msg.arg1);
3699                    break;
3700            }
3701        }
3702    }
3703
3704    private class SettingsObserver extends ContentObserver {
3705
3706        SettingsObserver() {
3707            super(new Handler());
3708            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3709                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3710            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3711                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3712        }
3713
3714        @Override
3715        public void onChange(boolean selfChange) {
3716            super.onChange(selfChange);
3717            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3718            //       However there appear to be some missing locks around mRingerModeMutedStreams
3719            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3720            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3721            synchronized (mSettingsLock) {
3722                if (updateRingerModeAffectedStreams()) {
3723                    /*
3724                     * Ensure all stream types that should be affected by ringer mode
3725                     * are in the proper state.
3726                     */
3727                    setRingerModeInt(getRingerMode(), false);
3728                }
3729                readDockAudioSettings(mContentResolver);
3730            }
3731        }
3732    }
3733
3734    // must be called synchronized on mConnectedDevices
3735    private void makeA2dpDeviceAvailable(String address) {
3736        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3737        // audio policy manager
3738        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3739        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3740                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
3741        setBluetoothA2dpOnInt(true);
3742        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3743                AudioSystem.DEVICE_STATE_AVAILABLE,
3744                address);
3745        // Reset A2DP suspend state each time a new sink is connected
3746        AudioSystem.setParameters("A2dpSuspended=false");
3747        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3748                address);
3749    }
3750
3751    private void onSendBecomingNoisyIntent() {
3752        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
3753    }
3754
3755    // must be called synchronized on mConnectedDevices
3756    private void makeA2dpDeviceUnavailableNow(String address) {
3757        synchronized (mA2dpAvrcpLock) {
3758            mAvrcpAbsVolSupported = false;
3759        }
3760        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3761                AudioSystem.DEVICE_STATE_UNAVAILABLE,
3762                address);
3763        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3764    }
3765
3766    // must be called synchronized on mConnectedDevices
3767    private void makeA2dpDeviceUnavailableLater(String address) {
3768        // prevent any activity on the A2DP audio output to avoid unwanted
3769        // reconnection of the sink.
3770        AudioSystem.setParameters("A2dpSuspended=true");
3771        // the device will be made unavailable later, so consider it disconnected right away
3772        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3773        // send the delayed message to make the device unavailable later
3774        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3775        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3776
3777    }
3778
3779    // must be called synchronized on mConnectedDevices
3780    private void cancelA2dpDeviceTimeout() {
3781        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3782    }
3783
3784    // must be called synchronized on mConnectedDevices
3785    private boolean hasScheduledA2dpDockTimeout() {
3786        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3787    }
3788
3789    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
3790    {
3791        if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state);
3792        if (btDevice == null) {
3793            return;
3794        }
3795        String address = btDevice.getAddress();
3796        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3797            address = "";
3798        }
3799
3800        synchronized (mConnectedDevices) {
3801            boolean isConnected =
3802                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
3803                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
3804
3805            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
3806                if (btDevice.isBluetoothDock()) {
3807                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
3808                        // introduction of a delay for transient disconnections of docks when
3809                        // power is rapidly turned off/on, this message will be canceled if
3810                        // we reconnect the dock under a preset delay
3811                        makeA2dpDeviceUnavailableLater(address);
3812                        // the next time isConnected is evaluated, it will be false for the dock
3813                    }
3814                } else {
3815                    makeA2dpDeviceUnavailableNow(address);
3816                }
3817                synchronized (mCurAudioRoutes) {
3818                    if (mCurAudioRoutes.mBluetoothName != null) {
3819                        mCurAudioRoutes.mBluetoothName = null;
3820                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3821                                SENDMSG_NOOP, 0, 0, null, 0);
3822                    }
3823                }
3824            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
3825                if (btDevice.isBluetoothDock()) {
3826                    // this could be a reconnection after a transient disconnection
3827                    cancelA2dpDeviceTimeout();
3828                    mDockAddress = address;
3829                } else {
3830                    // this could be a connection of another A2DP device before the timeout of
3831                    // a dock: cancel the dock timeout, and make the dock unavailable now
3832                    if(hasScheduledA2dpDockTimeout()) {
3833                        cancelA2dpDeviceTimeout();
3834                        makeA2dpDeviceUnavailableNow(mDockAddress);
3835                    }
3836                }
3837                makeA2dpDeviceAvailable(address);
3838                synchronized (mCurAudioRoutes) {
3839                    String name = btDevice.getAliasName();
3840                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3841                        mCurAudioRoutes.mBluetoothName = name;
3842                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3843                                SENDMSG_NOOP, 0, 0, null, 0);
3844                    }
3845                }
3846            }
3847        }
3848    }
3849
3850    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
3851        // address is not used for now, but may be used when multiple a2dp devices are supported
3852        synchronized (mA2dpAvrcpLock) {
3853            mAvrcpAbsVolSupported = support;
3854            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3855                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
3856                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
3857            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3858                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
3859                    mStreamStates[AudioSystem.STREAM_RING], 0);
3860        }
3861    }
3862
3863    private boolean handleDeviceConnection(boolean connected, int device, String params) {
3864        synchronized (mConnectedDevices) {
3865            boolean isConnected = (mConnectedDevices.containsKey(device) &&
3866                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
3867
3868            if (isConnected && !connected) {
3869                AudioSystem.setDeviceConnectionState(device,
3870                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
3871                                              mConnectedDevices.get(device));
3872                 mConnectedDevices.remove(device);
3873                 return true;
3874            } else if (!isConnected && connected) {
3875                 AudioSystem.setDeviceConnectionState(device,
3876                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
3877                                                      params);
3878                 mConnectedDevices.put(new Integer(device), params);
3879                 return true;
3880            }
3881        }
3882        return false;
3883    }
3884
3885    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3886    // sent if none of these devices is connected.
3887    int mBecomingNoisyIntentDevices =
3888            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3889            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL |
3890            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
3891            AudioSystem.DEVICE_OUT_ALL_USB;
3892
3893    // must be called before removing the device from mConnectedDevices
3894    private int checkSendBecomingNoisyIntent(int device, int state) {
3895        int delay = 0;
3896        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3897            int devices = 0;
3898            for (int dev : mConnectedDevices.keySet()) {
3899                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3900                   devices |= dev;
3901                }
3902            }
3903            if (devices == device) {
3904                sendMsg(mAudioHandler,
3905                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
3906                        SENDMSG_REPLACE,
3907                        0,
3908                        0,
3909                        null,
3910                        0);
3911                delay = 1000;
3912            }
3913        }
3914
3915        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3916                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3917            delay = 1000;
3918        }
3919        return delay;
3920    }
3921
3922    private void sendDeviceConnectionIntent(int device, int state, String name)
3923    {
3924        Intent intent = new Intent();
3925
3926        intent.putExtra("state", state);
3927        intent.putExtra("name", name);
3928        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3929
3930        int connType = 0;
3931
3932        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3933            connType = AudioRoutesInfo.MAIN_HEADSET;
3934            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3935            intent.putExtra("microphone", 1);
3936        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3937            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3938            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3939            intent.putExtra("microphone", 0);
3940        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3941            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3942            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3943        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3944            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3945            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3946        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3947            connType = AudioRoutesInfo.MAIN_HDMI;
3948            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3949        }
3950
3951        synchronized (mCurAudioRoutes) {
3952            if (connType != 0) {
3953                int newConn = mCurAudioRoutes.mMainType;
3954                if (state != 0) {
3955                    newConn |= connType;
3956                } else {
3957                    newConn &= ~connType;
3958                }
3959                if (newConn != mCurAudioRoutes.mMainType) {
3960                    mCurAudioRoutes.mMainType = newConn;
3961                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3962                            SENDMSG_NOOP, 0, 0, null, 0);
3963                }
3964            }
3965        }
3966
3967        final long ident = Binder.clearCallingIdentity();
3968        try {
3969            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
3970        } finally {
3971            Binder.restoreCallingIdentity(ident);
3972        }
3973    }
3974
3975    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3976    {
3977        synchronized (mConnectedDevices) {
3978            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3979                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3980                setBluetoothA2dpOnInt(true);
3981            }
3982            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
3983            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
3984            if (state != 0) {
3985                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3986                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
3987                    setBluetoothA2dpOnInt(false);
3988                }
3989                if ((device & mSafeMediaVolumeDevices) != 0) {
3990                    sendMsg(mAudioHandler,
3991                            MSG_CHECK_MUSIC_ACTIVE,
3992                            SENDMSG_REPLACE,
3993                            0,
3994                            0,
3995                            null,
3996                            MUSIC_ACTIVE_POLL_PERIOD_MS);
3997                }
3998            }
3999            if (!isUsb) {
4000                sendDeviceConnectionIntent(device, state, name);
4001            }
4002        }
4003    }
4004
4005    /* cache of the address of the last dock the device was connected to */
4006    private String mDockAddress;
4007
4008    /**
4009     * Receiver for misc intent broadcasts the Phone app cares about.
4010     */
4011    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4012        @Override
4013        public void onReceive(Context context, Intent intent) {
4014            String action = intent.getAction();
4015            int device;
4016            int state;
4017
4018            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4019                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4020                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4021                int config;
4022                switch (dockState) {
4023                    case Intent.EXTRA_DOCK_STATE_DESK:
4024                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4025                        break;
4026                    case Intent.EXTRA_DOCK_STATE_CAR:
4027                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4028                        break;
4029                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
4030                        config = AudioSystem.FORCE_ANALOG_DOCK;
4031                        break;
4032                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
4033                        config = AudioSystem.FORCE_DIGITAL_DOCK;
4034                        break;
4035                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4036                    default:
4037                        config = AudioSystem.FORCE_NONE;
4038                }
4039                // Low end docks have a menu to enable or disable audio
4040                // (see mDockAudioMediaEnabled)
4041                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4042                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4043                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4044                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4045                }
4046                mDockState = dockState;
4047            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
4048                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
4049                                               BluetoothProfile.STATE_DISCONNECTED);
4050                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4051                String address = null;
4052
4053                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4054                if (btDevice == null) {
4055                    return;
4056                }
4057
4058                address = btDevice.getAddress();
4059                BluetoothClass btClass = btDevice.getBluetoothClass();
4060                if (btClass != null) {
4061                    switch (btClass.getDeviceClass()) {
4062                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4063                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4064                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4065                        break;
4066                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4067                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4068                        break;
4069                    }
4070                }
4071
4072                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4073                    address = "";
4074                }
4075
4076                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4077                if (handleDeviceConnection(connected, device, address)) {
4078                    synchronized (mScoClients) {
4079                        if (connected) {
4080                            mBluetoothHeadsetDevice = btDevice;
4081                        } else {
4082                            mBluetoothHeadsetDevice = null;
4083                            resetBluetoothSco();
4084                        }
4085                    }
4086                }
4087            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
4088                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
4089                state = intent.getIntExtra("state", 0);
4090                int alsaCard = intent.getIntExtra("card", -1);
4091                int alsaDevice = intent.getIntExtra("device", -1);
4092                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4093                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4094                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
4095                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
4096                Log.v(TAG, "Broadcast Receiver: Got "
4097                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
4098                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
4099                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
4100                setWiredDeviceConnectionState(device, state, params);
4101            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
4102                boolean broadcast = false;
4103                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
4104                synchronized (mScoClients) {
4105                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4106                    // broadcast intent if the connection was initated by AudioService
4107                    if (!mScoClients.isEmpty() &&
4108                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4109                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4110                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
4111                        broadcast = true;
4112                    }
4113                    switch (btState) {
4114                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
4115                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4116                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4117                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4118                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4119                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4120                        }
4121                        break;
4122                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
4123                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
4124                        mScoAudioState = SCO_STATE_INACTIVE;
4125                        clearAllScoClients(0, false);
4126                        break;
4127                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4128                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4129                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4130                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
4131                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
4132                        }
4133                    default:
4134                        // do not broadcast CONNECTING or invalid state
4135                        broadcast = false;
4136                        break;
4137                    }
4138                }
4139                if (broadcast) {
4140                    broadcastScoConnectionState(scoAudioState);
4141                    //FIXME: this is to maintain compatibility with deprecated intent
4142                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4143                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4144                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
4145                    sendStickyBroadcastToAll(newIntent);
4146                }
4147            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
4148                mBootCompleted = true;
4149                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
4150                        0, 0, null, 0);
4151
4152                mKeyguardManager =
4153                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
4154                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
4155                resetBluetoothSco();
4156                getBluetoothHeadset();
4157                //FIXME: this is to maintain compatibility with deprecated intent
4158                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
4159                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
4160                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
4161                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
4162                sendStickyBroadcastToAll(newIntent);
4163
4164                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
4165                if (adapter != null) {
4166                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
4167                                            BluetoothProfile.A2DP);
4168                }
4169
4170                sendMsg(mAudioHandler,
4171                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
4172                        SENDMSG_REPLACE,
4173                        0,
4174                        0,
4175                        null,
4176                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
4177            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4178                AudioSystem.setParameters("screen_state=on");
4179            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4180                AudioSystem.setParameters("screen_state=off");
4181            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4182                handleConfigurationChanged(context);
4183            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4184                // attempt to stop music playback for background user
4185                sendMsg(mAudioHandler,
4186                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4187                        SENDMSG_REPLACE,
4188                        0,
4189                        0,
4190                        null,
4191                        0);
4192                // the current audio focus owner is no longer valid
4193                mMediaFocusControl.discardAudioFocusOwner();
4194
4195                // load volume settings for new user
4196                readAudioSettings(true /*userSwitch*/);
4197                // preserve STREAM_MUSIC volume from one user to the next.
4198                sendMsg(mAudioHandler,
4199                        MSG_SET_ALL_VOLUMES,
4200                        SENDMSG_QUEUE,
4201                        0,
4202                        0,
4203                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4204            }
4205        }
4206    }
4207
4208    //==========================================================================================
4209    // RemoteControlDisplay / RemoteControlClient / Remote info
4210    //==========================================================================================
4211    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4212            ComponentName listenerComp) {
4213        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4214    }
4215
4216    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4217        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4218    }
4219
4220    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4221        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4222    }
4223
4224    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4225        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4226    }
4227
4228    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4229            boolean wantsSync) {
4230        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4231    }
4232
4233    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4234        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
4235    }
4236
4237    public void unregisterMediaButtonEventReceiverForCalls() {
4238        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
4239    }
4240
4241    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
4242        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
4243    }
4244
4245    public void unregisterMediaButtonIntent(PendingIntent pi) {
4246        mMediaFocusControl.unregisterMediaButtonIntent(pi);
4247    }
4248
4249    public int registerRemoteControlClient(PendingIntent mediaIntent,
4250            IRemoteControlClient rcClient, String callingPckg) {
4251        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
4252    }
4253
4254    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
4255            IRemoteControlClient rcClient) {
4256        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
4257    }
4258
4259    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
4260        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
4261    }
4262
4263    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
4264        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
4265    }
4266
4267    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
4268        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
4269    }
4270
4271    public int getRemoteStreamVolume() {
4272        return mMediaFocusControl.getRemoteStreamVolume();
4273    }
4274
4275    public int getRemoteStreamMaxVolume() {
4276        return mMediaFocusControl.getRemoteStreamMaxVolume();
4277    }
4278
4279    public void setRemoteStreamVolume(int index) {
4280        mMediaFocusControl.setRemoteStreamVolume(index);
4281    }
4282
4283    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
4284        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
4285    }
4286
4287    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4288        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
4289    }
4290
4291    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
4292        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
4293    }
4294
4295    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
4296        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
4297    }
4298
4299    //==========================================================================================
4300    // Audio Focus
4301    //==========================================================================================
4302    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4303            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4304        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4305                clientId, callingPackageName);
4306    }
4307
4308    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4309        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4310    }
4311
4312    public void unregisterAudioFocusClient(String clientId) {
4313        mMediaFocusControl.unregisterAudioFocusClient(clientId);
4314    }
4315
4316    public int getCurrentAudioFocus() {
4317        return mMediaFocusControl.getCurrentAudioFocus();
4318    }
4319
4320    //==========================================================================================
4321    // Device orientation
4322    //==========================================================================================
4323    /**
4324     * Handles device configuration changes that may map to a change in the orientation
4325     * or orientation.
4326     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4327     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4328     */
4329    private void handleConfigurationChanged(Context context) {
4330        try {
4331            // reading new orientation "safely" (i.e. under try catch) in case anything
4332            // goes wrong when obtaining resources and configuration
4333            Configuration config = context.getResources().getConfiguration();
4334            // TODO merge rotation and orientation
4335            if (mMonitorOrientation) {
4336                int newOrientation = config.orientation;
4337                if (newOrientation != mDeviceOrientation) {
4338                    mDeviceOrientation = newOrientation;
4339                    setOrientationForAudioSystem();
4340                }
4341            }
4342            if (mMonitorRotation) {
4343                int newRotation = ((WindowManager) context.getSystemService(
4344                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4345                if (newRotation != mDeviceRotation) {
4346                    mDeviceRotation = newRotation;
4347                    setRotationForAudioSystem();
4348                }
4349            }
4350            sendMsg(mAudioHandler,
4351                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4352                    SENDMSG_REPLACE,
4353                    0,
4354                    0,
4355                    null,
4356                    0);
4357
4358            boolean cameraSoundForced = mContext.getResources().getBoolean(
4359                    com.android.internal.R.bool.config_camera_sound_forced);
4360            synchronized (mSettingsLock) {
4361                synchronized (mCameraSoundForced) {
4362                    if (cameraSoundForced != mCameraSoundForced) {
4363                        mCameraSoundForced = cameraSoundForced;
4364
4365                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4366                        if (cameraSoundForced) {
4367                            s.setAllIndexesToMax();
4368                            mRingerModeAffectedStreams &=
4369                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4370                        } else {
4371                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4372                            mRingerModeAffectedStreams |=
4373                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4374                        }
4375                        // take new state into account for streams muted by ringer mode
4376                        setRingerModeInt(getRingerMode(), false);
4377
4378                        sendMsg(mAudioHandler,
4379                                MSG_SET_FORCE_USE,
4380                                SENDMSG_QUEUE,
4381                                AudioSystem.FOR_SYSTEM,
4382                                cameraSoundForced ?
4383                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4384                                null,
4385                                0);
4386
4387                        sendMsg(mAudioHandler,
4388                                MSG_SET_ALL_VOLUMES,
4389                                SENDMSG_QUEUE,
4390                                0,
4391                                0,
4392                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4393                    }
4394                }
4395            }
4396            mVolumePanel.setLayoutDirection(config.getLayoutDirection());
4397        } catch (Exception e) {
4398            Log.e(TAG, "Error handling configuration change: ", e);
4399        }
4400    }
4401
4402    private void setOrientationForAudioSystem() {
4403        switch (mDeviceOrientation) {
4404            case Configuration.ORIENTATION_LANDSCAPE:
4405                //Log.i(TAG, "orientation is landscape");
4406                AudioSystem.setParameters("orientation=landscape");
4407                break;
4408            case Configuration.ORIENTATION_PORTRAIT:
4409                //Log.i(TAG, "orientation is portrait");
4410                AudioSystem.setParameters("orientation=portrait");
4411                break;
4412            case Configuration.ORIENTATION_SQUARE:
4413                //Log.i(TAG, "orientation is square");
4414                AudioSystem.setParameters("orientation=square");
4415                break;
4416            case Configuration.ORIENTATION_UNDEFINED:
4417                //Log.i(TAG, "orientation is undefined");
4418                AudioSystem.setParameters("orientation=undefined");
4419                break;
4420            default:
4421                Log.e(TAG, "Unknown orientation");
4422        }
4423    }
4424
4425    private void setRotationForAudioSystem() {
4426        switch (mDeviceRotation) {
4427            case Surface.ROTATION_0:
4428                AudioSystem.setParameters("rotation=0");
4429                break;
4430            case Surface.ROTATION_90:
4431                AudioSystem.setParameters("rotation=90");
4432                break;
4433            case Surface.ROTATION_180:
4434                AudioSystem.setParameters("rotation=180");
4435                break;
4436            case Surface.ROTATION_270:
4437                AudioSystem.setParameters("rotation=270");
4438                break;
4439            default:
4440                Log.e(TAG, "Unknown device rotation");
4441        }
4442    }
4443
4444
4445    // Handles request to override default use of A2DP for media.
4446    public void setBluetoothA2dpOnInt(boolean on) {
4447        synchronized (mBluetoothA2dpEnabledLock) {
4448            mBluetoothA2dpEnabled = on;
4449            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4450            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4451                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4452        }
4453    }
4454
4455    @Override
4456    public void setRingtonePlayer(IRingtonePlayer player) {
4457        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4458        mRingtonePlayer = player;
4459    }
4460
4461    @Override
4462    public IRingtonePlayer getRingtonePlayer() {
4463        return mRingtonePlayer;
4464    }
4465
4466    @Override
4467    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4468        synchronized (mCurAudioRoutes) {
4469            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4470            mRoutesObservers.register(observer);
4471            return routes;
4472        }
4473    }
4474
4475
4476    //==========================================================================================
4477    // Safe media volume management.
4478    // MUSIC stream volume level is limited when headphones are connected according to safety
4479    // regulation. When the user attempts to raise the volume above the limit, a warning is
4480    // displayed and the user has to acknowlegde before the volume is actually changed.
4481    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4482    // property. Platforms with a different limit must set this property accordingly in their
4483    // overlay.
4484    //==========================================================================================
4485
4486    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4487    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4488    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4489    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4490    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4491    // (when user opts out).
4492    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4493    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4494    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4495    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4496    private Integer mSafeMediaVolumeState;
4497
4498    private int mMcc = 0;
4499    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4500    private int mSafeMediaVolumeIndex;
4501    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4502    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4503                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4504    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4505    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4506    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4507    private int mMusicActiveMs;
4508    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4509    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4510    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4511
4512    private void setSafeMediaVolumeEnabled(boolean on) {
4513        synchronized (mSafeMediaVolumeState) {
4514            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4515                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4516                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4517                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4518                    enforceSafeMediaVolume();
4519                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4520                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4521                    mMusicActiveMs = 0;
4522                    sendMsg(mAudioHandler,
4523                            MSG_CHECK_MUSIC_ACTIVE,
4524                            SENDMSG_REPLACE,
4525                            0,
4526                            0,
4527                            null,
4528                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4529                }
4530            }
4531        }
4532    }
4533
4534    private void enforceSafeMediaVolume() {
4535        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4536        int devices = mSafeMediaVolumeDevices;
4537        int i = 0;
4538
4539        while (devices != 0) {
4540            int device = 1 << i++;
4541            if ((device & devices) == 0) {
4542                continue;
4543            }
4544            int index = streamState.getIndex(device);
4545            if (index > mSafeMediaVolumeIndex) {
4546                streamState.setIndex(mSafeMediaVolumeIndex, device);
4547                sendMsg(mAudioHandler,
4548                        MSG_SET_DEVICE_VOLUME,
4549                        SENDMSG_QUEUE,
4550                        device,
4551                        0,
4552                        streamState,
4553                        0);
4554            }
4555            devices &= ~device;
4556        }
4557    }
4558
4559    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4560        synchronized (mSafeMediaVolumeState) {
4561            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4562                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4563                    ((device & mSafeMediaVolumeDevices) != 0) &&
4564                    (index > mSafeMediaVolumeIndex)) {
4565                return false;
4566            }
4567            return true;
4568        }
4569    }
4570
4571    public void disableSafeMediaVolume() {
4572        synchronized (mSafeMediaVolumeState) {
4573            setSafeMediaVolumeEnabled(false);
4574            if (mPendingVolumeCommand != null) {
4575                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4576                                  mPendingVolumeCommand.mIndex,
4577                                  mPendingVolumeCommand.mFlags,
4578                                  mPendingVolumeCommand.mDevice);
4579                mPendingVolumeCommand = null;
4580            }
4581        }
4582    }
4583
4584
4585    //==========================================================================================
4586    // Camera shutter sound policy.
4587    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4588    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4589    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4590    //==========================================================================================
4591
4592    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4593    private Boolean mCameraSoundForced;
4594
4595    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4596    public boolean isCameraSoundForced() {
4597        synchronized (mCameraSoundForced) {
4598            return mCameraSoundForced;
4599        }
4600    }
4601
4602    private static final String[] RINGER_MODE_NAMES = new String[] {
4603            "SILENT",
4604            "VIBRATE",
4605            "NORMAL"
4606    };
4607
4608    private void dumpRingerMode(PrintWriter pw) {
4609        pw.println("\nRinger mode: ");
4610        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4611        pw.print("- ringer mode affected streams = 0x");
4612        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4613        pw.print("- ringer mode muted streams = 0x");
4614        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4615    }
4616
4617    @Override
4618    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4619        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4620
4621        mMediaFocusControl.dump(pw);
4622        dumpStreamStates(pw);
4623        dumpRingerMode(pw);
4624        pw.println("\nAudio routes:");
4625        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4626        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
4627    }
4628
4629    // Inform AudioFlinger of our device's low RAM attribute
4630    private static void readAndSetLowRamDevice()
4631    {
4632        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4633        if (status != 0) {
4634            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4635        }
4636    }
4637}
4638