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