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