AudioService.java revision f26f01784e1c733c53cad3ed31918e73448ce369
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.BroadcastReceiver; 37import android.content.ComponentName; 38import android.content.ContentResolver; 39import android.content.Context; 40import android.content.Intent; 41import android.content.IntentFilter; 42import android.content.pm.PackageManager; 43import android.content.res.Configuration; 44import android.database.ContentObserver; 45import android.media.MediaPlayer.OnCompletionListener; 46import android.media.MediaPlayer.OnErrorListener; 47import android.os.Binder; 48import android.os.Bundle; 49import android.os.Environment; 50import android.os.Handler; 51import android.os.IBinder; 52import android.os.Looper; 53import android.os.Message; 54import android.os.PowerManager; 55import android.os.RemoteException; 56import android.os.ServiceManager; 57import android.os.SystemProperties; 58import android.provider.Settings; 59import android.provider.Settings.System; 60import android.telephony.PhoneStateListener; 61import android.telephony.TelephonyManager; 62import android.util.Log; 63import android.view.KeyEvent; 64import android.view.VolumePanel; 65 66import com.android.internal.telephony.ITelephony; 67 68import java.io.FileDescriptor; 69import java.io.IOException; 70import java.io.PrintWriter; 71import java.util.ArrayList; 72import java.util.HashMap; 73import java.util.Iterator; 74import java.util.List; 75import java.util.Map; 76import java.util.NoSuchElementException; 77import java.util.Set; 78import java.util.Stack; 79 80/** 81 * The implementation of the volume manager service. 82 * <p> 83 * This implementation focuses on delivering a responsive UI. Most methods are 84 * asynchronous to external calls. For example, the task of setting a volume 85 * will update our internal state, but in a separate thread will set the system 86 * volume and later persist to the database. Similarly, setting the ringer mode 87 * will update the state and broadcast a change and in a separate thread later 88 * persist the ringer mode. 89 * 90 * @hide 91 */ 92public class AudioService extends IAudioService.Stub implements OnFinished { 93 94 private static final String TAG = "AudioService"; 95 96 /** Debug remote control client/display feature */ 97 protected static final boolean DEBUG_RC = false; 98 99 /** How long to delay before persisting a change in volume/ringer mode. */ 100 private static final int PERSIST_DELAY = 500; 101 102 private Context mContext; 103 private ContentResolver mContentResolver; 104 private boolean mVoiceCapable; 105 106 /** The UI */ 107 private VolumePanel mVolumePanel; 108 109 // sendMsg() flags 110 /** If the msg is already queued, replace it with this one. */ 111 private static final int SENDMSG_REPLACE = 0; 112 /** If the msg is already queued, ignore this one and leave the old. */ 113 private static final int SENDMSG_NOOP = 1; 114 /** If the msg is already queued, queue this one and leave the old. */ 115 private static final int SENDMSG_QUEUE = 2; 116 117 // AudioHandler message.whats 118 private static final int MSG_SET_DEVICE_VOLUME = 0; 119 private static final int MSG_PERSIST_VOLUME = 1; 120 private static final int MSG_PERSIST_MASTER_VOLUME = 2; 121 private static final int MSG_PERSIST_RINGER_MODE = 3; 122 private static final int MSG_PERSIST_VIBRATE_SETTING = 4; 123 private static final int MSG_MEDIA_SERVER_DIED = 5; 124 private static final int MSG_MEDIA_SERVER_STARTED = 6; 125 private static final int MSG_PLAY_SOUND_EFFECT = 7; 126 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8; 127 private static final int MSG_LOAD_SOUND_EFFECTS = 9; 128 private static final int MSG_SET_FORCE_USE = 10; 129 private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11; 130 private static final int MSG_BT_HEADSET_CNCT_FAILED = 12; 131 private static final int MSG_RCDISPLAY_CLEAR = 13; 132 private static final int MSG_RCDISPLAY_UPDATE = 14; 133 private static final int MSG_SET_ALL_VOLUMES = 15; 134 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 16; 135 136 137 // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be 138 // persisted 139 private static final int PERSIST_CURRENT = 0x1; 140 private static final int PERSIST_LAST_AUDIBLE = 0x2; 141 142 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 143 // Timeout for connection to bluetooth headset service 144 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 145 146 /** @see AudioSystemThread */ 147 private AudioSystemThread mAudioSystemThread; 148 /** @see AudioHandler */ 149 private AudioHandler mAudioHandler; 150 /** @see VolumeStreamState */ 151 private VolumeStreamState[] mStreamStates; 152 private SettingsObserver mSettingsObserver; 153 154 private int mMode; 155 // protects mRingerMode 156 private final Object mSettingsLock = new Object(); 157 158 private boolean mMediaServerOk; 159 160 private SoundPool mSoundPool; 161 private final Object mSoundEffectsLock = new Object(); 162 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 163 private static final int SOUND_EFFECT_VOLUME = 1000; 164 165 // Internally master volume is a float in the 0.0 - 1.0 range, 166 // but to support integer based AudioManager API we translate it to 0 - 100 167 private static final int MAX_MASTER_VOLUME = 100; 168 169 // Maximum volume adjust steps allowed in a single batch call. 170 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 171 172 /* Sound effect file names */ 173 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 174 private static final String[] SOUND_EFFECT_FILES = new String[] { 175 "Effect_Tick.ogg", 176 "KeypressStandard.ogg", 177 "KeypressSpacebar.ogg", 178 "KeypressDelete.ogg", 179 "KeypressReturn.ogg" 180 }; 181 182 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 183 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 184 * uses soundpool (second column) */ 185 private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 186 {0, -1}, // FX_KEY_CLICK 187 {0, -1}, // FX_FOCUS_NAVIGATION_UP 188 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 189 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 190 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 191 {1, -1}, // FX_KEYPRESS_STANDARD 192 {2, -1}, // FX_KEYPRESS_SPACEBAR 193 {3, -1}, // FX_FOCUS_DELETE 194 {4, -1} // FX_FOCUS_RETURN 195 }; 196 197 /** @hide Maximum volume index values for audio streams */ 198 private final int[] MAX_STREAM_VOLUME = new int[] { 199 5, // STREAM_VOICE_CALL 200 7, // STREAM_SYSTEM 201 7, // STREAM_RING 202 15, // STREAM_MUSIC 203 7, // STREAM_ALARM 204 7, // STREAM_NOTIFICATION 205 15, // STREAM_BLUETOOTH_SCO 206 7, // STREAM_SYSTEM_ENFORCED 207 15, // STREAM_DTMF 208 15 // STREAM_TTS 209 }; 210 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 211 * of another stream: This avoids multiplying the volume settings for hidden 212 * stream types that follow other stream behavior for volume settings 213 * NOTE: do not create loops in aliases! 214 * Some streams alias to different streams according to device category (phone or tablet) or 215 * use case (in call s off call...).See updateStreamVolumeAlias() for more details 216 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 217 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 218 private final int[] STREAM_VOLUME_ALIAS = new int[] { 219 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 220 AudioSystem.STREAM_RING, // STREAM_SYSTEM 221 AudioSystem.STREAM_RING, // STREAM_RING 222 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 223 AudioSystem.STREAM_ALARM, // STREAM_ALARM 224 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 225 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 226 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 227 AudioSystem.STREAM_RING, // STREAM_DTMF 228 AudioSystem.STREAM_MUSIC // STREAM_TTS 229 }; 230 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 231 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 232 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 233 AudioSystem.STREAM_RING, // STREAM_RING 234 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 235 AudioSystem.STREAM_ALARM, // STREAM_ALARM 236 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 237 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 238 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 239 AudioSystem.STREAM_MUSIC, // STREAM_DTMF 240 AudioSystem.STREAM_MUSIC // STREAM_TTS 241 }; 242 private int[] mStreamVolumeAlias; 243 244 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 245 public void onError(int error) { 246 switch (error) { 247 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 248 if (mMediaServerOk) { 249 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 250 null, 1500); 251 mMediaServerOk = false; 252 } 253 break; 254 case AudioSystem.AUDIO_STATUS_OK: 255 if (!mMediaServerOk) { 256 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 257 null, 0); 258 mMediaServerOk = true; 259 } 260 break; 261 default: 262 break; 263 } 264 } 265 }; 266 267 /** 268 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 269 * {@link AudioManager#RINGER_MODE_SILENT}, or 270 * {@link AudioManager#RINGER_MODE_VIBRATE}. 271 */ 272 // protected by mSettingsLock 273 private int mRingerMode; 274 275 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 276 private int mRingerModeAffectedStreams; 277 278 // Streams currently muted by ringer mode 279 private int mRingerModeMutedStreams; 280 281 /** @see System#MUTE_STREAMS_AFFECTED */ 282 private int mMuteAffectedStreams; 283 284 /** 285 * Has multiple bits per vibrate type to indicate the type's vibrate 286 * setting. See {@link #setVibrateSetting(int, int)}. 287 * <p> 288 * NOTE: This is not the final decision of whether vibrate is on/off for the 289 * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. 290 */ 291 private int mVibrateSetting; 292 293 // Broadcast receiver for device connections intent broadcasts 294 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 295 296 // Used to alter media button redirection when the phone is ringing. 297 private boolean mIsRinging = false; 298 299 // Devices currently connected 300 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 301 302 // Forced device usage for communications 303 private int mForcedUseForComm; 304 305 // True if we have master volume support 306 private final boolean mUseMasterVolume; 307 308 private final int[] mMasterVolumeRamp; 309 310 // List of binder death handlers for setMode() client processes. 311 // The last process to have called setMode() is at the top of the list. 312 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 313 314 // List of clients having issued a SCO start request 315 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 316 317 // BluetoothHeadset API to control SCO connection 318 private BluetoothHeadset mBluetoothHeadset; 319 320 // Bluetooth headset device 321 private BluetoothDevice mBluetoothHeadsetDevice; 322 323 // Indicate if SCO audio connection is currently active and if the initiator is 324 // audio service (internal) or bluetooth headset (external) 325 private int mScoAudioState; 326 // SCO audio state is not active 327 private static final int SCO_STATE_INACTIVE = 0; 328 // SCO audio activation request waiting for headset service to connect 329 private static final int SCO_STATE_ACTIVATE_REQ = 1; 330 // SCO audio state is active or starting due to a local request to start a virtual call 331 private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 332 // SCO audio deactivation request waiting for headset service to connect 333 private static final int SCO_STATE_DEACTIVATE_REQ = 5; 334 335 // SCO audio state is active due to an action in BT handsfree (either voice recognition or 336 // in call audio) 337 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 338 // Deactivation request for all SCO connections (initiated by audio mode change) 339 // waiting for headset service to connect 340 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 341 342 // Current connection state indicated by bluetooth headset 343 private int mScoConnectionState; 344 345 // true if boot sequence has been completed 346 private boolean mBootCompleted; 347 // listener for SoundPool sample load completion indication 348 private SoundPoolCallback mSoundPoolCallBack; 349 // thread for SoundPool listener 350 private SoundPoolListenerThread mSoundPoolListenerThread; 351 // message looper for SoundPool listener 352 private Looper mSoundPoolLooper = null; 353 // default volume applied to sound played with playSoundEffect() 354 private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = 0; 355 // volume applied to sound played with playSoundEffect() read from ro.config.sound_fx_volume 356 private int SOUND_EFFECT_VOLUME_DB; 357 // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification 358 // stopped 359 private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; 360 // previous volume adjustment direction received by checkForRingerModeChange() 361 private int mPrevVolDirection = AudioManager.ADJUST_SAME; 362 // Keyguard manager proxy 363 private KeyguardManager mKeyguardManager; 364 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 365 // is controlled by Vol keys. 366 private int mVolumeControlStream = -1; 367 private final Object mForceControlStreamLock = new Object(); 368 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 369 // server process so in theory it is not necessary to monitor the client death. 370 // However it is good to be ready for future evolutions. 371 private ForceControlStreamClient mForceControlStreamClient = null; 372 // Used to play ringtones outside system_server 373 private volatile IRingtonePlayer mRingtonePlayer; 374 375 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 376 377 /////////////////////////////////////////////////////////////////////////// 378 // Construction 379 /////////////////////////////////////////////////////////////////////////// 380 381 /** @hide */ 382 public AudioService(Context context) { 383 mContext = context; 384 mContentResolver = context.getContentResolver(); 385 mVoiceCapable = mContext.getResources().getBoolean( 386 com.android.internal.R.bool.config_voice_capable); 387 388 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 389 mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mediaKeyEvent"); 390 391 // Intialized volume 392 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 393 "ro.config.vc_call_vol_steps", 394 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 395 396 SOUND_EFFECT_VOLUME_DB = SystemProperties.getInt( 397 "ro.config.sound_fx_volume", 398 SOUND_EFFECT_DEFAULT_VOLUME_DB); 399 400 mVolumePanel = new VolumePanel(context, this); 401 mMode = AudioSystem.MODE_NORMAL; 402 mForcedUseForComm = AudioSystem.FORCE_NONE; 403 createAudioSystemThread(); 404 readPersistedSettings(); 405 mSettingsObserver = new SettingsObserver(); 406 updateStreamVolumeAlias(false /*updateVolumes*/); 407 createStreamStates(); 408 409 mMediaServerOk = true; 410 411 // Call setRingerModeInt() to apply correct mute 412 // state on streams affected by ringer mode. 413 mRingerModeMutedStreams = 0; 414 setRingerModeInt(getRingerMode(), false); 415 416 AudioSystem.setErrorCallback(mAudioSystemCallback); 417 418 // Register for device connection intent broadcasts. 419 IntentFilter intentFilter = 420 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 421 422 intentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 423 intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 424 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 425 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 426 intentFilter.addAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 427 intentFilter.addAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 428 intentFilter.addAction(Intent.ACTION_HDMI_AUDIO_PLUG); 429 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 430 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 431 intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 432 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 433 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 434 435 // Register a configuration change listener only if requested by system properties 436 // to monitor orientation changes (off by default) 437 if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 438 Log.v(TAG, "monitoring device orientation"); 439 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 440 // initialize orientation in AudioSystem 441 setOrientationForAudioSystem(); 442 } 443 444 context.registerReceiver(mReceiver, intentFilter); 445 446 // Register for package removal intent broadcasts for media button receiver persistence 447 IntentFilter pkgFilter = new IntentFilter(); 448 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 449 pkgFilter.addDataScheme("package"); 450 context.registerReceiver(mReceiver, pkgFilter); 451 452 // Register for phone state monitoring 453 TelephonyManager tmgr = (TelephonyManager) 454 context.getSystemService(Context.TELEPHONY_SERVICE); 455 tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 456 457 mUseMasterVolume = context.getResources().getBoolean( 458 com.android.internal.R.bool.config_useMasterVolume); 459 restoreMasterVolume(); 460 461 mMasterVolumeRamp = context.getResources().getIntArray( 462 com.android.internal.R.array.config_masterVolumeRamp); 463 } 464 465 private void createAudioSystemThread() { 466 mAudioSystemThread = new AudioSystemThread(); 467 mAudioSystemThread.start(); 468 waitForAudioHandlerCreation(); 469 } 470 471 /** Waits for the volume handler to be created by the other thread. */ 472 private void waitForAudioHandlerCreation() { 473 synchronized(this) { 474 while (mAudioHandler == null) { 475 try { 476 // Wait for mAudioHandler to be set by the other thread 477 wait(); 478 } catch (InterruptedException e) { 479 Log.e(TAG, "Interrupted while waiting on volume handler."); 480 } 481 } 482 } 483 } 484 485 private void createStreamStates() { 486 int numStreamTypes = AudioSystem.getNumStreamTypes(); 487 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 488 489 for (int i = 0; i < numStreamTypes; i++) { 490 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 491 } 492 493 // Correct stream index values for streams with aliases 494 for (int i = 0; i < numStreamTypes; i++) { 495 int device = getDeviceForStream(i); 496 if (mStreamVolumeAlias[i] != i) { 497 int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */), 498 mStreamVolumeAlias[i], 499 i); 500 streams[i].mIndex.put(device, streams[i].getValidIndex(index)); 501 streams[i].applyDeviceVolume(device); 502 index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */), 503 mStreamVolumeAlias[i], 504 i); 505 streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index)); 506 } 507 } 508 } 509 510 511 private void updateStreamVolumeAlias(boolean updateVolumes) { 512 int dtmfStreamAlias; 513 if (mVoiceCapable) { 514 mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 515 dtmfStreamAlias = AudioSystem.STREAM_RING; 516 } else { 517 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 518 dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 519 } 520 if (isInCommunication()) { 521 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 522 } 523 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 524 if (updateVolumes) { 525 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 526 false /*lastAudible*/); 527 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 528 true /*lastAudible*/); 529 sendMsg(mAudioHandler, 530 MSG_SET_ALL_VOLUMES, 531 SENDMSG_QUEUE, 532 0, 533 0, 534 mStreamStates[AudioSystem.STREAM_DTMF], 0); 535 } 536 } 537 538 private void readPersistedSettings() { 539 final ContentResolver cr = mContentResolver; 540 541 int ringerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 542 // sanity check in case the settings are restored from a device with incompatible 543 // ringer modes 544 if (!AudioManager.isValidRingerMode(ringerMode)) { 545 ringerMode = AudioManager.RINGER_MODE_NORMAL; 546 System.putInt(cr, System.MODE_RINGER, ringerMode); 547 } 548 synchronized(mSettingsLock) { 549 mRingerMode = ringerMode; 550 } 551 552 mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); 553 554 // make sure settings for ringer mode are consistent with device type: non voice capable 555 // devices (tablets) include media stream in silent mode whereas phones don't. 556 mRingerModeAffectedStreams = Settings.System.getInt(cr, 557 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 558 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 559 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 560 if (mVoiceCapable) { 561 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 562 } else { 563 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 564 } 565 Settings.System.putInt(cr, 566 Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams); 567 568 mMuteAffectedStreams = System.getInt(cr, 569 System.MUTE_STREAMS_AFFECTED, 570 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 571 572 boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1; 573 AudioSystem.setMasterMute(masterMute); 574 broadcastMasterMuteStatus(masterMute); 575 576 // Each stream will read its own persisted settings 577 578 // Broadcast the sticky intent 579 broadcastRingerMode(ringerMode); 580 581 // Broadcast vibrate settings 582 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 583 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 584 585 // Restore the default media button receiver from the system settings 586 restoreMediaButtonReceiver(); 587 } 588 589 private int rescaleIndex(int index, int srcStream, int dstStream) { 590 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 591 } 592 593 /////////////////////////////////////////////////////////////////////////// 594 // IPC methods 595 /////////////////////////////////////////////////////////////////////////// 596 597 /** @see AudioManager#adjustVolume(int, int) */ 598 public void adjustVolume(int direction, int flags) { 599 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 600 } 601 602 /** @see AudioManager#adjustVolume(int, int, int) */ 603 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 604 605 int streamType; 606 if (mVolumeControlStream != -1) { 607 streamType = mVolumeControlStream; 608 } else { 609 streamType = getActiveStreamType(suggestedStreamType); 610 } 611 612 // Play sounds on STREAM_RING only and if lock screen is not on. 613 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && 614 ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) 615 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { 616 flags &= ~AudioManager.FLAG_PLAY_SOUND; 617 } 618 619 adjustStreamVolume(streamType, direction, flags); 620 } 621 622 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 623 public void adjustStreamVolume(int streamType, int direction, int flags) { 624 ensureValidDirection(direction); 625 ensureValidStreamType(streamType); 626 627 // use stream type alias here so that streams with same alias have the same behavior, 628 // including with regard to silent mode control (e.g the use of STREAM_RING below and in 629 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) 630 int streamTypeAlias = mStreamVolumeAlias[streamType]; 631 VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 632 633 final int device = getDeviceForStream(streamTypeAlias); 634 // get last audible index if stream is muted, current index otherwise 635 final int oldIndex = streamState.getIndex(device, 636 (streamState.muteCount() != 0) /* lastAudible */); 637 boolean adjustVolume = true; 638 639 // If either the client forces allowing ringer modes for this adjustment, 640 // or the stream type is one that is affected by ringer modes 641 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 642 streamTypeAlias == AudioSystem.STREAM_RING || 643 (!mVoiceCapable && streamTypeAlias == AudioSystem.STREAM_MUSIC)) { 644 int ringerMode = getRingerMode(); 645 // do not vibrate if already in vibrate mode 646 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 647 flags &= ~AudioManager.FLAG_VIBRATE; 648 } 649 // Check if the ringer mode changes with this volume adjustment. If 650 // it does, it will handle adjusting the volume, so we won't below 651 adjustVolume = checkForRingerModeChange(oldIndex, direction, streamTypeAlias); 652 } 653 654 // If stream is muted, adjust last audible index only 655 int index; 656 if (streamState.muteCount() != 0) { 657 if (adjustVolume) { 658 // adjust volume on all stream types sharing the same alias otherwise a query 659 // on last audible index for an alias would not give the correct value 660 int numStreamTypes = AudioSystem.getNumStreamTypes(); 661 for (int i = numStreamTypes - 1; i >= 0; i--) { 662 if (mStreamVolumeAlias[i] == streamTypeAlias) { 663 VolumeStreamState s = mStreamStates[i]; 664 665 s.adjustLastAudibleIndex(direction, device); 666 // Post a persist volume msg 667 sendMsg(mAudioHandler, 668 MSG_PERSIST_VOLUME, 669 SENDMSG_QUEUE, 670 PERSIST_LAST_AUDIBLE, 671 device, 672 s, 673 PERSIST_DELAY); 674 } 675 } 676 } 677 index = streamState.getIndex(device, true /* lastAudible */); 678 } else { 679 if (adjustVolume && streamState.adjustIndex(direction, device)) { 680 // Post message to set system volume (it in turn will post a message 681 // to persist). Do not change volume if stream is muted. 682 sendMsg(mAudioHandler, 683 MSG_SET_DEVICE_VOLUME, 684 SENDMSG_QUEUE, 685 device, 686 0, 687 streamState, 688 0); 689 } 690 index = streamState.getIndex(device, false /* lastAudible */); 691 } 692 693 sendVolumeUpdate(streamType, oldIndex, index, flags); 694 } 695 696 /** @see AudioManager#adjustMasterVolume(int) */ 697 public void adjustMasterVolume(int steps, int flags) { 698 ensureValidSteps(steps); 699 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 700 int delta = 0; 701 int numSteps = Math.abs(steps); 702 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER; 703 for (int i = 0; i < numSteps; ++i) { 704 delta = findVolumeDelta(direction, volume); 705 volume += delta; 706 } 707 708 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps); 709 setMasterVolume(volume, flags); 710 } 711 712 /** @see AudioManager#setStreamVolume(int, int, int) */ 713 public void setStreamVolume(int streamType, int index, int flags) { 714 ensureValidStreamType(streamType); 715 VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]]; 716 717 final int device = getDeviceForStream(streamType); 718 // get last audible index if stream is muted, current index otherwise 719 final int oldIndex = streamState.getIndex(device, 720 (streamState.muteCount() != 0) /* lastAudible */); 721 722 // setting volume on master stream type also controls silent mode 723 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 724 (mStreamVolumeAlias[streamType] == getMasterStreamType())) { 725 int newRingerMode; 726 if (index == 0) { 727 newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 728 ? AudioManager.RINGER_MODE_VIBRATE 729 : AudioManager.RINGER_MODE_SILENT; 730 setStreamVolumeInt(mStreamVolumeAlias[streamType], 731 index, 732 device, 733 false, 734 true); 735 } else { 736 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 737 } 738 setRingerMode(newRingerMode); 739 } 740 741 index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); 742 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true); 743 // get last audible index if stream is muted, current index otherwise 744 index = streamState.getIndex(device, 745 (streamState.muteCount() != 0) /* lastAudible */); 746 747 sendVolumeUpdate(streamType, oldIndex, index, flags); 748 } 749 750 /** @see AudioManager#forceVolumeControlStream(int) */ 751 public void forceVolumeControlStream(int streamType, IBinder cb) { 752 synchronized(mForceControlStreamLock) { 753 mVolumeControlStream = streamType; 754 if (mVolumeControlStream == -1) { 755 if (mForceControlStreamClient != null) { 756 mForceControlStreamClient.release(); 757 mForceControlStreamClient = null; 758 } 759 } else { 760 mForceControlStreamClient = new ForceControlStreamClient(cb); 761 } 762 } 763 } 764 765 private class ForceControlStreamClient implements IBinder.DeathRecipient { 766 private IBinder mCb; // To be notified of client's death 767 768 ForceControlStreamClient(IBinder cb) { 769 if (cb != null) { 770 try { 771 cb.linkToDeath(this, 0); 772 } catch (RemoteException e) { 773 // Client has died! 774 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death"); 775 cb = null; 776 } 777 } 778 mCb = cb; 779 } 780 781 public void binderDied() { 782 synchronized(mForceControlStreamLock) { 783 Log.w(TAG, "SCO client died"); 784 if (mForceControlStreamClient != this) { 785 Log.w(TAG, "unregistered control stream client died"); 786 } else { 787 mForceControlStreamClient = null; 788 mVolumeControlStream = -1; 789 } 790 } 791 } 792 793 public void release() { 794 if (mCb != null) { 795 mCb.unlinkToDeath(this, 0); 796 mCb = null; 797 } 798 } 799 } 800 801 private int findVolumeDelta(int direction, int volume) { 802 int delta = 0; 803 if (direction == AudioManager.ADJUST_RAISE) { 804 if (volume == MAX_MASTER_VOLUME) { 805 return 0; 806 } 807 // This is the default value if we make it to the end 808 delta = mMasterVolumeRamp[1]; 809 // If we're raising the volume move down the ramp array until we 810 // find the volume we're above and use that groups delta. 811 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) { 812 if (volume >= mMasterVolumeRamp[i - 1]) { 813 delta = mMasterVolumeRamp[i]; 814 break; 815 } 816 } 817 } else if (direction == AudioManager.ADJUST_LOWER){ 818 if (volume == 0) { 819 return 0; 820 } 821 int length = mMasterVolumeRamp.length; 822 // This is the default value if we make it to the end 823 delta = -mMasterVolumeRamp[length - 1]; 824 // If we're lowering the volume move up the ramp array until we 825 // find the volume we're below and use the group below it's delta 826 for (int i = 2; i < length; i += 2) { 827 if (volume <= mMasterVolumeRamp[i]) { 828 delta = -mMasterVolumeRamp[i - 1]; 829 break; 830 } 831 } 832 } 833 return delta; 834 } 835 836 // UI update and Broadcast Intent 837 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { 838 if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { 839 streamType = AudioSystem.STREAM_NOTIFICATION; 840 } 841 842 mVolumePanel.postVolumeChanged(streamType, flags); 843 844 oldIndex = (oldIndex + 5) / 10; 845 index = (index + 5) / 10; 846 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 847 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 848 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 849 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 850 mContext.sendBroadcast(intent); 851 } 852 853 // UI update and Broadcast Intent 854 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { 855 mVolumePanel.postMasterVolumeChanged(flags); 856 857 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); 858 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); 859 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume); 860 mContext.sendBroadcast(intent); 861 } 862 863 // UI update and Broadcast Intent 864 private void sendMasterMuteUpdate(boolean muted, int flags) { 865 mVolumePanel.postMasterMuteChanged(flags); 866 broadcastMasterMuteStatus(muted); 867 } 868 869 private void broadcastMasterMuteStatus(boolean muted) { 870 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 871 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 872 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 873 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 874 long origCallerIdentityToken = Binder.clearCallingIdentity(); 875 mContext.sendStickyBroadcast(intent); 876 Binder.restoreCallingIdentity(origCallerIdentityToken); 877 } 878 879 /** 880 * Sets the stream state's index, and posts a message to set system volume. 881 * This will not call out to the UI. Assumes a valid stream type. 882 * 883 * @param streamType Type of the stream 884 * @param index Desired volume index of the stream 885 * @param device the device whose volume must be changed 886 * @param force If true, set the volume even if the desired volume is same 887 * as the current volume. 888 * @param lastAudible If true, stores new index as last audible one 889 */ 890 private void setStreamVolumeInt(int streamType, 891 int index, 892 int device, 893 boolean force, 894 boolean lastAudible) { 895 VolumeStreamState streamState = mStreamStates[streamType]; 896 897 // If stream is muted, set last audible index only 898 if (streamState.muteCount() != 0) { 899 // Do not allow last audible index to be 0 900 if (index != 0) { 901 streamState.setLastAudibleIndex(index, device); 902 // Post a persist volume msg 903 sendMsg(mAudioHandler, 904 MSG_PERSIST_VOLUME, 905 SENDMSG_QUEUE, 906 PERSIST_LAST_AUDIBLE, 907 device, 908 streamState, 909 PERSIST_DELAY); 910 } 911 } else { 912 if (streamState.setIndex(index, device, lastAudible) || force) { 913 // Post message to set system volume (it in turn will post a message 914 // to persist). 915 sendMsg(mAudioHandler, 916 MSG_SET_DEVICE_VOLUME, 917 SENDMSG_QUEUE, 918 device, 919 0, 920 streamState, 921 0); 922 } 923 } 924 } 925 926 /** @see AudioManager#setStreamSolo(int, boolean) */ 927 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 928 for (int stream = 0; stream < mStreamStates.length; stream++) { 929 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 930 // Bring back last audible volume 931 mStreamStates[stream].mute(cb, state); 932 } 933 } 934 935 /** @see AudioManager#setStreamMute(int, boolean) */ 936 public void setStreamMute(int streamType, boolean state, IBinder cb) { 937 if (isStreamAffectedByMute(streamType)) { 938 mStreamStates[streamType].mute(cb, state); 939 } 940 } 941 942 /** get stream mute state. */ 943 public boolean isStreamMute(int streamType) { 944 return (mStreamStates[streamType].muteCount() != 0); 945 } 946 947 /** @see AudioManager#setMasterMute(boolean, IBinder) */ 948 public void setMasterMute(boolean state, int flags, IBinder cb) { 949 if (state != AudioSystem.getMasterMute()) { 950 AudioSystem.setMasterMute(state); 951 // Post a persist master volume msg 952 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1 953 : 0, 0, null, PERSIST_DELAY); 954 sendMasterMuteUpdate(state, flags); 955 } 956 } 957 958 /** get master mute state. */ 959 public boolean isMasterMute() { 960 return AudioSystem.getMasterMute(); 961 } 962 963 /** @see AudioManager#getStreamVolume(int) */ 964 public int getStreamVolume(int streamType) { 965 ensureValidStreamType(streamType); 966 int device = getDeviceForStream(streamType); 967 return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10; 968 } 969 970 public int getMasterVolume() { 971 if (isMasterMute()) return 0; 972 return getLastAudibleMasterVolume(); 973 } 974 975 public void setMasterVolume(int volume, int flags) { 976 if (volume < 0) { 977 volume = 0; 978 } else if (volume > MAX_MASTER_VOLUME) { 979 volume = MAX_MASTER_VOLUME; 980 } 981 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags); 982 } 983 984 private void doSetMasterVolume(float volume, int flags) { 985 // don't allow changing master volume when muted 986 if (!AudioSystem.getMasterMute()) { 987 int oldVolume = getMasterVolume(); 988 AudioSystem.setMasterVolume(volume); 989 990 int newVolume = getMasterVolume(); 991 if (newVolume != oldVolume) { 992 // Post a persist master volume msg 993 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE, 994 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY); 995 } 996 // Send the volume update regardless whether there was a change. 997 sendMasterVolumeUpdate(flags, oldVolume, newVolume); 998 } 999 } 1000 1001 /** @see AudioManager#getStreamMaxVolume(int) */ 1002 public int getStreamMaxVolume(int streamType) { 1003 ensureValidStreamType(streamType); 1004 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 1005 } 1006 1007 public int getMasterMaxVolume() { 1008 return MAX_MASTER_VOLUME; 1009 } 1010 1011 /** Get last audible volume before stream was muted. */ 1012 public int getLastAudibleStreamVolume(int streamType) { 1013 ensureValidStreamType(streamType); 1014 int device = getDeviceForStream(streamType); 1015 return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10; 1016 } 1017 1018 /** Get last audible master volume before it was muted. */ 1019 public int getLastAudibleMasterVolume() { 1020 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 1021 } 1022 1023 /** @see AudioManager#getMasterStreamType(int) */ 1024 public int getMasterStreamType() { 1025 if (mVoiceCapable) { 1026 return AudioSystem.STREAM_RING; 1027 } else { 1028 return AudioSystem.STREAM_MUSIC; 1029 } 1030 } 1031 1032 /** @see AudioManager#getRingerMode() */ 1033 public int getRingerMode() { 1034 synchronized(mSettingsLock) { 1035 return mRingerMode; 1036 } 1037 } 1038 1039 private void ensureValidRingerMode(int ringerMode) { 1040 if (!AudioManager.isValidRingerMode(ringerMode)) { 1041 throw new IllegalArgumentException("Bad ringer mode " + ringerMode); 1042 } 1043 } 1044 1045 /** @see AudioManager#setRingerMode(int) */ 1046 public void setRingerMode(int ringerMode) { 1047 ensureValidRingerMode(ringerMode); 1048 if (ringerMode != getRingerMode()) { 1049 setRingerModeInt(ringerMode, true); 1050 // Send sticky broadcast 1051 broadcastRingerMode(ringerMode); 1052 } 1053 } 1054 1055 private void setRingerModeInt(int ringerMode, boolean persist) { 1056 synchronized(mSettingsLock) { 1057 mRingerMode = ringerMode; 1058 } 1059 1060 // Mute stream if not previously muted by ringer mode and ringer mode 1061 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 1062 // Unmute stream if previously muted by ringer mode and ringer mode 1063 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 1064 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1065 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1066 if (isStreamMutedByRingerMode(streamType)) { 1067 if (!isStreamAffectedByRingerMode(streamType) || 1068 ringerMode == AudioManager.RINGER_MODE_NORMAL) { 1069 // ring and notifications volume should never be 0 when not silenced 1070 // on voice capable devices 1071 if (mVoiceCapable && 1072 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { 1073 1074 Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); 1075 Iterator i = set.iterator(); 1076 while (i.hasNext()) { 1077 Map.Entry entry = (Map.Entry)i.next(); 1078 if ((Integer)entry.getValue() == 0) { 1079 entry.setValue(10); 1080 } 1081 } 1082 } 1083 mStreamStates[streamType].mute(null, false); 1084 mRingerModeMutedStreams &= ~(1 << streamType); 1085 } 1086 } else { 1087 if (isStreamAffectedByRingerMode(streamType) && 1088 ringerMode != AudioManager.RINGER_MODE_NORMAL) { 1089 mStreamStates[streamType].mute(null, true); 1090 mRingerModeMutedStreams |= (1 << streamType); 1091 } 1092 } 1093 } 1094 1095 // Post a persist ringer mode msg 1096 if (persist) { 1097 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, 1098 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 1099 } 1100 } 1101 1102 private void restoreMasterVolume() { 1103 if (mUseMasterVolume) { 1104 float volume = Settings.System.getFloat(mContentResolver, 1105 Settings.System.VOLUME_MASTER, -1.0f); 1106 if (volume >= 0.0f) { 1107 AudioSystem.setMasterVolume(volume); 1108 } 1109 } 1110 } 1111 1112 /** @see AudioManager#shouldVibrate(int) */ 1113 public boolean shouldVibrate(int vibrateType) { 1114 1115 switch (getVibrateSetting(vibrateType)) { 1116 1117 case AudioManager.VIBRATE_SETTING_ON: 1118 return getRingerMode() != AudioManager.RINGER_MODE_SILENT; 1119 1120 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 1121 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; 1122 1123 case AudioManager.VIBRATE_SETTING_OFF: 1124 // return false, even for incoming calls 1125 return false; 1126 1127 default: 1128 return false; 1129 } 1130 } 1131 1132 /** @see AudioManager#getVibrateSetting(int) */ 1133 public int getVibrateSetting(int vibrateType) { 1134 return (mVibrateSetting >> (vibrateType * 2)) & 3; 1135 } 1136 1137 /** @see AudioManager#setVibrateSetting(int, int) */ 1138 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1139 1140 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 1141 1142 // Broadcast change 1143 broadcastVibrateSetting(vibrateType); 1144 1145 // Post message to set ringer mode (it in turn will post a message 1146 // to persist) 1147 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SENDMSG_NOOP, 0, 0, 1148 null, 0); 1149 } 1150 1151 /** 1152 * @see #setVibrateSetting(int, int) 1153 */ 1154 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 1155 int vibrateSetting) { 1156 1157 // First clear the existing setting. Each vibrate type has two bits in 1158 // the value. Note '3' is '11' in binary. 1159 existingValue &= ~(3 << (vibrateType * 2)); 1160 1161 // Set into the old value 1162 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 1163 1164 return existingValue; 1165 } 1166 1167 private class SetModeDeathHandler implements IBinder.DeathRecipient { 1168 private IBinder mCb; // To be notified of client's death 1169 private int mPid; 1170 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 1171 1172 SetModeDeathHandler(IBinder cb, int pid) { 1173 mCb = cb; 1174 mPid = pid; 1175 } 1176 1177 public void binderDied() { 1178 int newModeOwnerPid = 0; 1179 synchronized(mSetModeDeathHandlers) { 1180 Log.w(TAG, "setMode() client died"); 1181 int index = mSetModeDeathHandlers.indexOf(this); 1182 if (index < 0) { 1183 Log.w(TAG, "unregistered setMode() client died"); 1184 } else { 1185 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid); 1186 } 1187 } 1188 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1189 // SCO connections not started by the application changing the mode 1190 if (newModeOwnerPid != 0) { 1191 disconnectBluetoothSco(newModeOwnerPid); 1192 } 1193 } 1194 1195 public int getPid() { 1196 return mPid; 1197 } 1198 1199 public void setMode(int mode) { 1200 mMode = mode; 1201 } 1202 1203 public int getMode() { 1204 return mMode; 1205 } 1206 1207 public IBinder getBinder() { 1208 return mCb; 1209 } 1210 } 1211 1212 /** @see AudioManager#setMode(int) */ 1213 public void setMode(int mode, IBinder cb) { 1214 if (!checkAudioSettingsPermission("setMode()")) { 1215 return; 1216 } 1217 1218 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { 1219 return; 1220 } 1221 1222 int newModeOwnerPid = 0; 1223 synchronized(mSetModeDeathHandlers) { 1224 if (mode == AudioSystem.MODE_CURRENT) { 1225 mode = mMode; 1226 } 1227 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid()); 1228 } 1229 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1230 // SCO connections not started by the application changing the mode 1231 if (newModeOwnerPid != 0) { 1232 disconnectBluetoothSco(newModeOwnerPid); 1233 } 1234 } 1235 1236 // must be called synchronized on mSetModeDeathHandlers 1237 // setModeInt() returns a valid PID if the audio mode was successfully set to 1238 // any mode other than NORMAL. 1239 int setModeInt(int mode, IBinder cb, int pid) { 1240 int newModeOwnerPid = 0; 1241 if (cb == null) { 1242 Log.e(TAG, "setModeInt() called with null binder"); 1243 return newModeOwnerPid; 1244 } 1245 1246 SetModeDeathHandler hdlr = null; 1247 Iterator iter = mSetModeDeathHandlers.iterator(); 1248 while (iter.hasNext()) { 1249 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 1250 if (h.getPid() == pid) { 1251 hdlr = h; 1252 // Remove from client list so that it is re-inserted at top of list 1253 iter.remove(); 1254 hdlr.getBinder().unlinkToDeath(hdlr, 0); 1255 break; 1256 } 1257 } 1258 int status = AudioSystem.AUDIO_STATUS_OK; 1259 do { 1260 if (mode == AudioSystem.MODE_NORMAL) { 1261 // get new mode from client at top the list if any 1262 if (!mSetModeDeathHandlers.isEmpty()) { 1263 hdlr = mSetModeDeathHandlers.get(0); 1264 cb = hdlr.getBinder(); 1265 mode = hdlr.getMode(); 1266 } 1267 } else { 1268 if (hdlr == null) { 1269 hdlr = new SetModeDeathHandler(cb, pid); 1270 } 1271 // Register for client death notification 1272 try { 1273 cb.linkToDeath(hdlr, 0); 1274 } catch (RemoteException e) { 1275 // Client has died! 1276 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 1277 } 1278 1279 // Last client to call setMode() is always at top of client list 1280 // as required by SetModeDeathHandler.binderDied() 1281 mSetModeDeathHandlers.add(0, hdlr); 1282 hdlr.setMode(mode); 1283 } 1284 1285 if (mode != mMode) { 1286 status = AudioSystem.setPhoneState(mode); 1287 if (status == AudioSystem.AUDIO_STATUS_OK) { 1288 mMode = mode; 1289 } else { 1290 if (hdlr != null) { 1291 mSetModeDeathHandlers.remove(hdlr); 1292 cb.unlinkToDeath(hdlr, 0); 1293 } 1294 // force reading new top of mSetModeDeathHandlers stack 1295 mode = AudioSystem.MODE_NORMAL; 1296 } 1297 } else { 1298 status = AudioSystem.AUDIO_STATUS_OK; 1299 } 1300 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty()); 1301 1302 if (status == AudioSystem.AUDIO_STATUS_OK) { 1303 if (mode != AudioSystem.MODE_NORMAL) { 1304 if (mSetModeDeathHandlers.isEmpty()) { 1305 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack"); 1306 } else { 1307 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); 1308 } 1309 } 1310 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 1311 int device = getDeviceForStream(streamType); 1312 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); 1313 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); 1314 1315 updateStreamVolumeAlias(true /*updateVolumes*/); 1316 } 1317 return newModeOwnerPid; 1318 } 1319 1320 /** @see AudioManager#getMode() */ 1321 public int getMode() { 1322 return mMode; 1323 } 1324 1325 /** @see AudioManager#playSoundEffect(int) */ 1326 public void playSoundEffect(int effectType) { 1327 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1328 effectType, -1, null, 0); 1329 } 1330 1331 /** @see AudioManager#playSoundEffect(int, float) */ 1332 public void playSoundEffectVolume(int effectType, float volume) { 1333 loadSoundEffects(); 1334 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1335 effectType, (int) (volume * 1000), null, 0); 1336 } 1337 1338 /** 1339 * Loads samples into the soundpool. 1340 * This method must be called at first when sound effects are enabled 1341 */ 1342 public boolean loadSoundEffects() { 1343 int status; 1344 1345 synchronized (mSoundEffectsLock) { 1346 if (!mBootCompleted) { 1347 Log.w(TAG, "loadSoundEffects() called before boot complete"); 1348 return false; 1349 } 1350 1351 if (mSoundPool != null) { 1352 return true; 1353 } 1354 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 1355 1356 try { 1357 mSoundPoolCallBack = null; 1358 mSoundPoolListenerThread = new SoundPoolListenerThread(); 1359 mSoundPoolListenerThread.start(); 1360 // Wait for mSoundPoolCallBack to be set by the other thread 1361 mSoundEffectsLock.wait(); 1362 } catch (InterruptedException e) { 1363 Log.w(TAG, "Interrupted while waiting sound pool listener thread."); 1364 } 1365 1366 if (mSoundPoolCallBack == null) { 1367 Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread"); 1368 if (mSoundPoolLooper != null) { 1369 mSoundPoolLooper.quit(); 1370 mSoundPoolLooper = null; 1371 } 1372 mSoundPoolListenerThread = null; 1373 mSoundPool.release(); 1374 mSoundPool = null; 1375 return false; 1376 } 1377 /* 1378 * poolId table: The value -1 in this table indicates that corresponding 1379 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 1380 * Once loaded, the value in poolId is the sample ID and the same 1381 * sample can be reused for another effect using the same file. 1382 */ 1383 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 1384 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 1385 poolId[fileIdx] = -1; 1386 } 1387 /* 1388 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 1389 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 1390 * this indicates we have a valid sample loaded for this effect. 1391 */ 1392 1393 int lastSample = 0; 1394 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1395 // Do not load sample if this effect uses the MediaPlayer 1396 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 1397 continue; 1398 } 1399 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 1400 String filePath = Environment.getRootDirectory() 1401 + SOUND_EFFECTS_PATH 1402 + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 1403 int sampleId = mSoundPool.load(filePath, 0); 1404 if (sampleId <= 0) { 1405 Log.w(TAG, "Soundpool could not load file: "+filePath); 1406 } else { 1407 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 1408 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 1409 lastSample = sampleId; 1410 } 1411 } else { 1412 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 1413 } 1414 } 1415 // wait for all samples to be loaded 1416 if (lastSample != 0) { 1417 mSoundPoolCallBack.setLastSample(lastSample); 1418 1419 try { 1420 mSoundEffectsLock.wait(); 1421 status = mSoundPoolCallBack.status(); 1422 } catch (java.lang.InterruptedException e) { 1423 Log.w(TAG, "Interrupted while waiting sound pool callback."); 1424 status = -1; 1425 } 1426 } else { 1427 status = -1; 1428 } 1429 1430 if (mSoundPoolLooper != null) { 1431 mSoundPoolLooper.quit(); 1432 mSoundPoolLooper = null; 1433 } 1434 mSoundPoolListenerThread = null; 1435 if (status != 0) { 1436 Log.w(TAG, 1437 "loadSoundEffects(), Error " 1438 + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1) 1439 + " while loading samples"); 1440 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1441 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) { 1442 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1443 } 1444 } 1445 1446 mSoundPool.release(); 1447 mSoundPool = null; 1448 } 1449 } 1450 return (status == 0); 1451 } 1452 1453 /** 1454 * Unloads samples from the sound pool. 1455 * This method can be called to free some memory when 1456 * sound effects are disabled. 1457 */ 1458 public void unloadSoundEffects() { 1459 synchronized (mSoundEffectsLock) { 1460 if (mSoundPool == null) { 1461 return; 1462 } 1463 1464 mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS); 1465 mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT); 1466 1467 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 1468 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 1469 poolId[fileIdx] = 0; 1470 } 1471 1472 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1473 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 1474 continue; 1475 } 1476 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 1477 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 1478 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1479 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 1480 } 1481 } 1482 mSoundPool.release(); 1483 mSoundPool = null; 1484 } 1485 } 1486 1487 class SoundPoolListenerThread extends Thread { 1488 public SoundPoolListenerThread() { 1489 super("SoundPoolListenerThread"); 1490 } 1491 1492 @Override 1493 public void run() { 1494 1495 Looper.prepare(); 1496 mSoundPoolLooper = Looper.myLooper(); 1497 1498 synchronized (mSoundEffectsLock) { 1499 if (mSoundPool != null) { 1500 mSoundPoolCallBack = new SoundPoolCallback(); 1501 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack); 1502 } 1503 mSoundEffectsLock.notify(); 1504 } 1505 Looper.loop(); 1506 } 1507 } 1508 1509 private final class SoundPoolCallback implements 1510 android.media.SoundPool.OnLoadCompleteListener { 1511 1512 int mStatus; 1513 int mLastSample; 1514 1515 public int status() { 1516 return mStatus; 1517 } 1518 1519 public void setLastSample(int sample) { 1520 mLastSample = sample; 1521 } 1522 1523 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 1524 synchronized (mSoundEffectsLock) { 1525 if (status != 0) { 1526 mStatus = status; 1527 } 1528 if (sampleId == mLastSample) { 1529 mSoundEffectsLock.notify(); 1530 } 1531 } 1532 } 1533 } 1534 1535 /** @see AudioManager#reloadAudioSettings() */ 1536 public void reloadAudioSettings() { 1537 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 1538 readPersistedSettings(); 1539 1540 // restore volume settings 1541 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1542 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 1543 VolumeStreamState streamState = mStreamStates[streamType]; 1544 1545 streamState.readSettings(); 1546 1547 // unmute stream that was muted but is not affect by mute anymore 1548 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 1549 int size = streamState.mDeathHandlers.size(); 1550 for (int i = 0; i < size; i++) { 1551 streamState.mDeathHandlers.get(i).mMuteCount = 1; 1552 streamState.mDeathHandlers.get(i).mute(false); 1553 } 1554 } 1555 // apply stream volume 1556 if (streamState.muteCount() == 0) { 1557 streamState.applyAllVolumes(); 1558 } 1559 } 1560 1561 // apply new ringer mode 1562 setRingerModeInt(getRingerMode(), false); 1563 } 1564 1565 /** @see AudioManager#setSpeakerphoneOn() */ 1566 public void setSpeakerphoneOn(boolean on){ 1567 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 1568 return; 1569 } 1570 mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; 1571 1572 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1573 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1574 } 1575 1576 /** @see AudioManager#isSpeakerphoneOn() */ 1577 public boolean isSpeakerphoneOn() { 1578 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER); 1579 } 1580 1581 /** @see AudioManager#setBluetoothScoOn() */ 1582 public void setBluetoothScoOn(boolean on){ 1583 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 1584 return; 1585 } 1586 mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 1587 1588 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1589 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1590 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1591 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); 1592 } 1593 1594 /** @see AudioManager#isBluetoothScoOn() */ 1595 public boolean isBluetoothScoOn() { 1596 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); 1597 } 1598 1599 /** @see AudioManager#startBluetoothSco() */ 1600 public void startBluetoothSco(IBinder cb){ 1601 if (!checkAudioSettingsPermission("startBluetoothSco()") || 1602 !mBootCompleted) { 1603 return; 1604 } 1605 ScoClient client = getScoClient(cb, true); 1606 client.incCount(); 1607 } 1608 1609 /** @see AudioManager#stopBluetoothSco() */ 1610 public void stopBluetoothSco(IBinder cb){ 1611 if (!checkAudioSettingsPermission("stopBluetoothSco()") || 1612 !mBootCompleted) { 1613 return; 1614 } 1615 ScoClient client = getScoClient(cb, false); 1616 if (client != null) { 1617 client.decCount(); 1618 } 1619 } 1620 1621 private class ScoClient implements IBinder.DeathRecipient { 1622 private IBinder mCb; // To be notified of client's death 1623 private int mCreatorPid; 1624 private int mStartcount; // number of SCO connections started by this client 1625 1626 ScoClient(IBinder cb) { 1627 mCb = cb; 1628 mCreatorPid = Binder.getCallingPid(); 1629 mStartcount = 0; 1630 } 1631 1632 public void binderDied() { 1633 synchronized(mScoClients) { 1634 Log.w(TAG, "SCO client died"); 1635 int index = mScoClients.indexOf(this); 1636 if (index < 0) { 1637 Log.w(TAG, "unregistered SCO client died"); 1638 } else { 1639 clearCount(true); 1640 mScoClients.remove(this); 1641 } 1642 } 1643 } 1644 1645 public void incCount() { 1646 synchronized(mScoClients) { 1647 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); 1648 if (mStartcount == 0) { 1649 try { 1650 mCb.linkToDeath(this, 0); 1651 } catch (RemoteException e) { 1652 // client has already died! 1653 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 1654 } 1655 } 1656 mStartcount++; 1657 } 1658 } 1659 1660 public void decCount() { 1661 synchronized(mScoClients) { 1662 if (mStartcount == 0) { 1663 Log.w(TAG, "ScoClient.decCount() already 0"); 1664 } else { 1665 mStartcount--; 1666 if (mStartcount == 0) { 1667 try { 1668 mCb.unlinkToDeath(this, 0); 1669 } catch (NoSuchElementException e) { 1670 Log.w(TAG, "decCount() going to 0 but not registered to binder"); 1671 } 1672 } 1673 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1674 } 1675 } 1676 } 1677 1678 public void clearCount(boolean stopSco) { 1679 synchronized(mScoClients) { 1680 if (mStartcount != 0) { 1681 try { 1682 mCb.unlinkToDeath(this, 0); 1683 } catch (NoSuchElementException e) { 1684 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder"); 1685 } 1686 } 1687 mStartcount = 0; 1688 if (stopSco) { 1689 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1690 } 1691 } 1692 } 1693 1694 public int getCount() { 1695 return mStartcount; 1696 } 1697 1698 public IBinder getBinder() { 1699 return mCb; 1700 } 1701 1702 public int getPid() { 1703 return mCreatorPid; 1704 } 1705 1706 public int totalCount() { 1707 synchronized(mScoClients) { 1708 int count = 0; 1709 int size = mScoClients.size(); 1710 for (int i = 0; i < size; i++) { 1711 count += mScoClients.get(i).getCount(); 1712 } 1713 return count; 1714 } 1715 } 1716 1717 private void requestScoState(int state) { 1718 checkScoAudioState(); 1719 if (totalCount() == 0) { 1720 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 1721 // Make sure that the state transitions to CONNECTING even if we cannot initiate 1722 // the connection. 1723 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); 1724 // Accept SCO audio activation only in NORMAL audio mode or if the mode is 1725 // currently controlled by the same client process. 1726 synchronized(mSetModeDeathHandlers) { 1727 if ((mSetModeDeathHandlers.isEmpty() || 1728 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) && 1729 (mScoAudioState == SCO_STATE_INACTIVE || 1730 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 1731 if (mScoAudioState == SCO_STATE_INACTIVE) { 1732 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1733 if (mBluetoothHeadset.startScoUsingVirtualVoiceCall( 1734 mBluetoothHeadsetDevice)) { 1735 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1736 } else { 1737 broadcastScoConnectionState( 1738 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1739 } 1740 } else if (getBluetoothHeadset()) { 1741 mScoAudioState = SCO_STATE_ACTIVATE_REQ; 1742 } 1743 } else { 1744 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1745 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); 1746 } 1747 } else { 1748 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1749 } 1750 } 1751 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED && 1752 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 1753 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { 1754 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { 1755 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1756 if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1757 mBluetoothHeadsetDevice)) { 1758 mScoAudioState = SCO_STATE_INACTIVE; 1759 broadcastScoConnectionState( 1760 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1761 } 1762 } else if (getBluetoothHeadset()) { 1763 mScoAudioState = SCO_STATE_DEACTIVATE_REQ; 1764 } 1765 } else { 1766 mScoAudioState = SCO_STATE_INACTIVE; 1767 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1768 } 1769 } 1770 } 1771 } 1772 } 1773 1774 private void checkScoAudioState() { 1775 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null && 1776 mScoAudioState == SCO_STATE_INACTIVE && 1777 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) 1778 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 1779 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 1780 } 1781 } 1782 1783 private ScoClient getScoClient(IBinder cb, boolean create) { 1784 synchronized(mScoClients) { 1785 ScoClient client = null; 1786 int size = mScoClients.size(); 1787 for (int i = 0; i < size; i++) { 1788 client = mScoClients.get(i); 1789 if (client.getBinder() == cb) 1790 return client; 1791 } 1792 if (create) { 1793 client = new ScoClient(cb); 1794 mScoClients.add(client); 1795 } 1796 return client; 1797 } 1798 } 1799 1800 public void clearAllScoClients(int exceptPid, boolean stopSco) { 1801 synchronized(mScoClients) { 1802 ScoClient savedClient = null; 1803 int size = mScoClients.size(); 1804 for (int i = 0; i < size; i++) { 1805 ScoClient cl = mScoClients.get(i); 1806 if (cl.getPid() != exceptPid) { 1807 cl.clearCount(stopSco); 1808 } else { 1809 savedClient = cl; 1810 } 1811 } 1812 mScoClients.clear(); 1813 if (savedClient != null) { 1814 mScoClients.add(savedClient); 1815 } 1816 } 1817 } 1818 1819 private boolean getBluetoothHeadset() { 1820 boolean result = false; 1821 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1822 if (adapter != null) { 1823 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 1824 BluetoothProfile.HEADSET); 1825 } 1826 // If we could not get a bluetooth headset proxy, send a failure message 1827 // without delay to reset the SCO audio state and clear SCO clients. 1828 // If we could get a proxy, send a delayed failure message that will reset our state 1829 // in case we don't receive onServiceConnected(). 1830 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1831 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); 1832 return result; 1833 } 1834 1835 private void disconnectBluetoothSco(int exceptPid) { 1836 synchronized(mScoClients) { 1837 checkScoAudioState(); 1838 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL || 1839 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1840 if (mBluetoothHeadsetDevice != null) { 1841 if (mBluetoothHeadset != null) { 1842 if (!mBluetoothHeadset.stopVoiceRecognition( 1843 mBluetoothHeadsetDevice)) { 1844 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1845 SENDMSG_REPLACE, 0, 0, null, 0); 1846 } 1847 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && 1848 getBluetoothHeadset()) { 1849 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ; 1850 } 1851 } 1852 } else { 1853 clearAllScoClients(exceptPid, true); 1854 } 1855 } 1856 } 1857 1858 private void resetBluetoothSco() { 1859 synchronized(mScoClients) { 1860 clearAllScoClients(0, false); 1861 mScoAudioState = SCO_STATE_INACTIVE; 1862 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1863 } 1864 } 1865 1866 private void broadcastScoConnectionState(int state) { 1867 if (state != mScoConnectionState) { 1868 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); 1869 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1870 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, 1871 mScoConnectionState); 1872 mContext.sendStickyBroadcast(newIntent); 1873 mScoConnectionState = state; 1874 } 1875 } 1876 1877 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 1878 new BluetoothProfile.ServiceListener() { 1879 public void onServiceConnected(int profile, BluetoothProfile proxy) { 1880 BluetoothDevice btDevice; 1881 List<BluetoothDevice> deviceList; 1882 switch(profile) { 1883 case BluetoothProfile.A2DP: 1884 BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 1885 deviceList = a2dp.getConnectedDevices(); 1886 if (deviceList.size() > 0) { 1887 btDevice = deviceList.get(0); 1888 handleA2dpConnectionStateChange(btDevice, a2dp.getConnectionState(btDevice)); 1889 } 1890 break; 1891 1892 case BluetoothProfile.HEADSET: 1893 synchronized (mScoClients) { 1894 // Discard timeout message 1895 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 1896 mBluetoothHeadset = (BluetoothHeadset) proxy; 1897 deviceList = mBluetoothHeadset.getConnectedDevices(); 1898 if (deviceList.size() > 0) { 1899 mBluetoothHeadsetDevice = deviceList.get(0); 1900 } else { 1901 mBluetoothHeadsetDevice = null; 1902 } 1903 // Refresh SCO audio state 1904 checkScoAudioState(); 1905 // Continue pending action if any 1906 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || 1907 mScoAudioState == SCO_STATE_DEACTIVATE_REQ || 1908 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1909 boolean status = false; 1910 if (mBluetoothHeadsetDevice != null) { 1911 switch (mScoAudioState) { 1912 case SCO_STATE_ACTIVATE_REQ: 1913 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1914 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 1915 mBluetoothHeadsetDevice); 1916 break; 1917 case SCO_STATE_DEACTIVATE_REQ: 1918 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1919 mBluetoothHeadsetDevice); 1920 break; 1921 case SCO_STATE_DEACTIVATE_EXT_REQ: 1922 status = mBluetoothHeadset.stopVoiceRecognition( 1923 mBluetoothHeadsetDevice); 1924 } 1925 } 1926 if (!status) { 1927 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1928 SENDMSG_REPLACE, 0, 0, null, 0); 1929 } 1930 } 1931 } 1932 break; 1933 1934 default: 1935 break; 1936 } 1937 } 1938 public void onServiceDisconnected(int profile) { 1939 switch(profile) { 1940 case BluetoothProfile.A2DP: 1941 synchronized (mConnectedDevices) { 1942 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { 1943 makeA2dpDeviceUnavailableNow( 1944 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); 1945 } 1946 } 1947 break; 1948 1949 case BluetoothProfile.HEADSET: 1950 synchronized (mScoClients) { 1951 mBluetoothHeadset = null; 1952 } 1953 break; 1954 1955 default: 1956 break; 1957 } 1958 } 1959 }; 1960 1961 /////////////////////////////////////////////////////////////////////////// 1962 // Internal methods 1963 /////////////////////////////////////////////////////////////////////////// 1964 1965 /** 1966 * Checks if the adjustment should change ringer mode instead of just 1967 * adjusting volume. If so, this will set the proper ringer mode and volume 1968 * indices on the stream states. 1969 */ 1970 private boolean checkForRingerModeChange(int oldIndex, int direction, int streamType) { 1971 boolean adjustVolumeIndex = true; 1972 int ringerMode = getRingerMode(); 1973 int newRingerMode = ringerMode; 1974 int uiIndex = (oldIndex + 5) / 10; 1975 boolean vibeInSilent = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1; 1976 1977 if (ringerMode == RINGER_MODE_NORMAL) { 1978 if ((direction == AudioManager.ADJUST_LOWER) && (uiIndex <= 1)) { 1979 // enter silent mode if current index is the last audible one and not repeating a 1980 // volume key down 1981 if (vibeInSilent || mPrevVolDirection != AudioManager.ADJUST_LOWER) { 1982 // "silent mode", but which one? 1983 newRingerMode = vibeInSilent ? RINGER_MODE_VIBRATE : RINGER_MODE_SILENT; 1984 } 1985 if (uiIndex == 0 || 1986 (!vibeInSilent && 1987 mPrevVolDirection == AudioManager.ADJUST_LOWER && 1988 mVoiceCapable && streamType == AudioSystem.STREAM_RING)) { 1989 adjustVolumeIndex = false; 1990 } 1991 } 1992 } else if (ringerMode == RINGER_MODE_VIBRATE) { 1993 if ((direction == AudioManager.ADJUST_LOWER)) { 1994 // Set it to silent, if it wasn't a long-press 1995 if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 1996 newRingerMode = RINGER_MODE_SILENT; 1997 } 1998 } else if (direction == AudioManager.ADJUST_RAISE) { 1999 newRingerMode = RINGER_MODE_NORMAL; 2000 } 2001 adjustVolumeIndex = false; 2002 } else { 2003 if (direction == AudioManager.ADJUST_RAISE) { 2004 // exiting silent mode 2005 // If VIBRATE_IN_SILENT, then go into vibrate mode 2006 newRingerMode = vibeInSilent ? RINGER_MODE_VIBRATE : RINGER_MODE_NORMAL; 2007 } 2008 adjustVolumeIndex = false; 2009 } 2010 2011 setRingerMode(newRingerMode); 2012 2013 mPrevVolDirection = direction; 2014 2015 return adjustVolumeIndex; 2016 } 2017 2018 public boolean isStreamAffectedByRingerMode(int streamType) { 2019 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 2020 } 2021 2022 private boolean isStreamMutedByRingerMode(int streamType) { 2023 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 2024 } 2025 2026 public boolean isStreamAffectedByMute(int streamType) { 2027 return (mMuteAffectedStreams & (1 << streamType)) != 0; 2028 } 2029 2030 private void ensureValidDirection(int direction) { 2031 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 2032 throw new IllegalArgumentException("Bad direction " + direction); 2033 } 2034 } 2035 2036 private void ensureValidSteps(int steps) { 2037 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 2038 throw new IllegalArgumentException("Bad volume adjust steps " + steps); 2039 } 2040 } 2041 2042 private void ensureValidStreamType(int streamType) { 2043 if (streamType < 0 || streamType >= mStreamStates.length) { 2044 throw new IllegalArgumentException("Bad stream type " + streamType); 2045 } 2046 } 2047 2048 private boolean isInCommunication() { 2049 boolean isOffhook = false; 2050 2051 if (mVoiceCapable) { 2052 try { 2053 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 2054 if (phone != null) isOffhook = phone.isOffhook(); 2055 } catch (RemoteException e) { 2056 Log.w(TAG, "Couldn't connect to phone service", e); 2057 } 2058 } 2059 return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 2060 } 2061 2062 private int getActiveStreamType(int suggestedStreamType) { 2063 if (mVoiceCapable) { 2064 if (isInCommunication()) { 2065 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2066 == AudioSystem.FORCE_BT_SCO) { 2067 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2068 return AudioSystem.STREAM_BLUETOOTH_SCO; 2069 } else { 2070 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2071 return AudioSystem.STREAM_VOICE_CALL; 2072 } 2073 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 2074 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 2075 return AudioSystem.STREAM_MUSIC; 2076 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2077 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..." 2078 // + " b/c USE_DEFAULT_STREAM_TYPE..."); 2079 return AudioSystem.STREAM_RING; 2080 } else { 2081 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 2082 return suggestedStreamType; 2083 } 2084 } else { 2085 if (isInCommunication()) { 2086 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2087 == AudioSystem.FORCE_BT_SCO) { 2088 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2089 return AudioSystem.STREAM_BLUETOOTH_SCO; 2090 } else { 2091 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2092 return AudioSystem.STREAM_VOICE_CALL; 2093 } 2094 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 2095 NOTIFICATION_VOLUME_DELAY_MS) || 2096 AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 2097 NOTIFICATION_VOLUME_DELAY_MS)) { 2098 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION..."); 2099 return AudioSystem.STREAM_NOTIFICATION; 2100 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) || 2101 (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE)) { 2102 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC " 2103 // + " b/c USE_DEFAULT_STREAM_TYPE..."); 2104 return AudioSystem.STREAM_MUSIC; 2105 } else { 2106 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 2107 return suggestedStreamType; 2108 } 2109 } 2110 } 2111 2112 private void broadcastRingerMode(int ringerMode) { 2113 // Send sticky broadcast 2114 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2115 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 2116 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2117 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2118 long origCallerIdentityToken = Binder.clearCallingIdentity(); 2119 mContext.sendStickyBroadcast(broadcast); 2120 Binder.restoreCallingIdentity(origCallerIdentityToken); 2121 } 2122 2123 private void broadcastVibrateSetting(int vibrateType) { 2124 // Send broadcast 2125 if (ActivityManagerNative.isSystemReady()) { 2126 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 2127 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 2128 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 2129 mContext.sendBroadcast(broadcast); 2130 } 2131 } 2132 2133 // Message helper methods 2134 2135 private static void sendMsg(Handler handler, int msg, 2136 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 2137 2138 if (existingMsgPolicy == SENDMSG_REPLACE) { 2139 handler.removeMessages(msg); 2140 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 2141 return; 2142 } 2143 2144 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 2145 } 2146 2147 boolean checkAudioSettingsPermission(String method) { 2148 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 2149 == PackageManager.PERMISSION_GRANTED) { 2150 return true; 2151 } 2152 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 2153 + Binder.getCallingPid() 2154 + ", uid=" + Binder.getCallingUid(); 2155 Log.w(TAG, msg); 2156 return false; 2157 } 2158 2159 private int getDeviceForStream(int stream) { 2160 int device = AudioSystem.getDevicesForStream(stream); 2161 if ((device & (device - 1)) != 0) { 2162 // Multiple device selection is either: 2163 // - speaker + one other device: give priority to speaker in this case. 2164 // - one A2DP device + another device: happens with duplicated output. In this case 2165 // retain the device on the A2DP output as the other must not correspond to an active 2166 // selection if not the speaker. 2167 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 2168 device = AudioSystem.DEVICE_OUT_SPEAKER; 2169 } else { 2170 device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 2171 } 2172 } 2173 return device; 2174 } 2175 2176 /////////////////////////////////////////////////////////////////////////// 2177 // Inner classes 2178 /////////////////////////////////////////////////////////////////////////// 2179 2180 public class VolumeStreamState { 2181 private final int mStreamType; 2182 2183 private String mVolumeIndexSettingName; 2184 private String mLastAudibleVolumeIndexSettingName; 2185 private int mIndexMax; 2186 private final HashMap <Integer, Integer> mIndex = new HashMap <Integer, Integer>(); 2187 private final HashMap <Integer, Integer> mLastAudibleIndex = 2188 new HashMap <Integer, Integer>(); 2189 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 2190 2191 private VolumeStreamState(String settingName, int streamType) { 2192 2193 mVolumeIndexSettingName = settingName; 2194 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 2195 2196 mStreamType = streamType; 2197 mIndexMax = MAX_STREAM_VOLUME[streamType]; 2198 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2199 mIndexMax *= 10; 2200 2201 readSettings(); 2202 2203 applyAllVolumes(); 2204 2205 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 2206 } 2207 2208 public String getSettingNameForDevice(boolean lastAudible, int device) { 2209 String name = lastAudible ? 2210 mLastAudibleVolumeIndexSettingName : 2211 mVolumeIndexSettingName; 2212 String suffix = AudioSystem.getDeviceName(device); 2213 if (suffix.isEmpty()) { 2214 return name; 2215 } 2216 return name + "_" + suffix; 2217 } 2218 2219 public void readSettings() { 2220 boolean checkSilentVolume = (mRingerMode == AudioManager.RINGER_MODE_NORMAL) && 2221 isStreamAffectedByRingerMode(mStreamType); 2222 2223 int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 2224 2225 for (int i = 0; remainingDevices != 0; i++) { 2226 int device = (1 << i); 2227 if ((device & remainingDevices) == 0) { 2228 continue; 2229 } 2230 remainingDevices &= ~device; 2231 2232 // retrieve current volume for device 2233 String name = getSettingNameForDevice(false /* lastAudible */, device); 2234 // if no volume stored for current stream and device, use default volume if default 2235 // device, continue otherwise 2236 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 2237 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 2238 int index = Settings.System.getInt(mContentResolver, name, defaultIndex); 2239 if (index == -1) { 2240 continue; 2241 } 2242 2243 // retrieve last audible volume for device 2244 name = getSettingNameForDevice(true /* lastAudible */, device); 2245 // use stored last audible index if present, otherwise use current index if not 0 2246 // or default index 2247 defaultIndex = (index > 0) ? 2248 index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2249 int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex); 2250 2251 // a last audible index of 0 is never stored, except on non-voice capable devices 2252 // (e.g. tablets) for the music stream type, where the music stream volume can reach 2253 // 0 without the device being in silent mode 2254 if ((lastAudibleIndex == 0) && 2255 (mVoiceCapable || 2256 (mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) { 2257 lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2258 // Correct the data base 2259 sendMsg(mAudioHandler, 2260 MSG_PERSIST_VOLUME, 2261 SENDMSG_QUEUE, 2262 PERSIST_LAST_AUDIBLE, 2263 device, 2264 this, 2265 PERSIST_DELAY); 2266 } 2267 mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex)); 2268 // the initial index should never be 0 for a stream affected by ringer mode if not 2269 // in silent or vibrate mode. 2270 // this is permitted on tablets for music stream type. 2271 if (checkSilentVolume && (index == 0) && 2272 (mVoiceCapable || 2273 (mStreamVolumeAlias[mStreamType] != AudioSystem.STREAM_MUSIC))) { 2274 index = lastAudibleIndex; 2275 // Correct the data base 2276 sendMsg(mAudioHandler, 2277 MSG_PERSIST_VOLUME, 2278 SENDMSG_QUEUE, 2279 PERSIST_CURRENT, 2280 device, 2281 this, 2282 PERSIST_DELAY); 2283 } 2284 mIndex.put(device, getValidIndex(10 * index)); 2285 } 2286 } 2287 2288 public void applyDeviceVolume(int device) { 2289 AudioSystem.setStreamVolumeIndex(mStreamType, 2290 (getIndex(device, false /* lastAudible */) + 5)/10, 2291 device); 2292 } 2293 2294 public void applyAllVolumes() { 2295 // apply default volume first: by convention this will reset all 2296 // devices volumes in audio policy manager to the supplied value 2297 AudioSystem.setStreamVolumeIndex(mStreamType, 2298 (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, 2299 AudioSystem.DEVICE_OUT_DEFAULT); 2300 // then apply device specific volumes 2301 Set set = mIndex.entrySet(); 2302 Iterator i = set.iterator(); 2303 while (i.hasNext()) { 2304 Map.Entry entry = (Map.Entry)i.next(); 2305 int device = ((Integer)entry.getKey()).intValue(); 2306 if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 2307 AudioSystem.setStreamVolumeIndex(mStreamType, 2308 ((Integer)entry.getValue() + 5)/10, 2309 device); 2310 } 2311 } 2312 } 2313 2314 public boolean adjustIndex(int deltaIndex, int device) { 2315 return setIndex(getIndex(device, 2316 false /* lastAudible */) + deltaIndex * 10, 2317 device, 2318 true /* lastAudible */); 2319 } 2320 2321 public boolean setIndex(int index, int device, boolean lastAudible) { 2322 int oldIndex = getIndex(device, false /* lastAudible */); 2323 index = getValidIndex(index); 2324 mIndex.put(device, getValidIndex(index)); 2325 2326 if (oldIndex != index) { 2327 if (lastAudible) { 2328 mLastAudibleIndex.put(device, index); 2329 } 2330 // Apply change to all streams using this one as alias 2331 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2332 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2333 if (streamType != mStreamType && mStreamVolumeAlias[streamType] == mStreamType) { 2334 mStreamStates[streamType].setIndex(rescaleIndex(index, 2335 mStreamType, 2336 streamType), 2337 getDeviceForStream(streamType), 2338 lastAudible); 2339 } 2340 } 2341 return true; 2342 } else { 2343 return false; 2344 } 2345 } 2346 2347 public int getIndex(int device, boolean lastAudible) { 2348 HashMap <Integer, Integer> indexes; 2349 if (lastAudible) { 2350 indexes = mLastAudibleIndex; 2351 } else { 2352 indexes = mIndex; 2353 } 2354 Integer index = indexes.get(device); 2355 if (index == null) { 2356 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 2357 index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); 2358 } 2359 return index.intValue(); 2360 } 2361 2362 public void setLastAudibleIndex(int index, int device) { 2363 mLastAudibleIndex.put(device, getValidIndex(index)); 2364 } 2365 2366 public void adjustLastAudibleIndex(int deltaIndex, int device) { 2367 setLastAudibleIndex(getIndex(device, 2368 true /* lastAudible */) + deltaIndex * 10, 2369 device); 2370 } 2371 2372 public int getMaxIndex() { 2373 return mIndexMax; 2374 } 2375 2376 public HashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { 2377 if (lastAudible) { 2378 return mLastAudibleIndex; 2379 } else { 2380 return mIndex; 2381 } 2382 } 2383 2384 public void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { 2385 HashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); 2386 Set set = indexes.entrySet(); 2387 Iterator i = set.iterator(); 2388 while (i.hasNext()) { 2389 Map.Entry entry = (Map.Entry)i.next(); 2390 int device = ((Integer)entry.getKey()).intValue(); 2391 int index = ((Integer)entry.getValue()).intValue(); 2392 index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 2393 setIndex(index, device, lastAudible); 2394 } 2395 } 2396 2397 public void mute(IBinder cb, boolean state) { 2398 VolumeDeathHandler handler = getDeathHandler(cb, state); 2399 if (handler == null) { 2400 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 2401 return; 2402 } 2403 handler.mute(state); 2404 } 2405 2406 public int getStreamType() { 2407 return mStreamType; 2408 } 2409 2410 private int getValidIndex(int index) { 2411 if (index < 0) { 2412 return 0; 2413 } else if (index > mIndexMax) { 2414 return mIndexMax; 2415 } 2416 2417 return index; 2418 } 2419 2420 private class VolumeDeathHandler implements IBinder.DeathRecipient { 2421 private IBinder mICallback; // To be notified of client's death 2422 private int mMuteCount; // Number of active mutes for this client 2423 2424 VolumeDeathHandler(IBinder cb) { 2425 mICallback = cb; 2426 } 2427 2428 public void mute(boolean state) { 2429 synchronized(mDeathHandlers) { 2430 if (state) { 2431 if (mMuteCount == 0) { 2432 // Register for client death notification 2433 try { 2434 // mICallback can be 0 if muted by AudioService 2435 if (mICallback != null) { 2436 mICallback.linkToDeath(this, 0); 2437 } 2438 mDeathHandlers.add(this); 2439 // If the stream is not yet muted by any client, set level to 0 2440 if (muteCount() == 0) { 2441 Set set = mIndex.entrySet(); 2442 Iterator i = set.iterator(); 2443 while (i.hasNext()) { 2444 Map.Entry entry = (Map.Entry)i.next(); 2445 int device = ((Integer)entry.getKey()).intValue(); 2446 setIndex(0, device, false /* lastAudible */); 2447 } 2448 sendMsg(mAudioHandler, 2449 MSG_SET_ALL_VOLUMES, 2450 SENDMSG_QUEUE, 2451 0, 2452 0, 2453 VolumeStreamState.this, 0); 2454 } 2455 } catch (RemoteException e) { 2456 // Client has died! 2457 binderDied(); 2458 mDeathHandlers.notify(); 2459 return; 2460 } 2461 } else { 2462 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 2463 } 2464 mMuteCount++; 2465 } else { 2466 if (mMuteCount == 0) { 2467 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 2468 } else { 2469 mMuteCount--; 2470 if (mMuteCount == 0) { 2471 // Unregistr from client death notification 2472 mDeathHandlers.remove(this); 2473 // mICallback can be 0 if muted by AudioService 2474 if (mICallback != null) { 2475 mICallback.unlinkToDeath(this, 0); 2476 } 2477 if (muteCount() == 0) { 2478 // If the stream is not muted any more, restore it's volume if 2479 // ringer mode allows it 2480 if (!isStreamAffectedByRingerMode(mStreamType) || 2481 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 2482 Set set = mIndex.entrySet(); 2483 Iterator i = set.iterator(); 2484 while (i.hasNext()) { 2485 Map.Entry entry = (Map.Entry)i.next(); 2486 int device = ((Integer)entry.getKey()).intValue(); 2487 setIndex(getIndex(device, 2488 true /* lastAudible */), 2489 device, 2490 false /* lastAudible */); 2491 } 2492 sendMsg(mAudioHandler, 2493 MSG_SET_ALL_VOLUMES, 2494 SENDMSG_QUEUE, 2495 0, 2496 0, 2497 VolumeStreamState.this, 0); 2498 } 2499 } 2500 } 2501 } 2502 } 2503 mDeathHandlers.notify(); 2504 } 2505 } 2506 2507 public void binderDied() { 2508 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 2509 if (mMuteCount != 0) { 2510 // Reset all active mute requests from this client. 2511 mMuteCount = 1; 2512 mute(false); 2513 } 2514 } 2515 } 2516 2517 private int muteCount() { 2518 int count = 0; 2519 int size = mDeathHandlers.size(); 2520 for (int i = 0; i < size; i++) { 2521 count += mDeathHandlers.get(i).mMuteCount; 2522 } 2523 return count; 2524 } 2525 2526 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 2527 synchronized(mDeathHandlers) { 2528 VolumeDeathHandler handler; 2529 int size = mDeathHandlers.size(); 2530 for (int i = 0; i < size; i++) { 2531 handler = mDeathHandlers.get(i); 2532 if (cb == handler.mICallback) { 2533 return handler; 2534 } 2535 } 2536 // If this is the first mute request for this client, create a new 2537 // client death handler. Otherwise, it is an out of sequence unmute request. 2538 if (state) { 2539 handler = new VolumeDeathHandler(cb); 2540 } else { 2541 Log.w(TAG, "stream was not muted by this client"); 2542 handler = null; 2543 } 2544 return handler; 2545 } 2546 } 2547 } 2548 2549 /** Thread that handles native AudioSystem control. */ 2550 private class AudioSystemThread extends Thread { 2551 AudioSystemThread() { 2552 super("AudioService"); 2553 } 2554 2555 @Override 2556 public void run() { 2557 // Set this thread up so the handler will work on it 2558 Looper.prepare(); 2559 2560 synchronized(AudioService.this) { 2561 mAudioHandler = new AudioHandler(); 2562 2563 // Notify that the handler has been created 2564 AudioService.this.notify(); 2565 } 2566 2567 // Listen for volume change requests that are set by VolumePanel 2568 Looper.loop(); 2569 } 2570 } 2571 2572 /** Handles internal volume messages in separate volume thread. */ 2573 private class AudioHandler extends Handler { 2574 2575 private void setDeviceVolume(VolumeStreamState streamState, int device) { 2576 2577 // Apply volume 2578 streamState.applyDeviceVolume(device); 2579 2580 // Apply change to all streams using this one as alias 2581 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2582 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2583 if (streamType != streamState.mStreamType && 2584 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 2585 mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 2586 } 2587 } 2588 2589 // Post a persist volume msg 2590 sendMsg(mAudioHandler, 2591 MSG_PERSIST_VOLUME, 2592 SENDMSG_QUEUE, 2593 PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, 2594 device, 2595 streamState, 2596 PERSIST_DELAY); 2597 2598 } 2599 2600 private void setAllVolumes(VolumeStreamState streamState) { 2601 2602 // Apply volume 2603 streamState.applyAllVolumes(); 2604 2605 // Apply change to all streams using this one as alias 2606 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2607 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2608 if (streamType != streamState.mStreamType && 2609 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 2610 mStreamStates[streamType].applyAllVolumes(); 2611 } 2612 } 2613 } 2614 2615 private void persistVolume(VolumeStreamState streamState, 2616 int persistType, 2617 int device) { 2618 if ((persistType & PERSIST_CURRENT) != 0) { 2619 System.putInt(mContentResolver, 2620 streamState.getSettingNameForDevice(false /* lastAudible */, device), 2621 (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10); 2622 } 2623 if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { 2624 System.putInt(mContentResolver, 2625 streamState.getSettingNameForDevice(true /* lastAudible */, device), 2626 (streamState.getIndex(device, true /* lastAudible */) + 5) / 10); 2627 } 2628 } 2629 2630 private void persistRingerMode(int ringerMode) { 2631 System.putInt(mContentResolver, System.MODE_RINGER, ringerMode); 2632 } 2633 2634 private void persistVibrateSetting() { 2635 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 2636 } 2637 2638 private void playSoundEffect(int effectType, int volume) { 2639 synchronized (mSoundEffectsLock) { 2640 if (mSoundPool == null) { 2641 return; 2642 } 2643 float volFloat; 2644 // use default if volume is not specified by caller 2645 if (volume < 0) { 2646 volFloat = (float)Math.pow(10, SOUND_EFFECT_VOLUME_DB/20); 2647 } else { 2648 volFloat = (float) volume / 1000.0f; 2649 } 2650 2651 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 2652 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 2653 } else { 2654 MediaPlayer mediaPlayer = new MediaPlayer(); 2655 try { 2656 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 2657 mediaPlayer.setDataSource(filePath); 2658 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 2659 mediaPlayer.prepare(); 2660 mediaPlayer.setVolume(volFloat, volFloat); 2661 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 2662 public void onCompletion(MediaPlayer mp) { 2663 cleanupPlayer(mp); 2664 } 2665 }); 2666 mediaPlayer.setOnErrorListener(new OnErrorListener() { 2667 public boolean onError(MediaPlayer mp, int what, int extra) { 2668 cleanupPlayer(mp); 2669 return true; 2670 } 2671 }); 2672 mediaPlayer.start(); 2673 } catch (IOException ex) { 2674 Log.w(TAG, "MediaPlayer IOException: "+ex); 2675 } catch (IllegalArgumentException ex) { 2676 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 2677 } catch (IllegalStateException ex) { 2678 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 2679 } 2680 } 2681 } 2682 } 2683 2684 private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { 2685 Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER, 2686 receiver == null ? "" : receiver.flattenToString()); 2687 } 2688 2689 private void cleanupPlayer(MediaPlayer mp) { 2690 if (mp != null) { 2691 try { 2692 mp.stop(); 2693 mp.release(); 2694 } catch (IllegalStateException ex) { 2695 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 2696 } 2697 } 2698 } 2699 2700 private void setForceUse(int usage, int config) { 2701 AudioSystem.setForceUse(usage, config); 2702 } 2703 2704 @Override 2705 public void handleMessage(Message msg) { 2706 2707 switch (msg.what) { 2708 2709 case MSG_SET_DEVICE_VOLUME: 2710 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 2711 break; 2712 2713 case MSG_SET_ALL_VOLUMES: 2714 setAllVolumes((VolumeStreamState) msg.obj); 2715 break; 2716 2717 case MSG_PERSIST_VOLUME: 2718 persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); 2719 break; 2720 2721 case MSG_PERSIST_MASTER_VOLUME: 2722 Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER, 2723 (float)msg.arg1 / (float)1000.0); 2724 break; 2725 2726 case MSG_PERSIST_MASTER_VOLUME_MUTE: 2727 Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE, 2728 msg.arg1); 2729 break; 2730 2731 case MSG_PERSIST_RINGER_MODE: 2732 // note that the value persisted is the current ringer mode, not the 2733 // value of ringer mode as of the time the request was made to persist 2734 persistRingerMode(getRingerMode()); 2735 break; 2736 2737 case MSG_PERSIST_VIBRATE_SETTING: 2738 persistVibrateSetting(); 2739 break; 2740 2741 case MSG_MEDIA_SERVER_DIED: 2742 if (!mMediaServerOk) { 2743 Log.e(TAG, "Media server died."); 2744 // Force creation of new IAudioFlinger interface so that we are notified 2745 // when new media_server process is back to life. 2746 AudioSystem.setErrorCallback(mAudioSystemCallback); 2747 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 2748 null, 500); 2749 } 2750 break; 2751 2752 case MSG_MEDIA_SERVER_STARTED: 2753 Log.e(TAG, "Media server started."); 2754 // indicate to audio HAL that we start the reconfiguration phase after a media 2755 // server crash 2756 // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 2757 // process restarts after a crash, not the first time it is started. 2758 AudioSystem.setParameters("restarting=true"); 2759 2760 // Restore device connection states 2761 synchronized (mConnectedDevices) { 2762 Set set = mConnectedDevices.entrySet(); 2763 Iterator i = set.iterator(); 2764 while (i.hasNext()) { 2765 Map.Entry device = (Map.Entry)i.next(); 2766 AudioSystem.setDeviceConnectionState( 2767 ((Integer)device.getKey()).intValue(), 2768 AudioSystem.DEVICE_STATE_AVAILABLE, 2769 (String)device.getValue()); 2770 } 2771 } 2772 // Restore call state 2773 AudioSystem.setPhoneState(mMode); 2774 2775 // Restore forced usage for communcations and record 2776 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 2777 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 2778 2779 // Restore stream volumes 2780 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2781 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2782 VolumeStreamState streamState = mStreamStates[streamType]; 2783 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 2784 2785 streamState.applyAllVolumes(); 2786 } 2787 2788 // Restore ringer mode 2789 setRingerModeInt(getRingerMode(), false); 2790 2791 // Restore master volume 2792 restoreMasterVolume(); 2793 2794 // Reset device orientation (if monitored for this device) 2795 if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 2796 setOrientationForAudioSystem(); 2797 } 2798 2799 // indicate the end of reconfiguration phase to audio HAL 2800 AudioSystem.setParameters("restarting=false"); 2801 break; 2802 2803 case MSG_LOAD_SOUND_EFFECTS: 2804 loadSoundEffects(); 2805 break; 2806 2807 case MSG_PLAY_SOUND_EFFECT: 2808 playSoundEffect(msg.arg1, msg.arg2); 2809 break; 2810 2811 case MSG_BTA2DP_DOCK_TIMEOUT: 2812 // msg.obj == address of BTA2DP device 2813 synchronized (mConnectedDevices) { 2814 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 2815 } 2816 break; 2817 2818 case MSG_SET_FORCE_USE: 2819 setForceUse(msg.arg1, msg.arg2); 2820 break; 2821 2822 case MSG_PERSIST_MEDIABUTTONRECEIVER: 2823 onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); 2824 break; 2825 2826 case MSG_RCDISPLAY_CLEAR: 2827 onRcDisplayClear(); 2828 break; 2829 2830 case MSG_RCDISPLAY_UPDATE: 2831 // msg.obj is guaranteed to be non null 2832 onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); 2833 break; 2834 2835 case MSG_BT_HEADSET_CNCT_FAILED: 2836 resetBluetoothSco(); 2837 break; 2838 } 2839 } 2840 } 2841 2842 private class SettingsObserver extends ContentObserver { 2843 2844 SettingsObserver() { 2845 super(new Handler()); 2846 mContentResolver.registerContentObserver(Settings.System.getUriFor( 2847 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 2848 } 2849 2850 @Override 2851 public void onChange(boolean selfChange) { 2852 super.onChange(selfChange); 2853 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 2854 // However there appear to be some missing locks around mRingerModeMutedStreams 2855 // and mRingerModeAffectedStreams, so will leave this synchronized for now. 2856 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 2857 synchronized (mSettingsLock) { 2858 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 2859 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 2860 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 2861 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 2862 if (mVoiceCapable) { 2863 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 2864 } else { 2865 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 2866 } 2867 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 2868 /* 2869 * Ensure all stream types that should be affected by ringer mode 2870 * are in the proper state. 2871 */ 2872 mRingerModeAffectedStreams = ringerModeAffectedStreams; 2873 setRingerModeInt(getRingerMode(), false); 2874 } 2875 } 2876 } 2877 } 2878 2879 // must be called synchronized on mConnectedDevices 2880 private void makeA2dpDeviceAvailable(String address) { 2881 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2882 AudioSystem.DEVICE_STATE_AVAILABLE, 2883 address); 2884 // Reset A2DP suspend state each time a new sink is connected 2885 AudioSystem.setParameters("A2dpSuspended=false"); 2886 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 2887 address); 2888 } 2889 2890 // must be called synchronized on mConnectedDevices 2891 private void makeA2dpDeviceUnavailableNow(String address) { 2892 Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 2893 mContext.sendBroadcast(noisyIntent); 2894 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2895 AudioSystem.DEVICE_STATE_UNAVAILABLE, 2896 address); 2897 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 2898 } 2899 2900 // must be called synchronized on mConnectedDevices 2901 private void makeA2dpDeviceUnavailableLater(String address) { 2902 // prevent any activity on the A2DP audio output to avoid unwanted 2903 // reconnection of the sink. 2904 AudioSystem.setParameters("A2dpSuspended=true"); 2905 // the device will be made unavailable later, so consider it disconnected right away 2906 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 2907 // send the delayed message to make the device unavailable later 2908 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 2909 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 2910 2911 } 2912 2913 // must be called synchronized on mConnectedDevices 2914 private void cancelA2dpDeviceTimeout() { 2915 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 2916 } 2917 2918 // must be called synchronized on mConnectedDevices 2919 private boolean hasScheduledA2dpDockTimeout() { 2920 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 2921 } 2922 2923 private void handleA2dpConnectionStateChange(BluetoothDevice btDevice, int state) 2924 { 2925 if (btDevice == null) { 2926 return; 2927 } 2928 String address = btDevice.getAddress(); 2929 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 2930 address = ""; 2931 } 2932 synchronized (mConnectedDevices) { 2933 boolean isConnected = 2934 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 2935 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 2936 2937 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 2938 if (btDevice.isBluetoothDock()) { 2939 if (state == BluetoothProfile.STATE_DISCONNECTED) { 2940 // introduction of a delay for transient disconnections of docks when 2941 // power is rapidly turned off/on, this message will be canceled if 2942 // we reconnect the dock under a preset delay 2943 makeA2dpDeviceUnavailableLater(address); 2944 // the next time isConnected is evaluated, it will be false for the dock 2945 } 2946 } else { 2947 makeA2dpDeviceUnavailableNow(address); 2948 } 2949 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 2950 if (btDevice.isBluetoothDock()) { 2951 // this could be a reconnection after a transient disconnection 2952 cancelA2dpDeviceTimeout(); 2953 mDockAddress = address; 2954 } else { 2955 // this could be a connection of another A2DP device before the timeout of 2956 // a dock: cancel the dock timeout, and make the dock unavailable now 2957 if(hasScheduledA2dpDockTimeout()) { 2958 cancelA2dpDeviceTimeout(); 2959 makeA2dpDeviceUnavailableNow(mDockAddress); 2960 } 2961 } 2962 makeA2dpDeviceAvailable(address); 2963 } 2964 } 2965 } 2966 2967 private boolean handleDeviceConnection(boolean connected, int device, String params) { 2968 synchronized (mConnectedDevices) { 2969 boolean isConnected = (mConnectedDevices.containsKey(device) && 2970 mConnectedDevices.get(device).equals(params)); 2971 2972 if (isConnected && !connected) { 2973 AudioSystem.setDeviceConnectionState(device, 2974 AudioSystem.DEVICE_STATE_UNAVAILABLE, 2975 params); 2976 mConnectedDevices.remove(device); 2977 return true; 2978 } else if (!isConnected && connected) { 2979 AudioSystem.setDeviceConnectionState(device, 2980 AudioSystem.DEVICE_STATE_AVAILABLE, 2981 params); 2982 mConnectedDevices.put(new Integer(device), params); 2983 return true; 2984 } 2985 } 2986 return false; 2987 } 2988 2989 /* cache of the address of the last dock the device was connected to */ 2990 private String mDockAddress; 2991 2992 /** 2993 * Receiver for misc intent broadcasts the Phone app cares about. 2994 */ 2995 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 2996 @Override 2997 public void onReceive(Context context, Intent intent) { 2998 String action = intent.getAction(); 2999 int device; 3000 int state; 3001 3002 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3003 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3004 Intent.EXTRA_DOCK_STATE_UNDOCKED); 3005 int config; 3006 switch (dockState) { 3007 case Intent.EXTRA_DOCK_STATE_DESK: 3008 config = AudioSystem.FORCE_BT_DESK_DOCK; 3009 break; 3010 case Intent.EXTRA_DOCK_STATE_CAR: 3011 config = AudioSystem.FORCE_BT_CAR_DOCK; 3012 break; 3013 case Intent.EXTRA_DOCK_STATE_LE_DESK: 3014 config = AudioSystem.FORCE_ANALOG_DOCK; 3015 break; 3016 case Intent.EXTRA_DOCK_STATE_HE_DESK: 3017 config = AudioSystem.FORCE_DIGITAL_DOCK; 3018 break; 3019 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3020 default: 3021 config = AudioSystem.FORCE_NONE; 3022 } 3023 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 3024 } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { 3025 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3026 BluetoothProfile.STATE_DISCONNECTED); 3027 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3028 3029 handleA2dpConnectionStateChange(btDevice, state); 3030 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 3031 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3032 BluetoothProfile.STATE_DISCONNECTED); 3033 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3034 String address = null; 3035 3036 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3037 if (btDevice == null) { 3038 return; 3039 } 3040 3041 address = btDevice.getAddress(); 3042 BluetoothClass btClass = btDevice.getBluetoothClass(); 3043 if (btClass != null) { 3044 switch (btClass.getDeviceClass()) { 3045 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3046 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3047 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3048 break; 3049 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3050 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3051 break; 3052 } 3053 } 3054 3055 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3056 address = ""; 3057 } 3058 3059 boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 3060 if (handleDeviceConnection(connected, device, address)) { 3061 synchronized (mScoClients) { 3062 if (connected) { 3063 mBluetoothHeadsetDevice = btDevice; 3064 } else { 3065 mBluetoothHeadsetDevice = null; 3066 resetBluetoothSco(); 3067 } 3068 } 3069 } 3070 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 3071 state = intent.getIntExtra("state", 0); 3072 int microphone = intent.getIntExtra("microphone", 0); 3073 3074 if (microphone != 0) { 3075 device = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 3076 } else { 3077 device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 3078 } 3079 handleDeviceConnection((state == 1), device, ""); 3080 } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) { 3081 state = intent.getIntExtra("state", 0); 3082 Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state); 3083 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, ""); 3084 } else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) { 3085 state = intent.getIntExtra("state", 0); 3086 Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state); 3087 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_AUX_DIGITAL, ""); 3088 } else if (action.equals(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG)) { 3089 state = intent.getIntExtra("state", 0); 3090 Log.v(TAG, 3091 "Broadcast Receiver Got ACTION_DIGITAL_AUDIO_DOCK_PLUG, state = " + state); 3092 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, ""); 3093 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 3094 action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 3095 state = intent.getIntExtra("state", 0); 3096 int alsaCard = intent.getIntExtra("card", -1); 3097 int alsaDevice = intent.getIntExtra("device", -1); 3098 String params = "card=" + alsaCard + ";device=" + alsaDevice; 3099 device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3100 AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 3101 Log.v(TAG, "Broadcast Receiver: Got " 3102 + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3103 "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 3104 + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 3105 handleDeviceConnection((state == 1), device, params); 3106 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 3107 boolean broadcast = false; 3108 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 3109 synchronized (mScoClients) { 3110 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 3111 // broadcast intent if the connection was initated by AudioService 3112 if (!mScoClients.isEmpty() && 3113 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 3114 mScoAudioState == SCO_STATE_ACTIVATE_REQ || 3115 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 3116 broadcast = true; 3117 } 3118 switch (btState) { 3119 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 3120 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 3121 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3122 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3123 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3124 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3125 } 3126 break; 3127 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 3128 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 3129 mScoAudioState = SCO_STATE_INACTIVE; 3130 clearAllScoClients(0, false); 3131 break; 3132 case BluetoothHeadset.STATE_AUDIO_CONNECTING: 3133 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3134 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3135 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3136 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3137 } 3138 default: 3139 // do not broadcast CONNECTING or invalid state 3140 broadcast = false; 3141 break; 3142 } 3143 } 3144 if (broadcast) { 3145 broadcastScoConnectionState(scoAudioState); 3146 //FIXME: this is to maintain compatibility with deprecated intent 3147 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3148 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3149 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 3150 mContext.sendStickyBroadcast(newIntent); 3151 } 3152 } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 3153 mBootCompleted = true; 3154 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 3155 0, 0, null, 0); 3156 3157 mKeyguardManager = 3158 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 3159 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 3160 resetBluetoothSco(); 3161 getBluetoothHeadset(); 3162 //FIXME: this is to maintain compatibility with deprecated intent 3163 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3164 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3165 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 3166 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 3167 mContext.sendStickyBroadcast(newIntent); 3168 3169 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 3170 if (adapter != null) { 3171 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 3172 BluetoothProfile.A2DP); 3173 } 3174 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { 3175 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 3176 // a package is being removed, not replaced 3177 String packageName = intent.getData().getSchemeSpecificPart(); 3178 if (packageName != null) { 3179 removeMediaButtonReceiverForPackage(packageName); 3180 } 3181 } 3182 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 3183 AudioSystem.setParameters("screen_state=on"); 3184 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 3185 AudioSystem.setParameters("screen_state=off"); 3186 } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) { 3187 handleConfigurationChanged(context); 3188 } 3189 } 3190 } 3191 3192 //========================================================================================== 3193 // AudioFocus 3194 //========================================================================================== 3195 3196 /* constant to identify focus stack entry that is used to hold the focus while the phone 3197 * is ringing or during a call. Used by com.android.internal.telephony.CallManager when 3198 * entering and exiting calls. 3199 */ 3200 public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; 3201 3202 private final static Object mAudioFocusLock = new Object(); 3203 3204 private final static Object mRingingLock = new Object(); 3205 3206 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 3207 @Override 3208 public void onCallStateChanged(int state, String incomingNumber) { 3209 if (state == TelephonyManager.CALL_STATE_RINGING) { 3210 //Log.v(TAG, " CALL_STATE_RINGING"); 3211 synchronized(mRingingLock) { 3212 mIsRinging = true; 3213 } 3214 } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) 3215 || (state == TelephonyManager.CALL_STATE_IDLE)) { 3216 synchronized(mRingingLock) { 3217 mIsRinging = false; 3218 } 3219 } 3220 } 3221 }; 3222 3223 private void notifyTopOfAudioFocusStack() { 3224 // notify the top of the stack it gained focus 3225 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3226 if (canReassignAudioFocus()) { 3227 try { 3228 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3229 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 3230 } catch (RemoteException e) { 3231 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 3232 e.printStackTrace(); 3233 } 3234 } 3235 } 3236 } 3237 3238 private static class FocusStackEntry { 3239 public int mStreamType = -1;// no stream type 3240 public IAudioFocusDispatcher mFocusDispatcher = null; 3241 public IBinder mSourceRef = null; 3242 public String mClientId; 3243 public int mFocusChangeType; 3244 public AudioFocusDeathHandler mHandler; 3245 public String mPackageName; 3246 public int mCallingUid; 3247 3248 public FocusStackEntry() { 3249 } 3250 3251 public FocusStackEntry(int streamType, int duration, 3252 IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 3253 String pn, int uid) { 3254 mStreamType = streamType; 3255 mFocusDispatcher = afl; 3256 mSourceRef = source; 3257 mClientId = id; 3258 mFocusChangeType = duration; 3259 mHandler = hdlr; 3260 mPackageName = pn; 3261 mCallingUid = uid; 3262 } 3263 3264 public void unlinkToDeath() { 3265 try { 3266 if (mSourceRef != null && mHandler != null) { 3267 mSourceRef.unlinkToDeath(mHandler, 0); 3268 mHandler = null; 3269 } 3270 } catch (java.util.NoSuchElementException e) { 3271 Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); 3272 } 3273 } 3274 3275 @Override 3276 protected void finalize() throws Throwable { 3277 unlinkToDeath(); // unlink exception handled inside method 3278 super.finalize(); 3279 } 3280 } 3281 3282 private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 3283 3284 /** 3285 * Helper function: 3286 * Display in the log the current entries in the audio focus stack 3287 */ 3288 private void dumpFocusStack(PrintWriter pw) { 3289 pw.println("\nAudio Focus stack entries:"); 3290 synchronized(mAudioFocusLock) { 3291 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3292 while(stackIterator.hasNext()) { 3293 FocusStackEntry fse = stackIterator.next(); 3294 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 3295 + " -- duration: " + fse.mFocusChangeType 3296 + " -- uid: " + fse.mCallingUid); 3297 } 3298 } 3299 } 3300 3301 /** 3302 * Helper function: 3303 * Called synchronized on mAudioFocusLock 3304 * Remove a focus listener from the focus stack. 3305 * @param focusListenerToRemove the focus listener 3306 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 3307 * focus, notify the next item in the stack it gained focus. 3308 */ 3309 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 3310 // is the current top of the focus stack abandoning focus? (because of request, not death) 3311 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 3312 { 3313 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 3314 FocusStackEntry fse = mFocusStack.pop(); 3315 fse.unlinkToDeath(); 3316 if (signal) { 3317 // notify the new top of the stack it gained focus 3318 notifyTopOfAudioFocusStack(); 3319 // there's a new top of the stack, let the remote control know 3320 synchronized(mRCStack) { 3321 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3322 } 3323 } 3324 } else { 3325 // focus is abandoned by a client that's not at the top of the stack, 3326 // no need to update focus. 3327 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3328 while(stackIterator.hasNext()) { 3329 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3330 if(fse.mClientId.equals(clientToRemove)) { 3331 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3332 + fse.mClientId); 3333 stackIterator.remove(); 3334 fse.unlinkToDeath(); 3335 } 3336 } 3337 } 3338 } 3339 3340 /** 3341 * Helper function: 3342 * Called synchronized on mAudioFocusLock 3343 * Remove focus listeners from the focus stack for a particular client when it has died. 3344 */ 3345 private void removeFocusStackEntryForClient(IBinder cb) { 3346 // is the owner of the audio focus part of the client to remove? 3347 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 3348 mFocusStack.peek().mSourceRef.equals(cb); 3349 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3350 while(stackIterator.hasNext()) { 3351 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3352 if(fse.mSourceRef.equals(cb)) { 3353 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3354 + fse.mClientId); 3355 stackIterator.remove(); 3356 // the client just died, no need to unlink to its death 3357 } 3358 } 3359 if (isTopOfStackForClientToRemove) { 3360 // we removed an entry at the top of the stack: 3361 // notify the new top of the stack it gained focus. 3362 notifyTopOfAudioFocusStack(); 3363 // there's a new top of the stack, let the remote control know 3364 synchronized(mRCStack) { 3365 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3366 } 3367 } 3368 } 3369 3370 /** 3371 * Helper function: 3372 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 3373 */ 3374 private boolean canReassignAudioFocus() { 3375 // focus requests are rejected during a phone call or when the phone is ringing 3376 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 3377 if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { 3378 return false; 3379 } 3380 return true; 3381 } 3382 3383 /** 3384 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 3385 * stack if necessary. 3386 */ 3387 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 3388 private IBinder mCb; // To be notified of client's death 3389 3390 AudioFocusDeathHandler(IBinder cb) { 3391 mCb = cb; 3392 } 3393 3394 public void binderDied() { 3395 synchronized(mAudioFocusLock) { 3396 Log.w(TAG, " AudioFocus audio focus client died"); 3397 removeFocusStackEntryForClient(mCb); 3398 } 3399 } 3400 3401 public IBinder getBinder() { 3402 return mCb; 3403 } 3404 } 3405 3406 3407 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 3408 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 3409 IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 3410 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 3411 // the main stream type for the audio focus request is currently not used. It may 3412 // potentially be used to handle multiple stream type-dependent audio focuses. 3413 3414 // we need a valid binder callback for clients 3415 if (!cb.pingBinder()) { 3416 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 3417 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3418 } 3419 3420 synchronized(mAudioFocusLock) { 3421 if (!canReassignAudioFocus()) { 3422 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3423 } 3424 3425 // handle the potential premature death of the new holder of the focus 3426 // (premature death == death before abandoning focus) 3427 // Register for client death notification 3428 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 3429 try { 3430 cb.linkToDeath(afdh, 0); 3431 } catch (RemoteException e) { 3432 // client has already died! 3433 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 3434 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3435 } 3436 3437 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 3438 // if focus is already owned by this client and the reason for acquiring the focus 3439 // hasn't changed, don't do anything 3440 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 3441 // unlink death handler so it can be gc'ed. 3442 // linkToDeath() creates a JNI global reference preventing collection. 3443 cb.unlinkToDeath(afdh, 0); 3444 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3445 } 3446 // the reason for the audio focus request has changed: remove the current top of 3447 // stack and respond as if we had a new focus owner 3448 FocusStackEntry fse = mFocusStack.pop(); 3449 fse.unlinkToDeath(); 3450 } 3451 3452 // notify current top of stack it is losing focus 3453 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3454 try { 3455 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3456 -1 * focusChangeHint, // loss and gain codes are inverse of each other 3457 mFocusStack.peek().mClientId); 3458 } catch (RemoteException e) { 3459 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 3460 e.printStackTrace(); 3461 } 3462 } 3463 3464 // focus requester might already be somewhere below in the stack, remove it 3465 removeFocusStackEntry(clientId, false /* signal */); 3466 3467 // push focus requester at the top of the audio focus stack 3468 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, 3469 clientId, afdh, callingPackageName, Binder.getCallingUid())); 3470 3471 // there's a new top of the stack, let the remote control know 3472 synchronized(mRCStack) { 3473 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3474 } 3475 }//synchronized(mAudioFocusLock) 3476 3477 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3478 } 3479 3480 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 3481 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 3482 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 3483 try { 3484 // this will take care of notifying the new focus owner if needed 3485 synchronized(mAudioFocusLock) { 3486 removeFocusStackEntry(clientId, true); 3487 } 3488 } catch (java.util.ConcurrentModificationException cme) { 3489 // Catching this exception here is temporary. It is here just to prevent 3490 // a crash seen when the "Silent" notification is played. This is believed to be fixed 3491 // but this try catch block is left just to be safe. 3492 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 3493 cme.printStackTrace(); 3494 } 3495 3496 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3497 } 3498 3499 3500 public void unregisterAudioFocusClient(String clientId) { 3501 synchronized(mAudioFocusLock) { 3502 removeFocusStackEntry(clientId, false); 3503 } 3504 } 3505 3506 3507 //========================================================================================== 3508 // RemoteControl 3509 //========================================================================================== 3510 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 3511 dispatchMediaKeyEvent(keyEvent, false /*needWakeLock*/); 3512 } 3513 3514 public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 3515 dispatchMediaKeyEvent(keyEvent, true /*needWakeLock*/); 3516 } 3517 3518 /** 3519 * Handles the dispatching of the media button events to one of the registered listeners, 3520 * or if there was none, broadcast a ACTION_MEDIA_BUTTON intent to the rest of the system. 3521 */ 3522 private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3523 // sanity check on the incoming key event 3524 if (!isValidMediaKeyEvent(keyEvent)) { 3525 Log.e(TAG, "not dispatching invalid media key event " + keyEvent); 3526 return; 3527 } 3528 // event filtering 3529 synchronized(mRingingLock) { 3530 if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) || 3531 (getMode() == AudioSystem.MODE_IN_COMMUNICATION) || 3532 (getMode() == AudioSystem.MODE_RINGTONE) ) { 3533 return; 3534 } 3535 } 3536 if (needWakeLock) { 3537 mMediaEventWakeLock.acquire(); 3538 } 3539 Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3540 keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3541 synchronized(mRCStack) { 3542 if (!mRCStack.empty()) { 3543 // send the intent that was registered by the client 3544 try { 3545 mRCStack.peek().mMediaIntent.send(mContext, 3546 needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, 3547 keyIntent, AudioService.this, mAudioHandler); 3548 } catch (CanceledException e) { 3549 Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); 3550 e.printStackTrace(); 3551 } 3552 } else { 3553 // legacy behavior when nobody registered their media button event receiver 3554 // through AudioManager 3555 if (needWakeLock) { 3556 keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3557 } 3558 mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3559 mAudioHandler, Activity.RESULT_OK, null, null); 3560 } 3561 } 3562 } 3563 3564 private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { 3565 if (keyEvent == null) { 3566 return false; 3567 } 3568 final int keyCode = keyEvent.getKeyCode(); 3569 switch (keyCode) { 3570 case KeyEvent.KEYCODE_MUTE: 3571 case KeyEvent.KEYCODE_HEADSETHOOK: 3572 case KeyEvent.KEYCODE_MEDIA_PLAY: 3573 case KeyEvent.KEYCODE_MEDIA_PAUSE: 3574 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 3575 case KeyEvent.KEYCODE_MEDIA_STOP: 3576 case KeyEvent.KEYCODE_MEDIA_NEXT: 3577 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 3578 case KeyEvent.KEYCODE_MEDIA_REWIND: 3579 case KeyEvent.KEYCODE_MEDIA_RECORD: 3580 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 3581 case KeyEvent.KEYCODE_MEDIA_CLOSE: 3582 case KeyEvent.KEYCODE_MEDIA_EJECT: 3583 break; 3584 default: 3585 return false; 3586 } 3587 return true; 3588 } 3589 3590 private PowerManager.WakeLock mMediaEventWakeLock; 3591 3592 private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number 3593 3594 // only set when wakelock was acquired, no need to check value when received 3595 private static final String EXTRA_WAKELOCK_ACQUIRED = 3596 "android.media.AudioService.WAKELOCK_ACQUIRED"; 3597 3598 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 3599 int resultCode, String resultData, Bundle resultExtras) { 3600 if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { 3601 mMediaEventWakeLock.release(); 3602 } 3603 } 3604 3605 BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { 3606 public void onReceive(Context context, Intent intent) { 3607 if (intent.getExtras().containsKey(EXTRA_WAKELOCK_ACQUIRED)) { 3608 mMediaEventWakeLock.release(); 3609 } 3610 } 3611 }; 3612 3613 private final Object mCurrentRcLock = new Object(); 3614 /** 3615 * The one remote control client which will receive a request for display information. 3616 * This object may be null. 3617 * Access protected by mCurrentRcLock. 3618 */ 3619 private IRemoteControlClient mCurrentRcClient = null; 3620 3621 private final static int RC_INFO_NONE = 0; 3622 private final static int RC_INFO_ALL = 3623 RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | 3624 RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | 3625 RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | 3626 RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; 3627 3628 /** 3629 * A monotonically increasing generation counter for mCurrentRcClient. 3630 * Only accessed with a lock on mCurrentRcLock. 3631 * No value wrap-around issues as we only act on equal values. 3632 */ 3633 private int mCurrentRcClientGen = 0; 3634 3635 /** 3636 * Inner class to monitor remote control client deaths, and remove the client for the 3637 * remote control stack if necessary. 3638 */ 3639 private class RcClientDeathHandler implements IBinder.DeathRecipient { 3640 private IBinder mCb; // To be notified of client's death 3641 private PendingIntent mMediaIntent; 3642 3643 RcClientDeathHandler(IBinder cb, PendingIntent pi) { 3644 mCb = cb; 3645 mMediaIntent = pi; 3646 } 3647 3648 public void binderDied() { 3649 Log.w(TAG, " RemoteControlClient died"); 3650 // remote control client died, make sure the displays don't use it anymore 3651 // by setting its remote control client to null 3652 registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); 3653 } 3654 3655 public IBinder getBinder() { 3656 return mCb; 3657 } 3658 } 3659 3660 private static class RemoteControlStackEntry { 3661 /** 3662 * The target for the ACTION_MEDIA_BUTTON events. 3663 * Always non null. 3664 */ 3665 public PendingIntent mMediaIntent; 3666 /** 3667 * The registered media button event receiver. 3668 * Always non null. 3669 */ 3670 public ComponentName mReceiverComponent; 3671 public String mCallingPackageName; 3672 public int mCallingUid; 3673 /** 3674 * Provides access to the information to display on the remote control. 3675 * May be null (when a media button event receiver is registered, 3676 * but no remote control client has been registered) */ 3677 public IRemoteControlClient mRcClient; 3678 public RcClientDeathHandler mRcClientDeathHandler; 3679 3680 /** precondition: mediaIntent != null, eventReceiver != null */ 3681 public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { 3682 mMediaIntent = mediaIntent; 3683 mReceiverComponent = eventReceiver; 3684 mCallingUid = -1; 3685 mRcClient = null; 3686 } 3687 3688 public void unlinkToRcClientDeath() { 3689 if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { 3690 try { 3691 mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); 3692 mRcClientDeathHandler = null; 3693 } catch (java.util.NoSuchElementException e) { 3694 // not much we can do here 3695 Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); 3696 e.printStackTrace(); 3697 } 3698 } 3699 } 3700 3701 @Override 3702 protected void finalize() throws Throwable { 3703 unlinkToRcClientDeath();// unlink exception handled inside method 3704 super.finalize(); 3705 } 3706 } 3707 3708 /** 3709 * The stack of remote control event receivers. 3710 * Code sections and methods that modify the remote control event receiver stack are 3711 * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either 3712 * stack, audio focus or RC, can lead to a change in the remote control display 3713 */ 3714 private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 3715 3716 /** 3717 * Helper function: 3718 * Display in the log the current entries in the remote control focus stack 3719 */ 3720 private void dumpRCStack(PrintWriter pw) { 3721 pw.println("\nRemote Control stack entries:"); 3722 synchronized(mRCStack) { 3723 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3724 while(stackIterator.hasNext()) { 3725 RemoteControlStackEntry rcse = stackIterator.next(); 3726 pw.println(" pi: " + rcse.mMediaIntent + 3727 " -- ercvr: " + rcse.mReceiverComponent + 3728 " -- client: " + rcse.mRcClient + 3729 " -- uid: " + rcse.mCallingUid); 3730 } 3731 } 3732 } 3733 3734 /** 3735 * Helper function: 3736 * Remove any entry in the remote control stack that has the same package name as packageName 3737 * Pre-condition: packageName != null 3738 */ 3739 private void removeMediaButtonReceiverForPackage(String packageName) { 3740 synchronized(mRCStack) { 3741 if (mRCStack.empty()) { 3742 return; 3743 } else { 3744 RemoteControlStackEntry oldTop = mRCStack.peek(); 3745 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3746 // iterate over the stack entries 3747 while(stackIterator.hasNext()) { 3748 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 3749 if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) { 3750 // a stack entry is from the package being removed, remove it from the stack 3751 stackIterator.remove(); 3752 rcse.unlinkToRcClientDeath(); 3753 } 3754 } 3755 if (mRCStack.empty()) { 3756 // no saved media button receiver 3757 mAudioHandler.sendMessage( 3758 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 3759 null)); 3760 } else if (oldTop != mRCStack.peek()) { 3761 // the top of the stack has changed, save it in the system settings 3762 // by posting a message to persist it 3763 mAudioHandler.sendMessage( 3764 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 3765 mRCStack.peek().mReceiverComponent)); 3766 } 3767 } 3768 } 3769 } 3770 3771 /** 3772 * Helper function: 3773 * Restore remote control receiver from the system settings. 3774 */ 3775 private void restoreMediaButtonReceiver() { 3776 String receiverName = Settings.System.getString(mContentResolver, 3777 Settings.System.MEDIA_BUTTON_RECEIVER); 3778 if ((null != receiverName) && !receiverName.isEmpty()) { 3779 ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); 3780 // construct a PendingIntent targeted to the restored component name 3781 // for the media button and register it 3782 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 3783 // the associated intent will be handled by the component being registered 3784 mediaButtonIntent.setComponent(eventReceiver); 3785 PendingIntent pi = PendingIntent.getBroadcast(mContext, 3786 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 3787 registerMediaButtonIntent(pi, eventReceiver); 3788 } 3789 } 3790 3791 /** 3792 * Helper function: 3793 * Set the new remote control receiver at the top of the RC focus stack. 3794 * precondition: mediaIntent != null, target != null 3795 */ 3796 private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) { 3797 // already at top of stack? 3798 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { 3799 return; 3800 } 3801 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3802 RemoteControlStackEntry rcse = null; 3803 boolean wasInsideStack = false; 3804 while(stackIterator.hasNext()) { 3805 rcse = (RemoteControlStackEntry)stackIterator.next(); 3806 if(rcse.mMediaIntent.equals(mediaIntent)) { 3807 wasInsideStack = true; 3808 stackIterator.remove(); 3809 break; 3810 } 3811 } 3812 if (!wasInsideStack) { 3813 rcse = new RemoteControlStackEntry(mediaIntent, target); 3814 } 3815 mRCStack.push(rcse); 3816 3817 // post message to persist the default media button receiver 3818 mAudioHandler.sendMessage( mAudioHandler.obtainMessage( 3819 MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); 3820 } 3821 3822 /** 3823 * Helper function: 3824 * Remove the remote control receiver from the RC focus stack. 3825 * precondition: pi != null 3826 */ 3827 private void removeMediaButtonReceiver(PendingIntent pi) { 3828 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3829 while(stackIterator.hasNext()) { 3830 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 3831 if(rcse.mMediaIntent.equals(pi)) { 3832 stackIterator.remove(); 3833 rcse.unlinkToRcClientDeath(); 3834 break; 3835 } 3836 } 3837 } 3838 3839 /** 3840 * Helper function: 3841 * Called synchronized on mRCStack 3842 */ 3843 private boolean isCurrentRcController(PendingIntent pi) { 3844 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { 3845 return true; 3846 } 3847 return false; 3848 } 3849 3850 //========================================================================================== 3851 // Remote control display / client 3852 //========================================================================================== 3853 /** 3854 * Update the remote control displays with the new "focused" client generation 3855 */ 3856 private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, 3857 PendingIntent newMediaIntent, boolean clearing) { 3858 // NOTE: Only one IRemoteControlDisplay supported in this implementation 3859 if (mRcDisplay != null) { 3860 try { 3861 mRcDisplay.setCurrentClientId( 3862 newClientGeneration, newMediaIntent, clearing); 3863 } catch (RemoteException e) { 3864 Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e); 3865 // if we had a display before, stop monitoring its death 3866 rcDisplay_stopDeathMonitor_syncRcStack(); 3867 mRcDisplay = null; 3868 } 3869 } 3870 } 3871 3872 /** 3873 * Update the remote control clients with the new "focused" client generation 3874 */ 3875 private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { 3876 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3877 while(stackIterator.hasNext()) { 3878 RemoteControlStackEntry se = stackIterator.next(); 3879 if ((se != null) && (se.mRcClient != null)) { 3880 try { 3881 se.mRcClient.setCurrentClientGenerationId(newClientGeneration); 3882 } catch (RemoteException e) { 3883 Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e); 3884 stackIterator.remove(); 3885 se.unlinkToRcClientDeath(); 3886 } 3887 } 3888 } 3889 } 3890 3891 /** 3892 * Update the displays and clients with the new "focused" client generation and name 3893 * @param newClientGeneration the new generation value matching a client update 3894 * @param newClientEventReceiver the media button event receiver associated with the client. 3895 * May be null, which implies there is no registered media button event receiver. 3896 * @param clearing true if the new client generation value maps to a remote control update 3897 * where the display should be cleared. 3898 */ 3899 private void setNewRcClient_syncRcsCurrc(int newClientGeneration, 3900 PendingIntent newMediaIntent, boolean clearing) { 3901 // send the new valid client generation ID to all displays 3902 setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); 3903 // send the new valid client generation ID to all clients 3904 setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); 3905 } 3906 3907 /** 3908 * Called when processing MSG_RCDISPLAY_CLEAR event 3909 */ 3910 private void onRcDisplayClear() { 3911 if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); 3912 3913 synchronized(mRCStack) { 3914 synchronized(mCurrentRcLock) { 3915 mCurrentRcClientGen++; 3916 // synchronously update the displays and clients with the new client generation 3917 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 3918 null /*newMediaIntent*/, true /*clearing*/); 3919 } 3920 } 3921 } 3922 3923 /** 3924 * Called when processing MSG_RCDISPLAY_UPDATE event 3925 */ 3926 private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { 3927 synchronized(mRCStack) { 3928 synchronized(mCurrentRcLock) { 3929 if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { 3930 if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); 3931 3932 mCurrentRcClientGen++; 3933 // synchronously update the displays and clients with 3934 // the new client generation 3935 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 3936 rcse.mMediaIntent /*newMediaIntent*/, 3937 false /*clearing*/); 3938 3939 // tell the current client that it needs to send info 3940 try { 3941 mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, 3942 flags, mArtworkExpectedWidth, mArtworkExpectedHeight); 3943 } catch (RemoteException e) { 3944 Log.e(TAG, "Current valid remote client is dead: "+e); 3945 mCurrentRcClient = null; 3946 } 3947 } else { 3948 // the remote control display owner has changed between the 3949 // the message to update the display was sent, and the time it 3950 // gets to be processed (now) 3951 } 3952 } 3953 } 3954 } 3955 3956 3957 /** 3958 * Helper function: 3959 * Called synchronized on mRCStack 3960 */ 3961 private void clearRemoteControlDisplay_syncAfRcs() { 3962 synchronized(mCurrentRcLock) { 3963 mCurrentRcClient = null; 3964 } 3965 // will cause onRcDisplayClear() to be called in AudioService's handler thread 3966 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); 3967 } 3968 3969 /** 3970 * Helper function for code readability: only to be called from 3971 * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for 3972 * this method. 3973 * Preconditions: 3974 * - called synchronized mAudioFocusLock then on mRCStack 3975 * - mRCStack.isEmpty() is false 3976 */ 3977 private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 3978 RemoteControlStackEntry rcse = mRCStack.peek(); 3979 int infoFlagsAboutToBeUsed = infoChangedFlags; 3980 // this is where we enforce opt-in for information display on the remote controls 3981 // with the new AudioManager.registerRemoteControlClient() API 3982 if (rcse.mRcClient == null) { 3983 //Log.w(TAG, "Can't update remote control display with null remote control client"); 3984 clearRemoteControlDisplay_syncAfRcs(); 3985 return; 3986 } 3987 synchronized(mCurrentRcLock) { 3988 if (!rcse.mRcClient.equals(mCurrentRcClient)) { 3989 // new RC client, assume every type of information shall be queried 3990 infoFlagsAboutToBeUsed = RC_INFO_ALL; 3991 } 3992 mCurrentRcClient = rcse.mRcClient; 3993 } 3994 // will cause onRcDisplayUpdate() to be called in AudioService's handler thread 3995 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 3996 infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); 3997 } 3998 3999 /** 4000 * Helper function: 4001 * Called synchronized on mAudioFocusLock, then mRCStack 4002 * Check whether the remote control display should be updated, triggers the update if required 4003 * @param infoChangedFlags the flags corresponding to the remote control client information 4004 * that has changed, if applicable (checking for the update conditions might trigger a 4005 * clear, rather than an update event). 4006 */ 4007 private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 4008 // determine whether the remote control display should be refreshed 4009 // if either stack is empty, there is a mismatch, so clear the RC display 4010 if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { 4011 clearRemoteControlDisplay_syncAfRcs(); 4012 return; 4013 } 4014 // if the top of the two stacks belong to different packages, there is a mismatch, clear 4015 if ((mRCStack.peek().mCallingPackageName != null) 4016 && (mFocusStack.peek().mPackageName != null) 4017 && !(mRCStack.peek().mCallingPackageName.compareTo( 4018 mFocusStack.peek().mPackageName) == 0)) { 4019 clearRemoteControlDisplay_syncAfRcs(); 4020 return; 4021 } 4022 // if the audio focus didn't originate from the same Uid as the one in which the remote 4023 // control information will be retrieved, clear 4024 if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { 4025 clearRemoteControlDisplay_syncAfRcs(); 4026 return; 4027 } 4028 // refresh conditions were verified: update the remote controls 4029 // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty 4030 updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); 4031 } 4032 4033 /** 4034 * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) 4035 * precondition: mediaIntent != null, target != null 4036 */ 4037 public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { 4038 Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); 4039 4040 synchronized(mAudioFocusLock) { 4041 synchronized(mRCStack) { 4042 pushMediaButtonReceiver(mediaIntent, eventReceiver); 4043 // new RC client, assume every type of information shall be queried 4044 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4045 } 4046 } 4047 } 4048 4049 /** 4050 * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) 4051 * precondition: mediaIntent != null, eventReceiver != null 4052 */ 4053 public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) 4054 { 4055 Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); 4056 4057 synchronized(mAudioFocusLock) { 4058 synchronized(mRCStack) { 4059 boolean topOfStackWillChange = isCurrentRcController(mediaIntent); 4060 removeMediaButtonReceiver(mediaIntent); 4061 if (topOfStackWillChange) { 4062 // current RC client will change, assume every type of info needs to be queried 4063 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4064 } 4065 } 4066 } 4067 } 4068 4069 /** 4070 * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) 4071 * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient 4072 * without modifying the RC stack, but while still causing the display to refresh (will 4073 * become blank as a result of this) 4074 */ 4075 public void registerRemoteControlClient(PendingIntent mediaIntent, 4076 IRemoteControlClient rcClient, String callingPackageName) { 4077 if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); 4078 synchronized(mAudioFocusLock) { 4079 synchronized(mRCStack) { 4080 // store the new display information 4081 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4082 while(stackIterator.hasNext()) { 4083 RemoteControlStackEntry rcse = stackIterator.next(); 4084 if(rcse.mMediaIntent.equals(mediaIntent)) { 4085 // already had a remote control client? 4086 if (rcse.mRcClientDeathHandler != null) { 4087 // stop monitoring the old client's death 4088 rcse.unlinkToRcClientDeath(); 4089 } 4090 // save the new remote control client 4091 rcse.mRcClient = rcClient; 4092 rcse.mCallingPackageName = callingPackageName; 4093 rcse.mCallingUid = Binder.getCallingUid(); 4094 if (rcClient == null) { 4095 // here rcse.mRcClientDeathHandler is null; 4096 break; 4097 } 4098 4099 // there is a new (non-null) client: 4100 // 1/ give the new client the current display (if any) 4101 if (mRcDisplay != null) { 4102 try { 4103 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4104 } catch (RemoteException e) { 4105 Log.e(TAG, "Error connecting remote control display to client: "+e); 4106 e.printStackTrace(); 4107 } 4108 } 4109 // 2/ monitor the new client's death 4110 IBinder b = rcse.mRcClient.asBinder(); 4111 RcClientDeathHandler rcdh = 4112 new RcClientDeathHandler(b, rcse.mMediaIntent); 4113 try { 4114 b.linkToDeath(rcdh, 0); 4115 } catch (RemoteException e) { 4116 // remote control client is DOA, disqualify it 4117 Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); 4118 rcse.mRcClient = null; 4119 } 4120 rcse.mRcClientDeathHandler = rcdh; 4121 break; 4122 } 4123 } 4124 // if the eventReceiver is at the top of the stack 4125 // then check for potential refresh of the remote controls 4126 if (isCurrentRcController(mediaIntent)) { 4127 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4128 } 4129 } 4130 } 4131 } 4132 4133 /** 4134 * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) 4135 * rcClient is guaranteed non-null 4136 */ 4137 public void unregisterRemoteControlClient(PendingIntent mediaIntent, 4138 IRemoteControlClient rcClient) { 4139 synchronized(mAudioFocusLock) { 4140 synchronized(mRCStack) { 4141 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4142 while(stackIterator.hasNext()) { 4143 RemoteControlStackEntry rcse = stackIterator.next(); 4144 if ((rcse.mMediaIntent.equals(mediaIntent)) 4145 && rcClient.equals(rcse.mRcClient)) { 4146 // we found the IRemoteControlClient to unregister 4147 // stop monitoring its death 4148 rcse.unlinkToRcClientDeath(); 4149 // reset the client-related fields 4150 rcse.mRcClient = null; 4151 rcse.mCallingPackageName = null; 4152 } 4153 } 4154 } 4155 } 4156 } 4157 4158 /** 4159 * The remote control displays. 4160 * Access synchronized on mRCStack 4161 * NOTE: Only one IRemoteControlDisplay supported in this implementation 4162 */ 4163 private IRemoteControlDisplay mRcDisplay; 4164 private RcDisplayDeathHandler mRcDisplayDeathHandler; 4165 private int mArtworkExpectedWidth = -1; 4166 private int mArtworkExpectedHeight = -1; 4167 /** 4168 * Inner class to monitor remote control display deaths, and unregister them from the list 4169 * of displays if necessary. 4170 */ 4171 private class RcDisplayDeathHandler implements IBinder.DeathRecipient { 4172 private IBinder mCb; // To be notified of client's death 4173 4174 public RcDisplayDeathHandler(IBinder b) { 4175 if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b); 4176 mCb = b; 4177 } 4178 4179 public void binderDied() { 4180 synchronized(mRCStack) { 4181 Log.w(TAG, "RemoteControl: display died"); 4182 mRcDisplay = null; 4183 } 4184 } 4185 4186 public void unlinkToRcDisplayDeath() { 4187 if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb); 4188 try { 4189 mCb.unlinkToDeath(this, 0); 4190 } catch (java.util.NoSuchElementException e) { 4191 // not much we can do here, the display was being unregistered anyway 4192 Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()"); 4193 e.printStackTrace(); 4194 } 4195 } 4196 4197 } 4198 4199 private void rcDisplay_stopDeathMonitor_syncRcStack() { 4200 if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null) 4201 // we had a display before, stop monitoring its death 4202 mRcDisplayDeathHandler.unlinkToRcDisplayDeath(); 4203 } 4204 } 4205 4206 private void rcDisplay_startDeathMonitor_syncRcStack() { 4207 if (mRcDisplay != null) { 4208 // new non-null display, monitor its death 4209 IBinder b = mRcDisplay.asBinder(); 4210 mRcDisplayDeathHandler = new RcDisplayDeathHandler(b); 4211 try { 4212 b.linkToDeath(mRcDisplayDeathHandler, 0); 4213 } catch (RemoteException e) { 4214 // remote control display is DOA, disqualify it 4215 Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b); 4216 mRcDisplay = null; 4217 } 4218 } 4219 } 4220 4221 /** 4222 * Register an IRemoteControlDisplay. 4223 * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient 4224 * at the top of the stack to update the new display with its information. 4225 * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. 4226 * @param rcd the IRemoteControlDisplay to register. No effect if null. 4227 */ 4228 public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { 4229 if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); 4230 synchronized(mAudioFocusLock) { 4231 synchronized(mRCStack) { 4232 if ((mRcDisplay == rcd) || (rcd == null)) { 4233 return; 4234 } 4235 // if we had a display before, stop monitoring its death 4236 rcDisplay_stopDeathMonitor_syncRcStack(); 4237 mRcDisplay = rcd; 4238 // new display, start monitoring its death 4239 rcDisplay_startDeathMonitor_syncRcStack(); 4240 4241 // let all the remote control clients there is a new display 4242 // no need to unplug the previous because we only support one display 4243 // and the clients don't track the death of the display 4244 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4245 while(stackIterator.hasNext()) { 4246 RemoteControlStackEntry rcse = stackIterator.next(); 4247 if(rcse.mRcClient != null) { 4248 try { 4249 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4250 } catch (RemoteException e) { 4251 Log.e(TAG, "Error connecting remote control display to client: " + e); 4252 e.printStackTrace(); 4253 } 4254 } 4255 } 4256 4257 // we have a new display, of which all the clients are now aware: have it be updated 4258 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4259 } 4260 } 4261 } 4262 4263 /** 4264 * Unregister an IRemoteControlDisplay. 4265 * Since only one IRemoteControlDisplay is supported, this has no effect if the one to 4266 * unregister is not the current one. 4267 * @param rcd the IRemoteControlDisplay to unregister. No effect if null. 4268 */ 4269 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 4270 if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); 4271 synchronized(mRCStack) { 4272 // only one display here, so you can only unregister the current display 4273 if ((rcd == null) || (rcd != mRcDisplay)) { 4274 if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); 4275 return; 4276 } 4277 // if we had a display before, stop monitoring its death 4278 rcDisplay_stopDeathMonitor_syncRcStack(); 4279 mRcDisplay = null; 4280 4281 // disconnect this remote control display from all the clients 4282 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4283 while(stackIterator.hasNext()) { 4284 RemoteControlStackEntry rcse = stackIterator.next(); 4285 if(rcse.mRcClient != null) { 4286 try { 4287 rcse.mRcClient.unplugRemoteControlDisplay(rcd); 4288 } catch (RemoteException e) { 4289 Log.e(TAG, "Error disconnecting remote control display to client: " + e); 4290 e.printStackTrace(); 4291 } 4292 } 4293 } 4294 } 4295 } 4296 4297 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 4298 synchronized(mRCStack) { 4299 // NOTE: Only one IRemoteControlDisplay supported in this implementation 4300 mArtworkExpectedWidth = w; 4301 mArtworkExpectedHeight = h; 4302 } 4303 } 4304 4305 //========================================================================================== 4306 // Device orientation 4307 //========================================================================================== 4308 /** 4309 * Handles device configuration changes that may map to a change in the orientation. 4310 * This feature is optional, and is defined by the definition and value of the 4311 * "ro.audio.monitorOrientation" system property. 4312 */ 4313 private void handleConfigurationChanged(Context context) { 4314 try { 4315 // reading new orientation "safely" (i.e. under try catch) in case anything 4316 // goes wrong when obtaining resources and configuration 4317 int newOrientation = context.getResources().getConfiguration().orientation; 4318 if (newOrientation != mDeviceOrientation) { 4319 mDeviceOrientation = newOrientation; 4320 setOrientationForAudioSystem(); 4321 } 4322 } catch (Exception e) { 4323 Log.e(TAG, "Error retrieving device orientation: " + e); 4324 } 4325 } 4326 4327 private void setOrientationForAudioSystem() { 4328 switch (mDeviceOrientation) { 4329 case Configuration.ORIENTATION_LANDSCAPE: 4330 //Log.i(TAG, "orientation is landscape"); 4331 AudioSystem.setParameters("orientation=landscape"); 4332 break; 4333 case Configuration.ORIENTATION_PORTRAIT: 4334 //Log.i(TAG, "orientation is portrait"); 4335 AudioSystem.setParameters("orientation=portrait"); 4336 break; 4337 case Configuration.ORIENTATION_SQUARE: 4338 //Log.i(TAG, "orientation is square"); 4339 AudioSystem.setParameters("orientation=square"); 4340 break; 4341 case Configuration.ORIENTATION_UNDEFINED: 4342 //Log.i(TAG, "orientation is undefined"); 4343 AudioSystem.setParameters("orientation=undefined"); 4344 break; 4345 default: 4346 Log.e(TAG, "Unknown orientation"); 4347 } 4348 } 4349 4350 4351 @Override 4352 public void setRingtonePlayer(IRingtonePlayer player) { 4353 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 4354 mRingtonePlayer = player; 4355 } 4356 4357 @Override 4358 public IRingtonePlayer getRingtonePlayer() { 4359 return mRingtonePlayer; 4360 } 4361 4362 @Override 4363 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4364 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 4365 4366 // TODO probably a lot more to do here than just the audio focus and remote control stacks 4367 dumpFocusStack(pw); 4368 dumpRCStack(pw); 4369 } 4370} 4371