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