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