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