AudioService.java revision 527c3ab51e258dfa15c6240f701693cf914e8e93
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19import android.app.ActivityManagerNative; 20import android.content.BroadcastReceiver; 21import android.content.ComponentName; 22import android.content.ContentResolver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.bluetooth.BluetoothA2dp; 27import android.bluetooth.BluetoothClass; 28import android.bluetooth.BluetoothDevice; 29import android.bluetooth.BluetoothHeadset; 30import android.content.pm.PackageManager; 31import android.database.ContentObserver; 32import android.media.MediaPlayer.OnCompletionListener; 33import android.media.MediaPlayer.OnErrorListener; 34import android.os.Binder; 35import android.os.Environment; 36import android.os.Handler; 37import android.os.IBinder; 38import android.os.Looper; 39import android.os.Message; 40import android.os.RemoteException; 41import android.os.ServiceManager; 42import android.provider.Settings; 43import android.provider.Settings.System; 44import android.util.Log; 45import android.view.KeyEvent; 46import android.view.VolumePanel; 47import android.os.SystemProperties; 48 49import com.android.internal.telephony.ITelephony; 50 51import java.io.FileDescriptor; 52import java.io.IOException; 53import java.io.PrintWriter; 54import java.util.ArrayList; 55import java.util.HashMap; 56import java.util.Iterator; 57import java.util.Map; 58import java.util.Set; 59import java.util.Stack; 60 61/** 62 * The implementation of the volume manager service. 63 * <p> 64 * This implementation focuses on delivering a responsive UI. Most methods are 65 * asynchronous to external calls. For example, the task of setting a volume 66 * will update our internal state, but in a separate thread will set the system 67 * volume and later persist to the database. Similarly, setting the ringer mode 68 * will update the state and broadcast a change and in a separate thread later 69 * persist the ringer mode. 70 * 71 * @hide 72 */ 73public class AudioService extends IAudioService.Stub { 74 75 private static final String TAG = "AudioService"; 76 77 /** How long to delay before persisting a change in volume/ringer mode. */ 78 private static final int PERSIST_DELAY = 3000; 79 80 private Context mContext; 81 private ContentResolver mContentResolver; 82 83 84 /** The UI */ 85 private VolumePanel mVolumePanel; 86 87 // sendMsg() flags 88 /** Used when a message should be shared across all stream types. */ 89 private static final int SHARED_MSG = -1; 90 /** If the msg is already queued, replace it with this one. */ 91 private static final int SENDMSG_REPLACE = 0; 92 /** If the msg is already queued, ignore this one and leave the old. */ 93 private static final int SENDMSG_NOOP = 1; 94 /** If the msg is already queued, queue this one and leave the old. */ 95 private static final int SENDMSG_QUEUE = 2; 96 97 // AudioHandler message.whats 98 private static final int MSG_SET_SYSTEM_VOLUME = 0; 99 private static final int MSG_PERSIST_VOLUME = 1; 100 private static final int MSG_PERSIST_RINGER_MODE = 3; 101 private static final int MSG_PERSIST_VIBRATE_SETTING = 4; 102 private static final int MSG_MEDIA_SERVER_DIED = 5; 103 private static final int MSG_MEDIA_SERVER_STARTED = 6; 104 private static final int MSG_PLAY_SOUND_EFFECT = 7; 105 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8; 106 107 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 108 109 /** @see AudioSystemThread */ 110 private AudioSystemThread mAudioSystemThread; 111 /** @see AudioHandler */ 112 private AudioHandler mAudioHandler; 113 /** @see VolumeStreamState */ 114 private VolumeStreamState[] mStreamStates; 115 private SettingsObserver mSettingsObserver; 116 117 private int mMode; 118 private Object mSettingsLock = new Object(); 119 private boolean mMediaServerOk; 120 121 private SoundPool mSoundPool; 122 private Object mSoundEffectsLock = new Object(); 123 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 124 private static final int SOUND_EFFECT_VOLUME = 1000; 125 126 /* Sound effect file names */ 127 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 128 private static final String[] SOUND_EFFECT_FILES = new String[] { 129 "Effect_Tick.ogg", 130 "KeypressStandard.ogg", 131 "KeypressSpacebar.ogg", 132 "KeypressDelete.ogg", 133 "KeypressReturn.ogg" 134 }; 135 136 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 137 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 138 * uses soundpool (second column) */ 139 private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 140 {0, -1}, // FX_KEY_CLICK 141 {0, -1}, // FX_FOCUS_NAVIGATION_UP 142 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 143 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 144 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 145 {1, -1}, // FX_KEYPRESS_STANDARD 146 {2, -1}, // FX_KEYPRESS_SPACEBAR 147 {3, -1}, // FX_FOCUS_DELETE 148 {4, -1} // FX_FOCUS_RETURN 149 }; 150 151 /** @hide Maximum volume index values for audio streams */ 152 private int[] MAX_STREAM_VOLUME = new int[] { 153 5, // STREAM_VOICE_CALL 154 7, // STREAM_SYSTEM 155 7, // STREAM_RING 156 15, // STREAM_MUSIC 157 7, // STREAM_ALARM 158 7, // STREAM_NOTIFICATION 159 15, // STREAM_BLUETOOTH_SCO 160 7, // STREAM_SYSTEM_ENFORCED 161 15, // STREAM_DTMF 162 15 // STREAM_TTS 163 }; 164 /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings 165 * of another stream: This avoids multiplying the volume settings for hidden 166 * stream types that follow other stream behavior for volume settings 167 * NOTE: do not create loops in aliases! */ 168 private int[] STREAM_VOLUME_ALIAS = new int[] { 169 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 170 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM 171 AudioSystem.STREAM_RING, // STREAM_RING 172 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 173 AudioSystem.STREAM_ALARM, // STREAM_ALARM 174 AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION 175 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 176 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED 177 AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF 178 AudioSystem.STREAM_MUSIC // STREAM_TTS 179 }; 180 181 private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 182 public void onError(int error) { 183 switch (error) { 184 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 185 if (mMediaServerOk) { 186 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 187 null, 1500); 188 mMediaServerOk = false; 189 } 190 break; 191 case AudioSystem.AUDIO_STATUS_OK: 192 if (!mMediaServerOk) { 193 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 194 null, 0); 195 mMediaServerOk = true; 196 } 197 break; 198 default: 199 break; 200 } 201 } 202 }; 203 204 /** 205 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 206 * {@link AudioManager#RINGER_MODE_SILENT}, or 207 * {@link AudioManager#RINGER_MODE_VIBRATE}. 208 */ 209 private int mRingerMode; 210 211 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 212 private int mRingerModeAffectedStreams; 213 214 // Streams currently muted by ringer mode 215 private int mRingerModeMutedStreams; 216 217 /** @see System#MUTE_STREAMS_AFFECTED */ 218 private int mMuteAffectedStreams; 219 220 /** 221 * Has multiple bits per vibrate type to indicate the type's vibrate 222 * setting. See {@link #setVibrateSetting(int, int)}. 223 * <p> 224 * NOTE: This is not the final decision of whether vibrate is on/off for the 225 * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. 226 */ 227 private int mVibrateSetting; 228 229 /** @see System#NOTIFICATIONS_USE_RING_VOLUME */ 230 private int mNotificationsUseRingVolume; 231 232 // Broadcast receiver for device connections intent broadcasts 233 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 234 235 // Broadcast receiver for media button broadcasts (separate from mReceiver to 236 // independently change its priority) 237 private final BroadcastReceiver mMediaButtonReceiver = new MediaButtonBroadcastReceiver(); 238 239 // Devices currently connected 240 private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 241 242 // Forced device usage for communications 243 private int mForcedUseForComm; 244 245 // List of binder death handlers for setMode() client processes. 246 // The last process to have called setMode() is at the top of the list. 247 private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 248 249 // List of clients having issued a SCO start request 250 private ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 251 252 // BluetoothHeadset API to control SCO connection 253 private BluetoothHeadset mBluetoothHeadset; 254 255 // Bluetooth headset connection state 256 private boolean mBluetoothHeadsetConnected; 257 258 /////////////////////////////////////////////////////////////////////////// 259 // Construction 260 /////////////////////////////////////////////////////////////////////////// 261 262 /** @hide */ 263 public AudioService(Context context) { 264 mContext = context; 265 mContentResolver = context.getContentResolver(); 266 267 // Intialized volume 268 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 269 "ro.config.vc_call_vol_steps", 270 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 271 272 mVolumePanel = new VolumePanel(context, this); 273 mSettingsObserver = new SettingsObserver(); 274 mForcedUseForComm = AudioSystem.FORCE_NONE; 275 createAudioSystemThread(); 276 readPersistedSettings(); 277 createStreamStates(); 278 // Call setMode() to initialize mSetModeDeathHandlers 279 mMode = AudioSystem.MODE_INVALID; 280 setMode(AudioSystem.MODE_NORMAL, null); 281 mMediaServerOk = true; 282 AudioSystem.setErrorCallback(mAudioSystemCallback); 283 loadSoundEffects(); 284 285 mBluetoothHeadsetConnected = false; 286 mBluetoothHeadset = new BluetoothHeadset(context, 287 mBluetoothHeadsetServiceListener); 288 289 // Register for device connection intent broadcasts. 290 IntentFilter intentFilter = 291 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 292 intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); 293 intentFilter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED); 294 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 295 intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 296 context.registerReceiver(mReceiver, intentFilter); 297 298 // Register for media button intent broadcasts. 299 intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON); 300 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 301 context.registerReceiver(mMediaButtonReceiver, intentFilter); 302 } 303 304 private void createAudioSystemThread() { 305 mAudioSystemThread = new AudioSystemThread(); 306 mAudioSystemThread.start(); 307 waitForAudioHandlerCreation(); 308 } 309 310 /** Waits for the volume handler to be created by the other thread. */ 311 private void waitForAudioHandlerCreation() { 312 synchronized(this) { 313 while (mAudioHandler == null) { 314 try { 315 // Wait for mAudioHandler to be set by the other thread 316 wait(); 317 } catch (InterruptedException e) { 318 Log.e(TAG, "Interrupted while waiting on volume handler."); 319 } 320 } 321 } 322 } 323 324 private void createStreamStates() { 325 int numStreamTypes = AudioSystem.getNumStreamTypes(); 326 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 327 328 for (int i = 0; i < numStreamTypes; i++) { 329 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i); 330 } 331 332 // Correct stream index values for streams with aliases 333 for (int i = 0; i < numStreamTypes; i++) { 334 if (STREAM_VOLUME_ALIAS[i] != i) { 335 int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i); 336 streams[i].mIndex = streams[i].getValidIndex(index); 337 setStreamVolumeIndex(i, index); 338 index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i); 339 streams[i].mLastAudibleIndex = streams[i].getValidIndex(index); 340 } 341 } 342 } 343 344 private void readPersistedSettings() { 345 final ContentResolver cr = mContentResolver; 346 347 mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 348 349 mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); 350 351 mRingerModeAffectedStreams = Settings.System.getInt(cr, 352 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 353 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 354 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 355 356 mMuteAffectedStreams = System.getInt(cr, 357 System.MUTE_STREAMS_AFFECTED, 358 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 359 360 mNotificationsUseRingVolume = System.getInt(cr, 361 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1); 362 363 if (mNotificationsUseRingVolume == 1) { 364 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 365 } 366 // Each stream will read its own persisted settings 367 368 // Broadcast the sticky intent 369 broadcastRingerMode(); 370 371 // Broadcast vibrate settings 372 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 373 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 374 } 375 376 private void setStreamVolumeIndex(int stream, int index) { 377 AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10); 378 } 379 380 private int rescaleIndex(int index, int srcStream, int dstStream) { 381 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 382 } 383 384 /////////////////////////////////////////////////////////////////////////// 385 // IPC methods 386 /////////////////////////////////////////////////////////////////////////// 387 388 /** @see AudioManager#adjustVolume(int, int) */ 389 public void adjustVolume(int direction, int flags) { 390 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 391 } 392 393 /** @see AudioManager#adjustVolume(int, int, int) */ 394 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 395 396 int streamType = getActiveStreamType(suggestedStreamType); 397 398 // Don't play sound on other streams 399 if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { 400 flags &= ~AudioManager.FLAG_PLAY_SOUND; 401 } 402 403 adjustStreamVolume(streamType, direction, flags); 404 } 405 406 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 407 public void adjustStreamVolume(int streamType, int direction, int flags) { 408 ensureValidDirection(direction); 409 ensureValidStreamType(streamType); 410 411 412 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 413 final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 414 boolean adjustVolume = true; 415 416 // If either the client forces allowing ringer modes for this adjustment, 417 // or the stream type is one that is affected by ringer modes 418 if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 419 || streamType == AudioSystem.STREAM_RING) { 420 // Check if the ringer mode changes with this volume adjustment. If 421 // it does, it will handle adjusting the volume, so we won't below 422 adjustVolume = checkForRingerModeChange(oldIndex, direction); 423 } 424 425 // If stream is muted, adjust last audible index only 426 int index; 427 if (streamState.muteCount() != 0) { 428 if (adjustVolume) { 429 streamState.adjustLastAudibleIndex(direction); 430 // Post a persist volume msg 431 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 432 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 433 } 434 index = streamState.mLastAudibleIndex; 435 } else { 436 if (adjustVolume && streamState.adjustIndex(direction)) { 437 // Post message to set system volume (it in turn will post a message 438 // to persist). Do not change volume if stream is muted. 439 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0, 440 streamState, 0); 441 } 442 index = streamState.mIndex; 443 } 444 // UI 445 mVolumePanel.postVolumeChanged(streamType, flags); 446 // Broadcast Intent 447 sendVolumeUpdate(streamType, oldIndex, index); 448 } 449 450 /** @see AudioManager#setStreamVolume(int, int, int) */ 451 public void setStreamVolume(int streamType, int index, int flags) { 452 ensureValidStreamType(streamType); 453 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 454 455 final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 456 457 index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); 458 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); 459 460 index = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; 461 462 // UI, etc. 463 mVolumePanel.postVolumeChanged(streamType, flags); 464 // Broadcast Intent 465 sendVolumeUpdate(streamType, oldIndex, index); 466 } 467 468 private void sendVolumeUpdate(int streamType, int oldIndex, int index) { 469 oldIndex = (oldIndex + 5) / 10; 470 index = (index + 5) / 10; 471 472 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 473 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 474 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 475 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 476 477 mContext.sendBroadcast(intent); 478 } 479 480 /** 481 * Sets the stream state's index, and posts a message to set system volume. 482 * This will not call out to the UI. Assumes a valid stream type. 483 * 484 * @param streamType Type of the stream 485 * @param index Desired volume index of the stream 486 * @param force If true, set the volume even if the desired volume is same 487 * as the current volume. 488 * @param lastAudible If true, stores new index as last audible one 489 */ 490 private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) { 491 VolumeStreamState streamState = mStreamStates[streamType]; 492 493 // If stream is muted, set last audible index only 494 if (streamState.muteCount() != 0) { 495 streamState.setLastAudibleIndex(index); 496 // Post a persist volume msg 497 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 498 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 499 } else { 500 if (streamState.setIndex(index, lastAudible) || force) { 501 // Post message to set system volume (it in turn will post a message 502 // to persist). 503 // If we are in silent mode and stream is affected by ringer mode 504 // and the new volume is not 0, just persist the new volume but do not change 505 // current value 506 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL || 507 !isStreamAffectedByRingerMode(streamType) || 508 index == 0) { 509 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, 510 streamState, 0); 511 } else { 512 // Post a persist volume msg 513 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 514 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 515 } 516 } 517 } 518 } 519 520 /** @see AudioManager#setStreamSolo(int, boolean) */ 521 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 522 for (int stream = 0; stream < mStreamStates.length; stream++) { 523 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 524 // Bring back last audible volume 525 mStreamStates[stream].mute(cb, state); 526 } 527 } 528 529 /** @see AudioManager#setStreamMute(int, boolean) */ 530 public void setStreamMute(int streamType, boolean state, IBinder cb) { 531 if (isStreamAffectedByMute(streamType)) { 532 mStreamStates[streamType].mute(cb, state); 533 } 534 } 535 536 /** @see AudioManager#getStreamVolume(int) */ 537 public int getStreamVolume(int streamType) { 538 ensureValidStreamType(streamType); 539 return (mStreamStates[streamType].mIndex + 5) / 10; 540 } 541 542 /** @see AudioManager#getStreamMaxVolume(int) */ 543 public int getStreamMaxVolume(int streamType) { 544 ensureValidStreamType(streamType); 545 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 546 } 547 548 /** @see AudioManager#getRingerMode() */ 549 public int getRingerMode() { 550 return mRingerMode; 551 } 552 553 /** @see AudioManager#setRingerMode(int) */ 554 public void setRingerMode(int ringerMode) { 555 synchronized (mSettingsLock) { 556 if (ringerMode != mRingerMode) { 557 setRingerModeInt(ringerMode, true); 558 // Send sticky broadcast 559 broadcastRingerMode(); 560 } 561 } 562 } 563 564 private void setRingerModeInt(int ringerMode, boolean persist) { 565 mRingerMode = ringerMode; 566 567 // Mute stream if not previously muted by ringer mode and ringer mode 568 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 569 // Unmute stream if previously muted by ringer mode and ringer mode 570 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 571 int numStreamTypes = AudioSystem.getNumStreamTypes(); 572 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 573 if (isStreamMutedByRingerMode(streamType)) { 574 if (!isStreamAffectedByRingerMode(streamType) || 575 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 576 mStreamStates[streamType].mute(null, false); 577 mRingerModeMutedStreams &= ~(1 << streamType); 578 } 579 } else { 580 if (isStreamAffectedByRingerMode(streamType) && 581 mRingerMode != AudioManager.RINGER_MODE_NORMAL) { 582 mStreamStates[streamType].mute(null, true); 583 mRingerModeMutedStreams |= (1 << streamType); 584 } 585 } 586 } 587 588 // Post a persist ringer mode msg 589 if (persist) { 590 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, 591 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 592 } 593 } 594 595 /** @see AudioManager#shouldVibrate(int) */ 596 public boolean shouldVibrate(int vibrateType) { 597 598 switch (getVibrateSetting(vibrateType)) { 599 600 case AudioManager.VIBRATE_SETTING_ON: 601 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 602 603 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 604 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 605 606 case AudioManager.VIBRATE_SETTING_OFF: 607 // return false, even for incoming calls 608 return false; 609 610 default: 611 return false; 612 } 613 } 614 615 /** @see AudioManager#getVibrateSetting(int) */ 616 public int getVibrateSetting(int vibrateType) { 617 return (mVibrateSetting >> (vibrateType * 2)) & 3; 618 } 619 620 /** @see AudioManager#setVibrateSetting(int, int) */ 621 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 622 623 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 624 625 // Broadcast change 626 broadcastVibrateSetting(vibrateType); 627 628 // Post message to set ringer mode (it in turn will post a message 629 // to persist) 630 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, 631 null, 0); 632 } 633 634 /** 635 * @see #setVibrateSetting(int, int) 636 */ 637 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 638 int vibrateSetting) { 639 640 // First clear the existing setting. Each vibrate type has two bits in 641 // the value. Note '3' is '11' in binary. 642 existingValue &= ~(3 << (vibrateType * 2)); 643 644 // Set into the old value 645 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 646 647 return existingValue; 648 } 649 650 private class SetModeDeathHandler implements IBinder.DeathRecipient { 651 private IBinder mCb; // To be notified of client's death 652 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 653 654 SetModeDeathHandler(IBinder cb) { 655 mCb = cb; 656 } 657 658 public void binderDied() { 659 synchronized(mSetModeDeathHandlers) { 660 Log.w(TAG, "setMode() client died"); 661 int index = mSetModeDeathHandlers.indexOf(this); 662 if (index < 0) { 663 Log.w(TAG, "unregistered setMode() client died"); 664 } else { 665 mSetModeDeathHandlers.remove(this); 666 // If dead client was a the top of client list, 667 // apply next mode in the stack 668 if (index == 0) { 669 // mSetModeDeathHandlers is never empty as the initial entry 670 // created when AudioService starts is never removed 671 SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0); 672 int mode = hdlr.getMode(); 673 if (AudioService.this.mMode != mode) { 674 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 675 AudioService.this.mMode = mode; 676 } 677 } 678 } 679 } 680 } 681 } 682 683 public void setMode(int mode) { 684 mMode = mode; 685 } 686 687 public int getMode() { 688 return mMode; 689 } 690 691 public IBinder getBinder() { 692 return mCb; 693 } 694 } 695 696 /** @see AudioManager#setMode(int) */ 697 public void setMode(int mode, IBinder cb) { 698 if (!checkAudioSettingsPermission("setMode()")) { 699 return; 700 } 701 702 if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) { 703 return; 704 } 705 706 synchronized (mSettingsLock) { 707 if (mode == AudioSystem.MODE_CURRENT) { 708 mode = mMode; 709 } 710 if (mode != mMode) { 711 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 712 checkForUndispatchedAudioFocusChange(mMode, mode); 713 mMode = mode; 714 715 synchronized(mSetModeDeathHandlers) { 716 SetModeDeathHandler hdlr = null; 717 Iterator iter = mSetModeDeathHandlers.iterator(); 718 while (iter.hasNext()) { 719 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 720 if (h.getBinder() == cb) { 721 hdlr = h; 722 // Remove from client list so that it is re-inserted at top of list 723 iter.remove(); 724 break; 725 } 726 } 727 if (hdlr == null) { 728 hdlr = new SetModeDeathHandler(cb); 729 // cb is null when setMode() is called by AudioService constructor 730 if (cb != null) { 731 // Register for client death notification 732 try { 733 cb.linkToDeath(hdlr, 0); 734 } catch (RemoteException e) { 735 // Client has died! 736 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 737 } 738 } 739 } 740 // Last client to call setMode() is always at top of client list 741 // as required by SetModeDeathHandler.binderDied() 742 mSetModeDeathHandlers.add(0, hdlr); 743 hdlr.setMode(mode); 744 } 745 746 if (mode != AudioSystem.MODE_NORMAL) { 747 clearAllScoClients(); 748 } 749 } 750 } 751 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 752 int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; 753 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false); 754 } 755 } 756 757 /** @see AudioManager#getMode() */ 758 public int getMode() { 759 return mMode; 760 } 761 762 /** @see AudioManager#playSoundEffect(int) */ 763 public void playSoundEffect(int effectType) { 764 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 765 effectType, -1, null, 0); 766 } 767 768 /** @see AudioManager#playSoundEffect(int, float) */ 769 public void playSoundEffectVolume(int effectType, float volume) { 770 loadSoundEffects(); 771 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 772 effectType, (int) (volume * 1000), null, 0); 773 } 774 775 /** 776 * Loads samples into the soundpool. 777 * This method must be called at when sound effects are enabled 778 */ 779 public boolean loadSoundEffects() { 780 synchronized (mSoundEffectsLock) { 781 if (mSoundPool != null) { 782 return true; 783 } 784 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 785 if (mSoundPool == null) { 786 return false; 787 } 788 /* 789 * poolId table: The value -1 in this table indicates that corresponding 790 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 791 * Once loaded, the value in poolId is the sample ID and the same 792 * sample can be reused for another effect using the same file. 793 */ 794 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 795 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 796 poolId[fileIdx] = -1; 797 } 798 /* 799 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 800 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 801 * this indicates we have a valid sample loaded for this effect. 802 */ 803 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 804 // Do not load sample if this effect uses the MediaPlayer 805 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 806 continue; 807 } 808 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 809 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 810 int sampleId = mSoundPool.load(filePath, 0); 811 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 812 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 813 if (sampleId <= 0) { 814 Log.w(TAG, "Soundpool could not load file: "+filePath); 815 } 816 } else { 817 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 818 } 819 } 820 } 821 822 return true; 823 } 824 825 /** 826 * Unloads samples from the sound pool. 827 * This method can be called to free some memory when 828 * sound effects are disabled. 829 */ 830 public void unloadSoundEffects() { 831 synchronized (mSoundEffectsLock) { 832 if (mSoundPool == null) { 833 return; 834 } 835 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 836 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 837 poolId[fileIdx] = 0; 838 } 839 840 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 841 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 842 continue; 843 } 844 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 845 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 846 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 847 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 848 } 849 } 850 mSoundPool = null; 851 } 852 } 853 854 /** @see AudioManager#reloadAudioSettings() */ 855 public void reloadAudioSettings() { 856 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 857 readPersistedSettings(); 858 859 // restore volume settings 860 int numStreamTypes = AudioSystem.getNumStreamTypes(); 861 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 862 VolumeStreamState streamState = mStreamStates[streamType]; 863 864 String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; 865 String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 866 int index = Settings.System.getInt(mContentResolver, 867 settingName, 868 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 869 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 870 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 871 } else { 872 index *= 10; 873 } 874 streamState.mIndex = streamState.getValidIndex(index); 875 876 index = (index + 5) / 10; 877 index = Settings.System.getInt(mContentResolver, 878 lastAudibleSettingName, 879 (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 880 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 881 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 882 } else { 883 index *= 10; 884 } 885 streamState.mLastAudibleIndex = streamState.getValidIndex(index); 886 887 // unmute stream that was muted but is not affect by mute anymore 888 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 889 int size = streamState.mDeathHandlers.size(); 890 for (int i = 0; i < size; i++) { 891 streamState.mDeathHandlers.get(i).mMuteCount = 1; 892 streamState.mDeathHandlers.get(i).mute(false); 893 } 894 } 895 // apply stream volume 896 if (streamState.muteCount() == 0) { 897 setStreamVolumeIndex(streamType, streamState.mIndex); 898 } 899 } 900 901 // apply new ringer mode 902 setRingerModeInt(getRingerMode(), false); 903 } 904 905 /** @see AudioManager#setSpeakerphoneOn() */ 906 public void setSpeakerphoneOn(boolean on){ 907 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 908 return; 909 } 910 if (on) { 911 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER); 912 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 913 } else { 914 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 915 mForcedUseForComm = AudioSystem.FORCE_NONE; 916 } 917 } 918 919 /** @see AudioManager#isSpeakerphoneOn() */ 920 public boolean isSpeakerphoneOn() { 921 if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 922 return true; 923 } else { 924 return false; 925 } 926 } 927 928 /** @see AudioManager#setBluetoothScoOn() */ 929 public void setBluetoothScoOn(boolean on){ 930 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 931 return; 932 } 933 if (on) { 934 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO); 935 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO); 936 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 937 } else { 938 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 939 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE); 940 mForcedUseForComm = AudioSystem.FORCE_NONE; 941 } 942 } 943 944 /** @see AudioManager#isBluetoothScoOn() */ 945 public boolean isBluetoothScoOn() { 946 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 947 return true; 948 } else { 949 return false; 950 } 951 } 952 953 /** @see AudioManager#startBluetoothSco() */ 954 public void startBluetoothSco(IBinder cb){ 955 if (!checkAudioSettingsPermission("startBluetoothSco()")) { 956 return; 957 } 958 ScoClient client = getScoClient(cb); 959 client.incCount(); 960 } 961 962 /** @see AudioManager#stopBluetoothSco() */ 963 public void stopBluetoothSco(IBinder cb){ 964 if (!checkAudioSettingsPermission("stopBluetoothSco()")) { 965 return; 966 } 967 ScoClient client = getScoClient(cb); 968 client.decCount(); 969 } 970 971 private class ScoClient implements IBinder.DeathRecipient { 972 private IBinder mCb; // To be notified of client's death 973 private int mStartcount; // number of SCO connections started by this client 974 975 ScoClient(IBinder cb) { 976 mCb = cb; 977 mStartcount = 0; 978 } 979 980 public void binderDied() { 981 synchronized(mScoClients) { 982 Log.w(TAG, "SCO client died"); 983 int index = mScoClients.indexOf(this); 984 if (index < 0) { 985 Log.w(TAG, "unregistered SCO client died"); 986 } else { 987 clearCount(true); 988 mScoClients.remove(this); 989 } 990 } 991 } 992 993 public void incCount() { 994 synchronized(mScoClients) { 995 requestScoState(BluetoothHeadset.AUDIO_STATE_CONNECTED); 996 if (mStartcount == 0) { 997 try { 998 mCb.linkToDeath(this, 0); 999 } catch (RemoteException e) { 1000 // client has already died! 1001 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 1002 } 1003 } 1004 mStartcount++; 1005 } 1006 } 1007 1008 public void decCount() { 1009 synchronized(mScoClients) { 1010 if (mStartcount == 0) { 1011 Log.w(TAG, "ScoClient.decCount() already 0"); 1012 } else { 1013 mStartcount--; 1014 if (mStartcount == 0) { 1015 mCb.unlinkToDeath(this, 0); 1016 } 1017 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1018 } 1019 } 1020 } 1021 1022 public void clearCount(boolean stopSco) { 1023 synchronized(mScoClients) { 1024 mStartcount = 0; 1025 mCb.unlinkToDeath(this, 0); 1026 if (stopSco) { 1027 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1028 } 1029 } 1030 } 1031 1032 public int getCount() { 1033 return mStartcount; 1034 } 1035 1036 public IBinder getBinder() { 1037 return mCb; 1038 } 1039 1040 public int totalCount() { 1041 synchronized(mScoClients) { 1042 int count = 0; 1043 int size = mScoClients.size(); 1044 for (int i = 0; i < size; i++) { 1045 count += mScoClients.get(i).getCount(); 1046 } 1047 return count; 1048 } 1049 } 1050 1051 private void requestScoState(int state) { 1052 if (totalCount() == 0 && 1053 mBluetoothHeadsetConnected && 1054 AudioService.this.mMode == AudioSystem.MODE_NORMAL) { 1055 if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) { 1056 mBluetoothHeadset.startVoiceRecognition(); 1057 } else { 1058 mBluetoothHeadset.stopVoiceRecognition(); 1059 } 1060 } 1061 } 1062 } 1063 1064 public ScoClient getScoClient(IBinder cb) { 1065 synchronized(mScoClients) { 1066 ScoClient client; 1067 int size = mScoClients.size(); 1068 for (int i = 0; i < size; i++) { 1069 client = mScoClients.get(i); 1070 if (client.getBinder() == cb) 1071 return client; 1072 } 1073 client = new ScoClient(cb); 1074 mScoClients.add(client); 1075 return client; 1076 } 1077 } 1078 1079 public void clearAllScoClients() { 1080 synchronized(mScoClients) { 1081 int size = mScoClients.size(); 1082 for (int i = 0; i < size; i++) { 1083 mScoClients.get(i).clearCount(false); 1084 } 1085 } 1086 } 1087 1088 private BluetoothHeadset.ServiceListener mBluetoothHeadsetServiceListener = 1089 new BluetoothHeadset.ServiceListener() { 1090 public void onServiceConnected() { 1091 if (mBluetoothHeadset != null && 1092 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_CONNECTED) { 1093 mBluetoothHeadsetConnected = true; 1094 } 1095 } 1096 public void onServiceDisconnected() { 1097 if (mBluetoothHeadset != null && 1098 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_DISCONNECTED) { 1099 mBluetoothHeadsetConnected = false; 1100 clearAllScoClients(); 1101 } 1102 } 1103 }; 1104 1105 /////////////////////////////////////////////////////////////////////////// 1106 // Internal methods 1107 /////////////////////////////////////////////////////////////////////////// 1108 1109 /** 1110 * Checks if the adjustment should change ringer mode instead of just 1111 * adjusting volume. If so, this will set the proper ringer mode and volume 1112 * indices on the stream states. 1113 */ 1114 private boolean checkForRingerModeChange(int oldIndex, int direction) { 1115 boolean adjustVolumeIndex = true; 1116 int newRingerMode = mRingerMode; 1117 1118 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1119 // audible mode, at the bottom of the scale 1120 if (direction == AudioManager.ADJUST_LOWER 1121 && (oldIndex + 5) / 10 == 1) { 1122 // "silent mode", but which one? 1123 newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 1124 ? AudioManager.RINGER_MODE_VIBRATE 1125 : AudioManager.RINGER_MODE_SILENT; 1126 } 1127 } else { 1128 if (direction == AudioManager.ADJUST_RAISE) { 1129 // exiting silent mode 1130 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 1131 } else { 1132 // prevent last audible index to reach 0 1133 adjustVolumeIndex = false; 1134 } 1135 } 1136 1137 if (newRingerMode != mRingerMode) { 1138 setRingerMode(newRingerMode); 1139 1140 /* 1141 * If we are changing ringer modes, do not increment/decrement the 1142 * volume index. Instead, the handler for the message above will 1143 * take care of changing the index. 1144 */ 1145 adjustVolumeIndex = false; 1146 } 1147 1148 return adjustVolumeIndex; 1149 } 1150 1151 public boolean isStreamAffectedByRingerMode(int streamType) { 1152 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 1153 } 1154 1155 private boolean isStreamMutedByRingerMode(int streamType) { 1156 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 1157 } 1158 1159 public boolean isStreamAffectedByMute(int streamType) { 1160 return (mMuteAffectedStreams & (1 << streamType)) != 0; 1161 } 1162 1163 private void ensureValidDirection(int direction) { 1164 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 1165 throw new IllegalArgumentException("Bad direction " + direction); 1166 } 1167 } 1168 1169 private void ensureValidStreamType(int streamType) { 1170 if (streamType < 0 || streamType >= mStreamStates.length) { 1171 throw new IllegalArgumentException("Bad stream type " + streamType); 1172 } 1173 } 1174 1175 private int getActiveStreamType(int suggestedStreamType) { 1176 boolean isOffhook = false; 1177 try { 1178 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 1179 if (phone != null) isOffhook = phone.isOffhook(); 1180 } catch (RemoteException e) { 1181 Log.w(TAG, "Couldn't connect to phone service", e); 1182 } 1183 1184 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { 1185 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 1186 return AudioSystem.STREAM_BLUETOOTH_SCO; 1187 } else if (isOffhook || AudioSystem.isStreamActive(AudioSystem.STREAM_VOICE_CALL)) { 1188 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 1189 return AudioSystem.STREAM_VOICE_CALL; 1190 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC)) { 1191 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 1192 return AudioSystem.STREAM_MUSIC; 1193 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1194 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); 1195 return AudioSystem.STREAM_RING; 1196 } else { 1197 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 1198 return suggestedStreamType; 1199 } 1200 } 1201 1202 private void broadcastRingerMode() { 1203 // Send sticky broadcast 1204 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 1205 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); 1206 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1207 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1208 long origCallerIdentityToken = Binder.clearCallingIdentity(); 1209 mContext.sendStickyBroadcast(broadcast); 1210 Binder.restoreCallingIdentity(origCallerIdentityToken); 1211 } 1212 1213 private void broadcastVibrateSetting(int vibrateType) { 1214 // Send broadcast 1215 if (ActivityManagerNative.isSystemReady()) { 1216 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 1217 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 1218 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 1219 mContext.sendBroadcast(broadcast); 1220 } 1221 } 1222 1223 // Message helper methods 1224 private static int getMsg(int baseMsg, int streamType) { 1225 return (baseMsg & 0xffff) | streamType << 16; 1226 } 1227 1228 private static int getMsgBase(int msg) { 1229 return msg & 0xffff; 1230 } 1231 1232 private static void sendMsg(Handler handler, int baseMsg, int streamType, 1233 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 1234 int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); 1235 1236 if (existingMsgPolicy == SENDMSG_REPLACE) { 1237 handler.removeMessages(msg); 1238 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 1239 return; 1240 } 1241 1242 handler 1243 .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 1244 } 1245 1246 boolean checkAudioSettingsPermission(String method) { 1247 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 1248 == PackageManager.PERMISSION_GRANTED) { 1249 return true; 1250 } 1251 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 1252 + Binder.getCallingPid() 1253 + ", uid=" + Binder.getCallingUid(); 1254 Log.w(TAG, msg); 1255 return false; 1256 } 1257 1258 1259 /////////////////////////////////////////////////////////////////////////// 1260 // Inner classes 1261 /////////////////////////////////////////////////////////////////////////// 1262 1263 public class VolumeStreamState { 1264 private final int mStreamType; 1265 1266 private String mVolumeIndexSettingName; 1267 private String mLastAudibleVolumeIndexSettingName; 1268 private int mIndexMax; 1269 private int mIndex; 1270 private int mLastAudibleIndex; 1271 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death 1272 1273 private VolumeStreamState(String settingName, int streamType) { 1274 1275 setVolumeIndexSettingName(settingName); 1276 1277 mStreamType = streamType; 1278 1279 final ContentResolver cr = mContentResolver; 1280 mIndexMax = MAX_STREAM_VOLUME[streamType]; 1281 mIndex = Settings.System.getInt(cr, 1282 mVolumeIndexSettingName, 1283 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1284 mLastAudibleIndex = Settings.System.getInt(cr, 1285 mLastAudibleVolumeIndexSettingName, 1286 (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1287 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 1288 mIndexMax *= 10; 1289 mIndex = getValidIndex(10 * mIndex); 1290 mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); 1291 setStreamVolumeIndex(streamType, mIndex); 1292 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 1293 } 1294 1295 public void setVolumeIndexSettingName(String settingName) { 1296 mVolumeIndexSettingName = settingName; 1297 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 1298 } 1299 1300 public boolean adjustIndex(int deltaIndex) { 1301 return setIndex(mIndex + deltaIndex * 10, true); 1302 } 1303 1304 public boolean setIndex(int index, boolean lastAudible) { 1305 int oldIndex = mIndex; 1306 mIndex = getValidIndex(index); 1307 1308 if (oldIndex != mIndex) { 1309 if (lastAudible) { 1310 mLastAudibleIndex = mIndex; 1311 } 1312 // Apply change to all streams using this one as alias 1313 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1314 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1315 if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { 1316 mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); 1317 } 1318 } 1319 return true; 1320 } else { 1321 return false; 1322 } 1323 } 1324 1325 public void setLastAudibleIndex(int index) { 1326 mLastAudibleIndex = getValidIndex(index); 1327 } 1328 1329 public void adjustLastAudibleIndex(int deltaIndex) { 1330 setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10); 1331 } 1332 1333 public int getMaxIndex() { 1334 return mIndexMax; 1335 } 1336 1337 public void mute(IBinder cb, boolean state) { 1338 VolumeDeathHandler handler = getDeathHandler(cb, state); 1339 if (handler == null) { 1340 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 1341 return; 1342 } 1343 handler.mute(state); 1344 } 1345 1346 private int getValidIndex(int index) { 1347 if (index < 0) { 1348 return 0; 1349 } else if (index > mIndexMax) { 1350 return mIndexMax; 1351 } 1352 1353 return index; 1354 } 1355 1356 private class VolumeDeathHandler implements IBinder.DeathRecipient { 1357 private IBinder mICallback; // To be notified of client's death 1358 private int mMuteCount; // Number of active mutes for this client 1359 1360 VolumeDeathHandler(IBinder cb) { 1361 mICallback = cb; 1362 } 1363 1364 public void mute(boolean state) { 1365 synchronized(mDeathHandlers) { 1366 if (state) { 1367 if (mMuteCount == 0) { 1368 // Register for client death notification 1369 try { 1370 // mICallback can be 0 if muted by AudioService 1371 if (mICallback != null) { 1372 mICallback.linkToDeath(this, 0); 1373 } 1374 mDeathHandlers.add(this); 1375 // If the stream is not yet muted by any client, set lvel to 0 1376 if (muteCount() == 0) { 1377 setIndex(0, false); 1378 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1379 VolumeStreamState.this, 0); 1380 } 1381 } catch (RemoteException e) { 1382 // Client has died! 1383 binderDied(); 1384 mDeathHandlers.notify(); 1385 return; 1386 } 1387 } else { 1388 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 1389 } 1390 mMuteCount++; 1391 } else { 1392 if (mMuteCount == 0) { 1393 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 1394 } else { 1395 mMuteCount--; 1396 if (mMuteCount == 0) { 1397 // Unregistr from client death notification 1398 mDeathHandlers.remove(this); 1399 // mICallback can be 0 if muted by AudioService 1400 if (mICallback != null) { 1401 mICallback.unlinkToDeath(this, 0); 1402 } 1403 if (muteCount() == 0) { 1404 // If the stream is not muted any more, restore it's volume if 1405 // ringer mode allows it 1406 if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1407 setIndex(mLastAudibleIndex, false); 1408 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1409 VolumeStreamState.this, 0); 1410 } 1411 } 1412 } 1413 } 1414 } 1415 mDeathHandlers.notify(); 1416 } 1417 } 1418 1419 public void binderDied() { 1420 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 1421 if (mMuteCount != 0) { 1422 // Reset all active mute requests from this client. 1423 mMuteCount = 1; 1424 mute(false); 1425 } 1426 } 1427 } 1428 1429 private int muteCount() { 1430 int count = 0; 1431 int size = mDeathHandlers.size(); 1432 for (int i = 0; i < size; i++) { 1433 count += mDeathHandlers.get(i).mMuteCount; 1434 } 1435 return count; 1436 } 1437 1438 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 1439 synchronized(mDeathHandlers) { 1440 VolumeDeathHandler handler; 1441 int size = mDeathHandlers.size(); 1442 for (int i = 0; i < size; i++) { 1443 handler = mDeathHandlers.get(i); 1444 if (cb == handler.mICallback) { 1445 return handler; 1446 } 1447 } 1448 // If this is the first mute request for this client, create a new 1449 // client death handler. Otherwise, it is an out of sequence unmute request. 1450 if (state) { 1451 handler = new VolumeDeathHandler(cb); 1452 } else { 1453 Log.w(TAG, "stream was not muted by this client"); 1454 handler = null; 1455 } 1456 return handler; 1457 } 1458 } 1459 } 1460 1461 /** Thread that handles native AudioSystem control. */ 1462 private class AudioSystemThread extends Thread { 1463 AudioSystemThread() { 1464 super("AudioService"); 1465 } 1466 1467 @Override 1468 public void run() { 1469 // Set this thread up so the handler will work on it 1470 Looper.prepare(); 1471 1472 synchronized(AudioService.this) { 1473 mAudioHandler = new AudioHandler(); 1474 1475 // Notify that the handler has been created 1476 AudioService.this.notify(); 1477 } 1478 1479 // Listen for volume change requests that are set by VolumePanel 1480 Looper.loop(); 1481 } 1482 } 1483 1484 /** Handles internal volume messages in separate volume thread. */ 1485 private class AudioHandler extends Handler { 1486 1487 private void setSystemVolume(VolumeStreamState streamState) { 1488 1489 // Adjust volume 1490 setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); 1491 1492 // Apply change to all streams using this one as alias 1493 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1494 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1495 if (streamType != streamState.mStreamType && 1496 STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { 1497 setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); 1498 } 1499 } 1500 1501 // Post a persist volume msg 1502 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, 1503 SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY); 1504 } 1505 1506 private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) { 1507 if (current) { 1508 System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, 1509 (streamState.mIndex + 5)/ 10); 1510 } 1511 if (lastAudible) { 1512 System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, 1513 (streamState.mLastAudibleIndex + 5) / 10); 1514 } 1515 } 1516 1517 private void persistRingerMode() { 1518 System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); 1519 } 1520 1521 private void persistVibrateSetting() { 1522 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 1523 } 1524 1525 private void playSoundEffect(int effectType, int volume) { 1526 synchronized (mSoundEffectsLock) { 1527 if (mSoundPool == null) { 1528 return; 1529 } 1530 float volFloat; 1531 // use STREAM_MUSIC volume attenuated by 3 dB if volume is not specified by caller 1532 if (volume < 0) { 1533 // Same linear to log conversion as in native AudioSystem::linearToLog() (AudioSystem.cpp) 1534 float dBPerStep = (float)((0.5 * 100) / MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1535 int musicVolIndex = (mStreamStates[AudioSystem.STREAM_MUSIC].mIndex + 5) / 10; 1536 float musicVoldB = dBPerStep * (musicVolIndex - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1537 volFloat = (float)Math.pow(10, (musicVoldB - 3)/20); 1538 } else { 1539 volFloat = (float) volume / 1000.0f; 1540 } 1541 1542 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 1543 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 1544 } else { 1545 MediaPlayer mediaPlayer = new MediaPlayer(); 1546 if (mediaPlayer != null) { 1547 try { 1548 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 1549 mediaPlayer.setDataSource(filePath); 1550 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 1551 mediaPlayer.prepare(); 1552 mediaPlayer.setVolume(volFloat, volFloat); 1553 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 1554 public void onCompletion(MediaPlayer mp) { 1555 cleanupPlayer(mp); 1556 } 1557 }); 1558 mediaPlayer.setOnErrorListener(new OnErrorListener() { 1559 public boolean onError(MediaPlayer mp, int what, int extra) { 1560 cleanupPlayer(mp); 1561 return true; 1562 } 1563 }); 1564 mediaPlayer.start(); 1565 } catch (IOException ex) { 1566 Log.w(TAG, "MediaPlayer IOException: "+ex); 1567 } catch (IllegalArgumentException ex) { 1568 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 1569 } catch (IllegalStateException ex) { 1570 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1571 } 1572 } 1573 } 1574 } 1575 } 1576 1577 private void cleanupPlayer(MediaPlayer mp) { 1578 if (mp != null) { 1579 try { 1580 mp.stop(); 1581 mp.release(); 1582 } catch (IllegalStateException ex) { 1583 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1584 } 1585 } 1586 } 1587 1588 @Override 1589 public void handleMessage(Message msg) { 1590 int baseMsgWhat = getMsgBase(msg.what); 1591 1592 switch (baseMsgWhat) { 1593 1594 case MSG_SET_SYSTEM_VOLUME: 1595 setSystemVolume((VolumeStreamState) msg.obj); 1596 break; 1597 1598 case MSG_PERSIST_VOLUME: 1599 persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0)); 1600 break; 1601 1602 case MSG_PERSIST_RINGER_MODE: 1603 persistRingerMode(); 1604 break; 1605 1606 case MSG_PERSIST_VIBRATE_SETTING: 1607 persistVibrateSetting(); 1608 break; 1609 1610 case MSG_MEDIA_SERVER_DIED: 1611 // Force creation of new IAudioflinger interface 1612 if (!mMediaServerOk) { 1613 Log.e(TAG, "Media server died."); 1614 AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC); 1615 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 1616 null, 500); 1617 } 1618 break; 1619 1620 case MSG_MEDIA_SERVER_STARTED: 1621 Log.e(TAG, "Media server started."); 1622 // Restore device connection states 1623 Set set = mConnectedDevices.entrySet(); 1624 Iterator i = set.iterator(); 1625 while(i.hasNext()){ 1626 Map.Entry device = (Map.Entry)i.next(); 1627 AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), 1628 AudioSystem.DEVICE_STATE_AVAILABLE, 1629 (String)device.getValue()); 1630 } 1631 1632 // Restore call state 1633 AudioSystem.setPhoneState(mMode); 1634 1635 // Restore forced usage for communcations and record 1636 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 1637 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 1638 1639 // Restore stream volumes 1640 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1641 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1642 int index; 1643 VolumeStreamState streamState = mStreamStates[streamType]; 1644 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 1645 if (streamState.muteCount() == 0) { 1646 index = streamState.mIndex; 1647 } else { 1648 index = 0; 1649 } 1650 setStreamVolumeIndex(streamType, index); 1651 } 1652 1653 // Restore ringer mode 1654 setRingerModeInt(getRingerMode(), false); 1655 break; 1656 1657 case MSG_PLAY_SOUND_EFFECT: 1658 playSoundEffect(msg.arg1, msg.arg2); 1659 break; 1660 1661 case MSG_BTA2DP_DOCK_TIMEOUT: 1662 // msg.obj == address of BTA2DP device 1663 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 1664 break; 1665 } 1666 } 1667 } 1668 1669 private class SettingsObserver extends ContentObserver { 1670 1671 SettingsObserver() { 1672 super(new Handler()); 1673 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1674 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 1675 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1676 Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this); 1677 } 1678 1679 @Override 1680 public void onChange(boolean selfChange) { 1681 super.onChange(selfChange); 1682 synchronized (mSettingsLock) { 1683 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 1684 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 1685 0); 1686 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 1687 /* 1688 * Ensure all stream types that should be affected by ringer mode 1689 * are in the proper state. 1690 */ 1691 mRingerModeAffectedStreams = ringerModeAffectedStreams; 1692 setRingerModeInt(getRingerMode(), false); 1693 } 1694 1695 int notificationsUseRingVolume = Settings.System.getInt(mContentResolver, 1696 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1697 1); 1698 if (notificationsUseRingVolume != mNotificationsUseRingVolume) { 1699 mNotificationsUseRingVolume = notificationsUseRingVolume; 1700 if (mNotificationsUseRingVolume == 1) { 1701 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 1702 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1703 System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]); 1704 } else { 1705 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; 1706 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1707 System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]); 1708 // Persist notification volume volume as it was not persisted while aliased to ring volume 1709 // and persist with no delay as there might be registered observers of the persisted 1710 // notification volume. 1711 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, 1712 SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0); 1713 } 1714 } 1715 } 1716 } 1717 } 1718 1719 private void makeA2dpDeviceAvailable(String address) { 1720 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1721 AudioSystem.DEVICE_STATE_AVAILABLE, 1722 address); 1723 // Reset A2DP suspend state each time a new sink is connected 1724 AudioSystem.setParameters("A2dpSuspended=false"); 1725 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 1726 address); 1727 } 1728 1729 private void makeA2dpDeviceUnavailableNow(String address) { 1730 Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 1731 mContext.sendBroadcast(noisyIntent); 1732 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1733 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1734 address); 1735 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1736 } 1737 1738 private void makeA2dpDeviceUnavailableLater(String address) { 1739 // the device will be made unavailable later, so consider it disconnected right away 1740 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1741 // send the delayed message to make the device unavailable later 1742 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 1743 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 1744 1745 } 1746 1747 private void cancelA2dpDeviceTimeout(String address) { 1748 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 1749 } 1750 1751 /** 1752 * Receiver for misc intent broadcasts the Phone app cares about. 1753 */ 1754 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 1755 @Override 1756 public void onReceive(Context context, Intent intent) { 1757 String action = intent.getAction(); 1758 1759 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 1760 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1761 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1762 int config; 1763 switch (dockState) { 1764 case Intent.EXTRA_DOCK_STATE_DESK: 1765 config = AudioSystem.FORCE_BT_DESK_DOCK; 1766 break; 1767 case Intent.EXTRA_DOCK_STATE_CAR: 1768 config = AudioSystem.FORCE_BT_CAR_DOCK; 1769 break; 1770 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 1771 default: 1772 config = AudioSystem.FORCE_NONE; 1773 } 1774 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 1775 } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) { 1776 int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 1777 BluetoothA2dp.STATE_DISCONNECTED); 1778 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1779 String address = btDevice.getAddress(); 1780 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 1781 ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); 1782 1783 if (isConnected && 1784 state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) { 1785 if (btDevice.isBluetoothDock()) { 1786 if (state == BluetoothA2dp.STATE_DISCONNECTED) { 1787 // introduction of a delay for transient disconnections of docks when 1788 // power is rapidly turned off/on, this message will be canceled if 1789 // we reconnect the dock under a preset delay 1790 makeA2dpDeviceUnavailableLater(address); 1791 // the next time isConnected is evaluated, it will be false for the dock 1792 } 1793 } else { 1794 makeA2dpDeviceUnavailableNow(address); 1795 } 1796 } else if (!isConnected && 1797 (state == BluetoothA2dp.STATE_CONNECTED || 1798 state == BluetoothA2dp.STATE_PLAYING)) { 1799 if (btDevice.isBluetoothDock()) { 1800 // this could be a reconnection after a transient disconnection 1801 cancelA2dpDeviceTimeout(address); 1802 } 1803 makeA2dpDeviceAvailable(address); 1804 } 1805 } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) { 1806 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 1807 BluetoothHeadset.STATE_ERROR); 1808 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 1809 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1810 String address = null; 1811 if (btDevice != null) { 1812 address = btDevice.getAddress(); 1813 BluetoothClass btClass = btDevice.getBluetoothClass(); 1814 if (btClass != null) { 1815 switch (btClass.getDeviceClass()) { 1816 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 1817 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 1818 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 1819 break; 1820 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 1821 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 1822 break; 1823 } 1824 } 1825 } 1826 1827 boolean isConnected = (mConnectedDevices.containsKey(device) && 1828 ((String)mConnectedDevices.get(device)).equals(address)); 1829 1830 if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) { 1831 AudioSystem.setDeviceConnectionState(device, 1832 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1833 address); 1834 mConnectedDevices.remove(device); 1835 mBluetoothHeadsetConnected = false; 1836 clearAllScoClients(); 1837 } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) { 1838 AudioSystem.setDeviceConnectionState(device, 1839 AudioSystem.DEVICE_STATE_AVAILABLE, 1840 address); 1841 mConnectedDevices.put(new Integer(device), address); 1842 mBluetoothHeadsetConnected = true; 1843 } 1844 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1845 int state = intent.getIntExtra("state", 0); 1846 int microphone = intent.getIntExtra("microphone", 0); 1847 1848 if (microphone != 0) { 1849 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1850 if (state == 0 && isConnected) { 1851 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1852 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1853 ""); 1854 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1855 } else if (state == 1 && !isConnected) { 1856 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1857 AudioSystem.DEVICE_STATE_AVAILABLE, 1858 ""); 1859 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); 1860 } 1861 } else { 1862 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1863 if (state == 0 && isConnected) { 1864 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1865 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1866 ""); 1867 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1868 } else if (state == 1 && !isConnected) { 1869 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1870 AudioSystem.DEVICE_STATE_AVAILABLE, 1871 ""); 1872 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); 1873 } 1874 } 1875 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 1876 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_AUDIO_STATE, 1877 BluetoothHeadset.STATE_ERROR); 1878 synchronized (mScoClients) { 1879 if (!mScoClients.isEmpty()) { 1880 switch (state) { 1881 case BluetoothHeadset.AUDIO_STATE_CONNECTED: 1882 state = AudioManager.SCO_AUDIO_STATE_CONNECTED; 1883 break; 1884 case BluetoothHeadset.AUDIO_STATE_DISCONNECTED: 1885 state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 1886 break; 1887 default: 1888 state = AudioManager.SCO_AUDIO_STATE_ERROR; 1889 break; 1890 } 1891 if (state != AudioManager.SCO_AUDIO_STATE_ERROR) { 1892 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 1893 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1894 mContext.sendStickyBroadcast(newIntent); 1895 } 1896 } 1897 } 1898 } 1899 } 1900 } 1901 1902 //========================================================================================== 1903 // AudioFocus 1904 //========================================================================================== 1905 /** 1906 * Flag to indicate that the top of the audio focus stack needs to recover focus 1907 * but hasn't been signaled yet. 1908 */ 1909 private boolean mHasUndispatchedAudioFocus = false; 1910 1911 private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) { 1912 // when exiting a call 1913 if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) { 1914 // check for undispatched remote control focus gain 1915 if (mHasUndispatchedAudioFocus) { 1916 notifyTopOfAudioFocusStack(); 1917 } 1918 } 1919 } 1920 1921 private void notifyTopOfAudioFocusStack() { 1922 // notify the top of the stack it gained focus 1923 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 1924 if (canReassignAudioFocus()) { 1925 try { 1926 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 1927 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 1928 mHasUndispatchedAudioFocus = false; 1929 } catch (RemoteException e) { 1930 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 1931 e.printStackTrace(); 1932 } 1933 } else { 1934 mHasUndispatchedAudioFocus = true; 1935 } 1936 } 1937 } 1938 1939 private static class FocusStackEntry { 1940 public int mStreamType = -1;// no stream type 1941 public boolean mIsTransportControlReceiver = false; 1942 public IAudioFocusDispatcher mFocusDispatcher = null; 1943 public IBinder mSourceRef = null; 1944 public String mClientId; 1945 public int mFocusChangeType; 1946 1947 public FocusStackEntry() { 1948 } 1949 1950 public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver, 1951 IAudioFocusDispatcher afl, IBinder source, String id) { 1952 mStreamType = streamType; 1953 mIsTransportControlReceiver = isTransportControlReceiver; 1954 mFocusDispatcher = afl; 1955 mSourceRef = source; 1956 mClientId = id; 1957 mFocusChangeType = duration; 1958 } 1959 } 1960 1961 private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 1962 1963 /** 1964 * Helper function: 1965 * Display in the log the current entries in the audio focus stack 1966 */ 1967 private void dumpFocusStack(PrintWriter pw) { 1968 pw.println("Audio Focus stack entries:"); 1969 synchronized(mFocusStack) { 1970 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1971 while(stackIterator.hasNext()) { 1972 FocusStackEntry fse = stackIterator.next(); 1973 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 1974 + " -- duration: " +fse.mFocusChangeType); 1975 } 1976 } 1977 } 1978 1979 /** 1980 * Helper function: 1981 * Remove a focus listener from the focus stack. 1982 * @param focusListenerToRemove the focus listener 1983 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 1984 * focus, notify the next item in the stack it gained focus. 1985 */ 1986 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 1987 // is the current top of the focus stack abandoning focus? (because of death or request) 1988 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 1989 { 1990 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 1991 mFocusStack.pop(); 1992 if (signal) { 1993 // notify the new top of the stack it gained focus 1994 notifyTopOfAudioFocusStack(); 1995 } 1996 } else { 1997 // focus is abandoned by a client that's not at the top of the stack, 1998 // no need to update focus. 1999 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 2000 while(stackIterator.hasNext()) { 2001 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 2002 if(fse.mClientId.equals(clientToRemove)) { 2003 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 2004 + fse.mClientId); 2005 mFocusStack.remove(fse); 2006 } 2007 } 2008 } 2009 } 2010 2011 /** 2012 * Helper function: 2013 * Remove focus listeners from the focus stack for a particular client. 2014 */ 2015 private void removeFocusStackEntryForClient(IBinder cb) { 2016 // is the owner of the audio focus part of the client to remove? 2017 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 2018 mFocusStack.peek().mSourceRef.equals(cb); 2019 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 2020 while(stackIterator.hasNext()) { 2021 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 2022 if(fse.mSourceRef.equals(cb)) { 2023 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 2024 + fse.mClientId); 2025 mFocusStack.remove(fse); 2026 } 2027 } 2028 if (isTopOfStackForClientToRemove) { 2029 // we removed an entry at the top of the stack: 2030 // notify the new top of the stack it gained focus. 2031 notifyTopOfAudioFocusStack(); 2032 } 2033 } 2034 2035 /** 2036 * Helper function: 2037 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 2038 */ 2039 private boolean canReassignAudioFocus() { 2040 // focus requests are rejected during a phone call 2041 if (getMode() == AudioSystem.MODE_IN_CALL) { 2042 Log.i(TAG, " AudioFocus can't be reassigned during a call, exiting"); 2043 return false; 2044 } 2045 return true; 2046 } 2047 2048 /** 2049 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 2050 * stack if necessary. 2051 */ 2052 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 2053 private IBinder mCb; // To be notified of client's death 2054 2055 AudioFocusDeathHandler(IBinder cb) { 2056 mCb = cb; 2057 } 2058 2059 public void binderDied() { 2060 synchronized(mFocusStack) { 2061 Log.w(TAG, " AudioFocus audio focus client died"); 2062 removeFocusStackEntryForClient(mCb); 2063 } 2064 } 2065 2066 public IBinder getBinder() { 2067 return mCb; 2068 } 2069 } 2070 2071 2072 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 2073 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 2074 IAudioFocusDispatcher fd, String clientId) { 2075 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 2076 // the main stream type for the audio focus request is currently not used. It may 2077 // potentially be used to handle multiple stream type-dependent audio focuses. 2078 2079 if ((cb == null) || !cb.pingBinder()) { 2080 Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting"); 2081 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2082 } 2083 2084 if (!canReassignAudioFocus()) { 2085 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2086 } 2087 2088 synchronized(mFocusStack) { 2089 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 2090 // if focus is already owned by this client and the reason for acquiring the focus 2091 // hasn't changed, don't do anything 2092 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 2093 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2094 } 2095 // the reason for the audio focus request has changed: remove the current top of 2096 // stack and respond as if we had a new focus owner 2097 mFocusStack.pop(); 2098 } 2099 2100 // notify current top of stack it is losing focus 2101 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 2102 try { 2103 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 2104 -1 * focusChangeHint, // loss and gain codes are inverse of each other 2105 mFocusStack.peek().mClientId); 2106 } catch (RemoteException e) { 2107 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 2108 e.printStackTrace(); 2109 } 2110 } 2111 2112 // focus requester might already be somewhere below in the stack, remove it 2113 removeFocusStackEntry(clientId, false); 2114 2115 // push focus requester at the top of the audio focus stack 2116 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb, 2117 clientId)); 2118 }//synchronized(mFocusStack) 2119 2120 // handle the potential premature death of the new holder of the focus 2121 // (premature death == death before abandoning focus) 2122 // Register for client death notification 2123 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 2124 try { 2125 cb.linkToDeath(afdh, 0); 2126 } catch (RemoteException e) { 2127 // client has already died! 2128 Log.w(TAG, " AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 2129 } 2130 2131 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2132 } 2133 2134 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 2135 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 2136 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 2137 2138 // this will take care of notifying the new focus owner if needed 2139 synchronized(mFocusStack) { 2140 removeFocusStackEntry(clientId, true); 2141 } 2142 2143 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2144 } 2145 2146 2147 public void unregisterAudioFocusClient(String clientId) { 2148 synchronized(mFocusStack) { 2149 removeFocusStackEntry(clientId, false); 2150 } 2151 } 2152 2153 2154 //========================================================================================== 2155 // RemoteControl 2156 //========================================================================================== 2157 /** 2158 * Receiver for media button intents. Handles the dispatching of the media button event 2159 * to one of the registered listeners, or if there was none, resumes the intent broadcast 2160 * to the rest of the system. 2161 */ 2162 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 2163 @Override 2164 public void onReceive(Context context, Intent intent) { 2165 String action = intent.getAction(); 2166 if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) { 2167 return; 2168 } 2169 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 2170 if (event != null) { 2171 // if in a call or ringing, do not break the current phone app behavior 2172 // TODO modify this to let the phone app specifically get the RC focus 2173 // add modify the phone app to take advantage of the new API 2174 if ((getMode() == AudioSystem.MODE_IN_CALL) || 2175 (getMode() == AudioSystem.MODE_RINGTONE)) { 2176 return; 2177 } 2178 synchronized(mRCStack) { 2179 if (!mRCStack.empty()) { 2180 // create a new intent specifically aimed at the current registered listener 2181 Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 2182 targetedIntent.putExtras(intent.getExtras()); 2183 targetedIntent.setComponent(mRCStack.peek().mReceiverComponent); 2184 // trap the current broadcast 2185 abortBroadcast(); 2186 //Log.v(TAG, " Sending intent" + targetedIntent); 2187 context.sendBroadcast(targetedIntent, null); 2188 } 2189 } 2190 } 2191 } 2192 } 2193 2194 private static class RemoteControlStackEntry { 2195 public ComponentName mReceiverComponent;// always non null 2196 // TODO implement registration expiration? 2197 //public int mRegistrationTime; 2198 2199 public RemoteControlStackEntry() { 2200 } 2201 2202 public RemoteControlStackEntry(ComponentName r) { 2203 mReceiverComponent = r; 2204 } 2205 } 2206 2207 private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 2208 2209 /** 2210 * Helper function: 2211 * Display in the log the current entries in the remote control focus stack 2212 */ 2213 private void dumpRCStack(PrintWriter pw) { 2214 pw.println("Remote Control stack entries:"); 2215 synchronized(mRCStack) { 2216 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2217 while(stackIterator.hasNext()) { 2218 RemoteControlStackEntry fse = stackIterator.next(); 2219 pw.println(" receiver:" + fse.mReceiverComponent); 2220 } 2221 } 2222 } 2223 2224 /** 2225 * Helper function: 2226 * Set the new remote control receiver at the top of the RC focus stack 2227 */ 2228 private void pushMediaButtonReceiver(ComponentName newReceiver) { 2229 // already at top of stack? 2230 if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) { 2231 return; 2232 } 2233 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2234 while(stackIterator.hasNext()) { 2235 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2236 if(rcse.mReceiverComponent.equals(newReceiver)) { 2237 mRCStack.remove(rcse); 2238 break; 2239 } 2240 } 2241 mRCStack.push(new RemoteControlStackEntry(newReceiver)); 2242 } 2243 2244 /** 2245 * Helper function: 2246 * Remove the remote control receiver from the RC focus stack 2247 */ 2248 private void removeMediaButtonReceiver(ComponentName newReceiver) { 2249 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2250 while(stackIterator.hasNext()) { 2251 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2252 if(rcse.mReceiverComponent.equals(newReceiver)) { 2253 mRCStack.remove(rcse); 2254 break; 2255 } 2256 } 2257 } 2258 2259 2260 /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */ 2261 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 2262 Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver); 2263 2264 synchronized(mRCStack) { 2265 pushMediaButtonReceiver(eventReceiver); 2266 } 2267 } 2268 2269 /** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */ 2270 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 2271 Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver); 2272 2273 synchronized(mRCStack) { 2274 removeMediaButtonReceiver(eventReceiver); 2275 } 2276 } 2277 2278 2279 @Override 2280 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2281 // TODO probably a lot more to do here than just the audio focus and remote control stacks 2282 dumpFocusStack(pw); 2283 dumpRCStack(pw); 2284 } 2285 2286 2287} 2288