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