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