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