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