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