AudioService.java revision 758dd527f64f1e827adfe09f0141ab213733ca22
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 // Do not allow last audible index to be 0 496 if (index != 0) { 497 streamState.setLastAudibleIndex(index); 498 // Post a persist volume msg 499 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, 500 SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); 501 } 502 } else { 503 if (streamState.setIndex(index, lastAudible) || force) { 504 // Post message to set system volume (it in turn will post a message 505 // to persist). 506 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, 507 streamState, 0); 508 } 509 } 510 } 511 512 /** @see AudioManager#setStreamSolo(int, boolean) */ 513 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 514 for (int stream = 0; stream < mStreamStates.length; stream++) { 515 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 516 // Bring back last audible volume 517 mStreamStates[stream].mute(cb, state); 518 } 519 } 520 521 /** @see AudioManager#setStreamMute(int, boolean) */ 522 public void setStreamMute(int streamType, boolean state, IBinder cb) { 523 if (isStreamAffectedByMute(streamType)) { 524 mStreamStates[streamType].mute(cb, state); 525 } 526 } 527 528 /** @see AudioManager#getStreamVolume(int) */ 529 public int getStreamVolume(int streamType) { 530 ensureValidStreamType(streamType); 531 return (mStreamStates[streamType].mIndex + 5) / 10; 532 } 533 534 /** @see AudioManager#getStreamMaxVolume(int) */ 535 public int getStreamMaxVolume(int streamType) { 536 ensureValidStreamType(streamType); 537 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 538 } 539 540 /** @see AudioManager#getRingerMode() */ 541 public int getRingerMode() { 542 return mRingerMode; 543 } 544 545 /** @see AudioManager#setRingerMode(int) */ 546 public void setRingerMode(int ringerMode) { 547 synchronized (mSettingsLock) { 548 if (ringerMode != mRingerMode) { 549 setRingerModeInt(ringerMode, true); 550 // Send sticky broadcast 551 broadcastRingerMode(); 552 } 553 } 554 } 555 556 private void setRingerModeInt(int ringerMode, boolean persist) { 557 mRingerMode = ringerMode; 558 559 // Mute stream if not previously muted by ringer mode and ringer mode 560 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 561 // Unmute stream if previously muted by ringer mode and ringer mode 562 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 563 int numStreamTypes = AudioSystem.getNumStreamTypes(); 564 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 565 if (isStreamMutedByRingerMode(streamType)) { 566 if (!isStreamAffectedByRingerMode(streamType) || 567 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 568 mStreamStates[streamType].mute(null, false); 569 mRingerModeMutedStreams &= ~(1 << streamType); 570 } 571 } else { 572 if (isStreamAffectedByRingerMode(streamType) && 573 mRingerMode != AudioManager.RINGER_MODE_NORMAL) { 574 mStreamStates[streamType].mute(null, true); 575 mRingerModeMutedStreams |= (1 << streamType); 576 } 577 } 578 } 579 580 // Post a persist ringer mode msg 581 if (persist) { 582 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, 583 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 584 } 585 } 586 587 /** @see AudioManager#shouldVibrate(int) */ 588 public boolean shouldVibrate(int vibrateType) { 589 590 switch (getVibrateSetting(vibrateType)) { 591 592 case AudioManager.VIBRATE_SETTING_ON: 593 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 594 595 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 596 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 597 598 case AudioManager.VIBRATE_SETTING_OFF: 599 // return false, even for incoming calls 600 return false; 601 602 default: 603 return false; 604 } 605 } 606 607 /** @see AudioManager#getVibrateSetting(int) */ 608 public int getVibrateSetting(int vibrateType) { 609 return (mVibrateSetting >> (vibrateType * 2)) & 3; 610 } 611 612 /** @see AudioManager#setVibrateSetting(int, int) */ 613 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 614 615 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 616 617 // Broadcast change 618 broadcastVibrateSetting(vibrateType); 619 620 // Post message to set ringer mode (it in turn will post a message 621 // to persist) 622 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, 623 null, 0); 624 } 625 626 /** 627 * @see #setVibrateSetting(int, int) 628 */ 629 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 630 int vibrateSetting) { 631 632 // First clear the existing setting. Each vibrate type has two bits in 633 // the value. Note '3' is '11' in binary. 634 existingValue &= ~(3 << (vibrateType * 2)); 635 636 // Set into the old value 637 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 638 639 return existingValue; 640 } 641 642 private class SetModeDeathHandler implements IBinder.DeathRecipient { 643 private IBinder mCb; // To be notified of client's death 644 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 645 646 SetModeDeathHandler(IBinder cb) { 647 mCb = cb; 648 } 649 650 public void binderDied() { 651 synchronized(mSetModeDeathHandlers) { 652 Log.w(TAG, "setMode() client died"); 653 int index = mSetModeDeathHandlers.indexOf(this); 654 if (index < 0) { 655 Log.w(TAG, "unregistered setMode() client died"); 656 } else { 657 mSetModeDeathHandlers.remove(this); 658 // If dead client was a the top of client list, 659 // apply next mode in the stack 660 if (index == 0) { 661 // mSetModeDeathHandlers is never empty as the initial entry 662 // created when AudioService starts is never removed 663 SetModeDeathHandler hdlr = mSetModeDeathHandlers.get(0); 664 int mode = hdlr.getMode(); 665 if (AudioService.this.mMode != mode) { 666 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 667 AudioService.this.mMode = mode; 668 } 669 } 670 } 671 } 672 } 673 } 674 675 public void setMode(int mode) { 676 mMode = mode; 677 } 678 679 public int getMode() { 680 return mMode; 681 } 682 683 public IBinder getBinder() { 684 return mCb; 685 } 686 } 687 688 /** @see AudioManager#setMode(int) */ 689 public void setMode(int mode, IBinder cb) { 690 if (!checkAudioSettingsPermission("setMode()")) { 691 return; 692 } 693 694 if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) { 695 return; 696 } 697 698 synchronized (mSettingsLock) { 699 if (mode == AudioSystem.MODE_CURRENT) { 700 mode = mMode; 701 } 702 if (mode != mMode) { 703 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 704 checkForUndispatchedAudioFocusChange(mMode, mode); 705 mMode = mode; 706 707 synchronized(mSetModeDeathHandlers) { 708 SetModeDeathHandler hdlr = null; 709 Iterator iter = mSetModeDeathHandlers.iterator(); 710 while (iter.hasNext()) { 711 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 712 if (h.getBinder() == cb) { 713 hdlr = h; 714 // Remove from client list so that it is re-inserted at top of list 715 iter.remove(); 716 break; 717 } 718 } 719 if (hdlr == null) { 720 hdlr = new SetModeDeathHandler(cb); 721 // cb is null when setMode() is called by AudioService constructor 722 if (cb != null) { 723 // Register for client death notification 724 try { 725 cb.linkToDeath(hdlr, 0); 726 } catch (RemoteException e) { 727 // Client has died! 728 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 729 } 730 } 731 } 732 // Last client to call setMode() is always at top of client list 733 // as required by SetModeDeathHandler.binderDied() 734 mSetModeDeathHandlers.add(0, hdlr); 735 hdlr.setMode(mode); 736 } 737 738 if (mode != AudioSystem.MODE_NORMAL) { 739 clearAllScoClients(); 740 } 741 } 742 } 743 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 744 int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; 745 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false); 746 } 747 } 748 749 /** @see AudioManager#getMode() */ 750 public int getMode() { 751 return mMode; 752 } 753 754 /** @see AudioManager#playSoundEffect(int) */ 755 public void playSoundEffect(int effectType) { 756 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 757 effectType, -1, null, 0); 758 } 759 760 /** @see AudioManager#playSoundEffect(int, float) */ 761 public void playSoundEffectVolume(int effectType, float volume) { 762 loadSoundEffects(); 763 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 764 effectType, (int) (volume * 1000), null, 0); 765 } 766 767 /** 768 * Loads samples into the soundpool. 769 * This method must be called at when sound effects are enabled 770 */ 771 public boolean loadSoundEffects() { 772 synchronized (mSoundEffectsLock) { 773 if (mSoundPool != null) { 774 return true; 775 } 776 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 777 if (mSoundPool == null) { 778 return false; 779 } 780 /* 781 * poolId table: The value -1 in this table indicates that corresponding 782 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 783 * Once loaded, the value in poolId is the sample ID and the same 784 * sample can be reused for another effect using the same file. 785 */ 786 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 787 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 788 poolId[fileIdx] = -1; 789 } 790 /* 791 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 792 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 793 * this indicates we have a valid sample loaded for this effect. 794 */ 795 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 796 // Do not load sample if this effect uses the MediaPlayer 797 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 798 continue; 799 } 800 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 801 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 802 int sampleId = mSoundPool.load(filePath, 0); 803 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 804 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 805 if (sampleId <= 0) { 806 Log.w(TAG, "Soundpool could not load file: "+filePath); 807 } 808 } else { 809 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 810 } 811 } 812 } 813 814 return true; 815 } 816 817 /** 818 * Unloads samples from the sound pool. 819 * This method can be called to free some memory when 820 * sound effects are disabled. 821 */ 822 public void unloadSoundEffects() { 823 synchronized (mSoundEffectsLock) { 824 if (mSoundPool == null) { 825 return; 826 } 827 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 828 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 829 poolId[fileIdx] = 0; 830 } 831 832 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 833 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 834 continue; 835 } 836 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 837 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 838 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 839 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 840 } 841 } 842 mSoundPool = null; 843 } 844 } 845 846 /** @see AudioManager#reloadAudioSettings() */ 847 public void reloadAudioSettings() { 848 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 849 readPersistedSettings(); 850 851 // restore volume settings 852 int numStreamTypes = AudioSystem.getNumStreamTypes(); 853 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 854 VolumeStreamState streamState = mStreamStates[streamType]; 855 856 String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; 857 String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 858 int index = Settings.System.getInt(mContentResolver, 859 settingName, 860 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 861 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 862 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 863 } else { 864 index *= 10; 865 } 866 streamState.mIndex = streamState.getValidIndex(index); 867 868 index = (index + 5) / 10; 869 index = Settings.System.getInt(mContentResolver, 870 lastAudibleSettingName, 871 (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 872 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 873 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 874 } else { 875 index *= 10; 876 } 877 streamState.mLastAudibleIndex = streamState.getValidIndex(index); 878 879 // unmute stream that was muted but is not affect by mute anymore 880 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 881 int size = streamState.mDeathHandlers.size(); 882 for (int i = 0; i < size; i++) { 883 streamState.mDeathHandlers.get(i).mMuteCount = 1; 884 streamState.mDeathHandlers.get(i).mute(false); 885 } 886 } 887 // apply stream volume 888 if (streamState.muteCount() == 0) { 889 setStreamVolumeIndex(streamType, streamState.mIndex); 890 } 891 } 892 893 // apply new ringer mode 894 setRingerModeInt(getRingerMode(), false); 895 } 896 897 /** @see AudioManager#setSpeakerphoneOn() */ 898 public void setSpeakerphoneOn(boolean on){ 899 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 900 return; 901 } 902 if (on) { 903 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER); 904 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 905 } else { 906 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 907 mForcedUseForComm = AudioSystem.FORCE_NONE; 908 } 909 } 910 911 /** @see AudioManager#isSpeakerphoneOn() */ 912 public boolean isSpeakerphoneOn() { 913 if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 914 return true; 915 } else { 916 return false; 917 } 918 } 919 920 /** @see AudioManager#setBluetoothScoOn() */ 921 public void setBluetoothScoOn(boolean on){ 922 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 923 return; 924 } 925 if (on) { 926 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO); 927 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO); 928 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 929 } else { 930 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 931 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE); 932 mForcedUseForComm = AudioSystem.FORCE_NONE; 933 } 934 } 935 936 /** @see AudioManager#isBluetoothScoOn() */ 937 public boolean isBluetoothScoOn() { 938 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 939 return true; 940 } else { 941 return false; 942 } 943 } 944 945 /** @see AudioManager#startBluetoothSco() */ 946 public void startBluetoothSco(IBinder cb){ 947 if (!checkAudioSettingsPermission("startBluetoothSco()")) { 948 return; 949 } 950 ScoClient client = getScoClient(cb); 951 client.incCount(); 952 } 953 954 /** @see AudioManager#stopBluetoothSco() */ 955 public void stopBluetoothSco(IBinder cb){ 956 if (!checkAudioSettingsPermission("stopBluetoothSco()")) { 957 return; 958 } 959 ScoClient client = getScoClient(cb); 960 client.decCount(); 961 } 962 963 private class ScoClient implements IBinder.DeathRecipient { 964 private IBinder mCb; // To be notified of client's death 965 private int mStartcount; // number of SCO connections started by this client 966 967 ScoClient(IBinder cb) { 968 mCb = cb; 969 mStartcount = 0; 970 } 971 972 public void binderDied() { 973 synchronized(mScoClients) { 974 Log.w(TAG, "SCO client died"); 975 int index = mScoClients.indexOf(this); 976 if (index < 0) { 977 Log.w(TAG, "unregistered SCO client died"); 978 } else { 979 clearCount(true); 980 mScoClients.remove(this); 981 } 982 } 983 } 984 985 public void incCount() { 986 synchronized(mScoClients) { 987 requestScoState(BluetoothHeadset.AUDIO_STATE_CONNECTED); 988 if (mStartcount == 0) { 989 try { 990 mCb.linkToDeath(this, 0); 991 } catch (RemoteException e) { 992 // client has already died! 993 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 994 } 995 } 996 mStartcount++; 997 } 998 } 999 1000 public void decCount() { 1001 synchronized(mScoClients) { 1002 if (mStartcount == 0) { 1003 Log.w(TAG, "ScoClient.decCount() already 0"); 1004 } else { 1005 mStartcount--; 1006 if (mStartcount == 0) { 1007 mCb.unlinkToDeath(this, 0); 1008 } 1009 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1010 } 1011 } 1012 } 1013 1014 public void clearCount(boolean stopSco) { 1015 synchronized(mScoClients) { 1016 mStartcount = 0; 1017 mCb.unlinkToDeath(this, 0); 1018 if (stopSco) { 1019 requestScoState(BluetoothHeadset.AUDIO_STATE_DISCONNECTED); 1020 } 1021 } 1022 } 1023 1024 public int getCount() { 1025 return mStartcount; 1026 } 1027 1028 public IBinder getBinder() { 1029 return mCb; 1030 } 1031 1032 public int totalCount() { 1033 synchronized(mScoClients) { 1034 int count = 0; 1035 int size = mScoClients.size(); 1036 for (int i = 0; i < size; i++) { 1037 count += mScoClients.get(i).getCount(); 1038 } 1039 return count; 1040 } 1041 } 1042 1043 private void requestScoState(int state) { 1044 if (totalCount() == 0 && 1045 mBluetoothHeadsetConnected && 1046 AudioService.this.mMode == AudioSystem.MODE_NORMAL) { 1047 if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) { 1048 mBluetoothHeadset.startVoiceRecognition(); 1049 } else { 1050 mBluetoothHeadset.stopVoiceRecognition(); 1051 } 1052 } 1053 } 1054 } 1055 1056 public ScoClient getScoClient(IBinder cb) { 1057 synchronized(mScoClients) { 1058 ScoClient client; 1059 int size = mScoClients.size(); 1060 for (int i = 0; i < size; i++) { 1061 client = mScoClients.get(i); 1062 if (client.getBinder() == cb) 1063 return client; 1064 } 1065 client = new ScoClient(cb); 1066 mScoClients.add(client); 1067 return client; 1068 } 1069 } 1070 1071 public void clearAllScoClients() { 1072 synchronized(mScoClients) { 1073 int size = mScoClients.size(); 1074 for (int i = 0; i < size; i++) { 1075 mScoClients.get(i).clearCount(false); 1076 } 1077 } 1078 } 1079 1080 private BluetoothHeadset.ServiceListener mBluetoothHeadsetServiceListener = 1081 new BluetoothHeadset.ServiceListener() { 1082 public void onServiceConnected() { 1083 if (mBluetoothHeadset != null && 1084 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_CONNECTED) { 1085 mBluetoothHeadsetConnected = true; 1086 } 1087 } 1088 public void onServiceDisconnected() { 1089 if (mBluetoothHeadset != null && 1090 mBluetoothHeadset.getState() == BluetoothHeadset.STATE_DISCONNECTED) { 1091 mBluetoothHeadsetConnected = false; 1092 clearAllScoClients(); 1093 } 1094 } 1095 }; 1096 1097 /////////////////////////////////////////////////////////////////////////// 1098 // Internal methods 1099 /////////////////////////////////////////////////////////////////////////// 1100 1101 /** 1102 * Checks if the adjustment should change ringer mode instead of just 1103 * adjusting volume. If so, this will set the proper ringer mode and volume 1104 * indices on the stream states. 1105 */ 1106 private boolean checkForRingerModeChange(int oldIndex, int direction) { 1107 boolean adjustVolumeIndex = true; 1108 int newRingerMode = mRingerMode; 1109 1110 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1111 // audible mode, at the bottom of the scale 1112 if (direction == AudioManager.ADJUST_LOWER 1113 && (oldIndex + 5) / 10 == 1) { 1114 // "silent mode", but which one? 1115 newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 1116 ? AudioManager.RINGER_MODE_VIBRATE 1117 : AudioManager.RINGER_MODE_SILENT; 1118 } 1119 } else { 1120 if (direction == AudioManager.ADJUST_RAISE) { 1121 // exiting silent mode 1122 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 1123 } else { 1124 // prevent last audible index to reach 0 1125 adjustVolumeIndex = false; 1126 } 1127 } 1128 1129 if (newRingerMode != mRingerMode) { 1130 setRingerMode(newRingerMode); 1131 1132 /* 1133 * If we are changing ringer modes, do not increment/decrement the 1134 * volume index. Instead, the handler for the message above will 1135 * take care of changing the index. 1136 */ 1137 adjustVolumeIndex = false; 1138 } 1139 1140 return adjustVolumeIndex; 1141 } 1142 1143 public boolean isStreamAffectedByRingerMode(int streamType) { 1144 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 1145 } 1146 1147 private boolean isStreamMutedByRingerMode(int streamType) { 1148 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 1149 } 1150 1151 public boolean isStreamAffectedByMute(int streamType) { 1152 return (mMuteAffectedStreams & (1 << streamType)) != 0; 1153 } 1154 1155 private void ensureValidDirection(int direction) { 1156 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 1157 throw new IllegalArgumentException("Bad direction " + direction); 1158 } 1159 } 1160 1161 private void ensureValidStreamType(int streamType) { 1162 if (streamType < 0 || streamType >= mStreamStates.length) { 1163 throw new IllegalArgumentException("Bad stream type " + streamType); 1164 } 1165 } 1166 1167 private int getActiveStreamType(int suggestedStreamType) { 1168 boolean isOffhook = false; 1169 try { 1170 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 1171 if (phone != null) isOffhook = phone.isOffhook(); 1172 } catch (RemoteException e) { 1173 Log.w(TAG, "Couldn't connect to phone service", e); 1174 } 1175 1176 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { 1177 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 1178 return AudioSystem.STREAM_BLUETOOTH_SCO; 1179 } else if (isOffhook || AudioSystem.isStreamActive(AudioSystem.STREAM_VOICE_CALL)) { 1180 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 1181 return AudioSystem.STREAM_VOICE_CALL; 1182 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC)) { 1183 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 1184 return AudioSystem.STREAM_MUSIC; 1185 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1186 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); 1187 return AudioSystem.STREAM_RING; 1188 } else { 1189 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 1190 return suggestedStreamType; 1191 } 1192 } 1193 1194 private void broadcastRingerMode() { 1195 // Send sticky broadcast 1196 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 1197 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); 1198 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1199 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1200 long origCallerIdentityToken = Binder.clearCallingIdentity(); 1201 mContext.sendStickyBroadcast(broadcast); 1202 Binder.restoreCallingIdentity(origCallerIdentityToken); 1203 } 1204 1205 private void broadcastVibrateSetting(int vibrateType) { 1206 // Send broadcast 1207 if (ActivityManagerNative.isSystemReady()) { 1208 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 1209 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 1210 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 1211 mContext.sendBroadcast(broadcast); 1212 } 1213 } 1214 1215 // Message helper methods 1216 private static int getMsg(int baseMsg, int streamType) { 1217 return (baseMsg & 0xffff) | streamType << 16; 1218 } 1219 1220 private static int getMsgBase(int msg) { 1221 return msg & 0xffff; 1222 } 1223 1224 private static void sendMsg(Handler handler, int baseMsg, int streamType, 1225 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 1226 int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); 1227 1228 if (existingMsgPolicy == SENDMSG_REPLACE) { 1229 handler.removeMessages(msg); 1230 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 1231 return; 1232 } 1233 1234 handler 1235 .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 1236 } 1237 1238 boolean checkAudioSettingsPermission(String method) { 1239 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 1240 == PackageManager.PERMISSION_GRANTED) { 1241 return true; 1242 } 1243 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 1244 + Binder.getCallingPid() 1245 + ", uid=" + Binder.getCallingUid(); 1246 Log.w(TAG, msg); 1247 return false; 1248 } 1249 1250 1251 /////////////////////////////////////////////////////////////////////////// 1252 // Inner classes 1253 /////////////////////////////////////////////////////////////////////////// 1254 1255 public class VolumeStreamState { 1256 private final int mStreamType; 1257 1258 private String mVolumeIndexSettingName; 1259 private String mLastAudibleVolumeIndexSettingName; 1260 private int mIndexMax; 1261 private int mIndex; 1262 private int mLastAudibleIndex; 1263 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death 1264 1265 private VolumeStreamState(String settingName, int streamType) { 1266 1267 setVolumeIndexSettingName(settingName); 1268 1269 mStreamType = streamType; 1270 1271 final ContentResolver cr = mContentResolver; 1272 mIndexMax = MAX_STREAM_VOLUME[streamType]; 1273 mIndex = Settings.System.getInt(cr, 1274 mVolumeIndexSettingName, 1275 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1276 mLastAudibleIndex = Settings.System.getInt(cr, 1277 mLastAudibleVolumeIndexSettingName, 1278 (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 1279 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 1280 mIndexMax *= 10; 1281 mIndex = getValidIndex(10 * mIndex); 1282 mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); 1283 setStreamVolumeIndex(streamType, mIndex); 1284 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 1285 } 1286 1287 public void setVolumeIndexSettingName(String settingName) { 1288 mVolumeIndexSettingName = settingName; 1289 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 1290 } 1291 1292 public boolean adjustIndex(int deltaIndex) { 1293 return setIndex(mIndex + deltaIndex * 10, true); 1294 } 1295 1296 public boolean setIndex(int index, boolean lastAudible) { 1297 int oldIndex = mIndex; 1298 mIndex = getValidIndex(index); 1299 1300 if (oldIndex != mIndex) { 1301 if (lastAudible) { 1302 mLastAudibleIndex = mIndex; 1303 } 1304 // Apply change to all streams using this one as alias 1305 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1306 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1307 if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { 1308 mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); 1309 } 1310 } 1311 return true; 1312 } else { 1313 return false; 1314 } 1315 } 1316 1317 public void setLastAudibleIndex(int index) { 1318 mLastAudibleIndex = getValidIndex(index); 1319 } 1320 1321 public void adjustLastAudibleIndex(int deltaIndex) { 1322 setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10); 1323 } 1324 1325 public int getMaxIndex() { 1326 return mIndexMax; 1327 } 1328 1329 public void mute(IBinder cb, boolean state) { 1330 VolumeDeathHandler handler = getDeathHandler(cb, state); 1331 if (handler == null) { 1332 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 1333 return; 1334 } 1335 handler.mute(state); 1336 } 1337 1338 private int getValidIndex(int index) { 1339 if (index < 0) { 1340 return 0; 1341 } else if (index > mIndexMax) { 1342 return mIndexMax; 1343 } 1344 1345 return index; 1346 } 1347 1348 private class VolumeDeathHandler implements IBinder.DeathRecipient { 1349 private IBinder mICallback; // To be notified of client's death 1350 private int mMuteCount; // Number of active mutes for this client 1351 1352 VolumeDeathHandler(IBinder cb) { 1353 mICallback = cb; 1354 } 1355 1356 public void mute(boolean state) { 1357 synchronized(mDeathHandlers) { 1358 if (state) { 1359 if (mMuteCount == 0) { 1360 // Register for client death notification 1361 try { 1362 // mICallback can be 0 if muted by AudioService 1363 if (mICallback != null) { 1364 mICallback.linkToDeath(this, 0); 1365 } 1366 mDeathHandlers.add(this); 1367 // If the stream is not yet muted by any client, set lvel to 0 1368 if (muteCount() == 0) { 1369 setIndex(0, false); 1370 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1371 VolumeStreamState.this, 0); 1372 } 1373 } catch (RemoteException e) { 1374 // Client has died! 1375 binderDied(); 1376 mDeathHandlers.notify(); 1377 return; 1378 } 1379 } else { 1380 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 1381 } 1382 mMuteCount++; 1383 } else { 1384 if (mMuteCount == 0) { 1385 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 1386 } else { 1387 mMuteCount--; 1388 if (mMuteCount == 0) { 1389 // Unregistr from client death notification 1390 mDeathHandlers.remove(this); 1391 // mICallback can be 0 if muted by AudioService 1392 if (mICallback != null) { 1393 mICallback.unlinkToDeath(this, 0); 1394 } 1395 if (muteCount() == 0) { 1396 // If the stream is not muted any more, restore it's volume if 1397 // ringer mode allows it 1398 if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1399 setIndex(mLastAudibleIndex, false); 1400 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1401 VolumeStreamState.this, 0); 1402 } 1403 } 1404 } 1405 } 1406 } 1407 mDeathHandlers.notify(); 1408 } 1409 } 1410 1411 public void binderDied() { 1412 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 1413 if (mMuteCount != 0) { 1414 // Reset all active mute requests from this client. 1415 mMuteCount = 1; 1416 mute(false); 1417 } 1418 } 1419 } 1420 1421 private int muteCount() { 1422 int count = 0; 1423 int size = mDeathHandlers.size(); 1424 for (int i = 0; i < size; i++) { 1425 count += mDeathHandlers.get(i).mMuteCount; 1426 } 1427 return count; 1428 } 1429 1430 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 1431 synchronized(mDeathHandlers) { 1432 VolumeDeathHandler handler; 1433 int size = mDeathHandlers.size(); 1434 for (int i = 0; i < size; i++) { 1435 handler = mDeathHandlers.get(i); 1436 if (cb == handler.mICallback) { 1437 return handler; 1438 } 1439 } 1440 // If this is the first mute request for this client, create a new 1441 // client death handler. Otherwise, it is an out of sequence unmute request. 1442 if (state) { 1443 handler = new VolumeDeathHandler(cb); 1444 } else { 1445 Log.w(TAG, "stream was not muted by this client"); 1446 handler = null; 1447 } 1448 return handler; 1449 } 1450 } 1451 } 1452 1453 /** Thread that handles native AudioSystem control. */ 1454 private class AudioSystemThread extends Thread { 1455 AudioSystemThread() { 1456 super("AudioService"); 1457 } 1458 1459 @Override 1460 public void run() { 1461 // Set this thread up so the handler will work on it 1462 Looper.prepare(); 1463 1464 synchronized(AudioService.this) { 1465 mAudioHandler = new AudioHandler(); 1466 1467 // Notify that the handler has been created 1468 AudioService.this.notify(); 1469 } 1470 1471 // Listen for volume change requests that are set by VolumePanel 1472 Looper.loop(); 1473 } 1474 } 1475 1476 /** Handles internal volume messages in separate volume thread. */ 1477 private class AudioHandler extends Handler { 1478 1479 private void setSystemVolume(VolumeStreamState streamState) { 1480 1481 // Adjust volume 1482 setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); 1483 1484 // Apply change to all streams using this one as alias 1485 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1486 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1487 if (streamType != streamState.mStreamType && 1488 STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { 1489 setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); 1490 } 1491 } 1492 1493 // Post a persist volume msg 1494 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, 1495 SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY); 1496 } 1497 1498 private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) { 1499 if (current) { 1500 System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, 1501 (streamState.mIndex + 5)/ 10); 1502 } 1503 if (lastAudible) { 1504 System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, 1505 (streamState.mLastAudibleIndex + 5) / 10); 1506 } 1507 } 1508 1509 private void persistRingerMode() { 1510 System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); 1511 } 1512 1513 private void persistVibrateSetting() { 1514 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 1515 } 1516 1517 private void playSoundEffect(int effectType, int volume) { 1518 synchronized (mSoundEffectsLock) { 1519 if (mSoundPool == null) { 1520 return; 1521 } 1522 float volFloat; 1523 // use STREAM_MUSIC volume attenuated by 3 dB if volume is not specified by caller 1524 if (volume < 0) { 1525 // Same linear to log conversion as in native AudioSystem::linearToLog() (AudioSystem.cpp) 1526 float dBPerStep = (float)((0.5 * 100) / MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1527 int musicVolIndex = (mStreamStates[AudioSystem.STREAM_MUSIC].mIndex + 5) / 10; 1528 float musicVoldB = dBPerStep * (musicVolIndex - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); 1529 volFloat = (float)Math.pow(10, (musicVoldB - 3)/20); 1530 } else { 1531 volFloat = (float) volume / 1000.0f; 1532 } 1533 1534 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 1535 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 1536 } else { 1537 MediaPlayer mediaPlayer = new MediaPlayer(); 1538 if (mediaPlayer != null) { 1539 try { 1540 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 1541 mediaPlayer.setDataSource(filePath); 1542 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 1543 mediaPlayer.prepare(); 1544 mediaPlayer.setVolume(volFloat, volFloat); 1545 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 1546 public void onCompletion(MediaPlayer mp) { 1547 cleanupPlayer(mp); 1548 } 1549 }); 1550 mediaPlayer.setOnErrorListener(new OnErrorListener() { 1551 public boolean onError(MediaPlayer mp, int what, int extra) { 1552 cleanupPlayer(mp); 1553 return true; 1554 } 1555 }); 1556 mediaPlayer.start(); 1557 } catch (IOException ex) { 1558 Log.w(TAG, "MediaPlayer IOException: "+ex); 1559 } catch (IllegalArgumentException ex) { 1560 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 1561 } catch (IllegalStateException ex) { 1562 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1563 } 1564 } 1565 } 1566 } 1567 } 1568 1569 private void cleanupPlayer(MediaPlayer mp) { 1570 if (mp != null) { 1571 try { 1572 mp.stop(); 1573 mp.release(); 1574 } catch (IllegalStateException ex) { 1575 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1576 } 1577 } 1578 } 1579 1580 @Override 1581 public void handleMessage(Message msg) { 1582 int baseMsgWhat = getMsgBase(msg.what); 1583 1584 switch (baseMsgWhat) { 1585 1586 case MSG_SET_SYSTEM_VOLUME: 1587 setSystemVolume((VolumeStreamState) msg.obj); 1588 break; 1589 1590 case MSG_PERSIST_VOLUME: 1591 persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0)); 1592 break; 1593 1594 case MSG_PERSIST_RINGER_MODE: 1595 persistRingerMode(); 1596 break; 1597 1598 case MSG_PERSIST_VIBRATE_SETTING: 1599 persistVibrateSetting(); 1600 break; 1601 1602 case MSG_MEDIA_SERVER_DIED: 1603 // Force creation of new IAudioflinger interface 1604 if (!mMediaServerOk) { 1605 Log.e(TAG, "Media server died."); 1606 AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC); 1607 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 1608 null, 500); 1609 } 1610 break; 1611 1612 case MSG_MEDIA_SERVER_STARTED: 1613 Log.e(TAG, "Media server started."); 1614 // Restore device connection states 1615 Set set = mConnectedDevices.entrySet(); 1616 Iterator i = set.iterator(); 1617 while(i.hasNext()){ 1618 Map.Entry device = (Map.Entry)i.next(); 1619 AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), 1620 AudioSystem.DEVICE_STATE_AVAILABLE, 1621 (String)device.getValue()); 1622 } 1623 1624 // Restore call state 1625 AudioSystem.setPhoneState(mMode); 1626 1627 // Restore forced usage for communcations and record 1628 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 1629 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 1630 1631 // Restore stream volumes 1632 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1633 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1634 int index; 1635 VolumeStreamState streamState = mStreamStates[streamType]; 1636 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 1637 if (streamState.muteCount() == 0) { 1638 index = streamState.mIndex; 1639 } else { 1640 index = 0; 1641 } 1642 setStreamVolumeIndex(streamType, index); 1643 } 1644 1645 // Restore ringer mode 1646 setRingerModeInt(getRingerMode(), false); 1647 break; 1648 1649 case MSG_PLAY_SOUND_EFFECT: 1650 playSoundEffect(msg.arg1, msg.arg2); 1651 break; 1652 1653 case MSG_BTA2DP_DOCK_TIMEOUT: 1654 // msg.obj == address of BTA2DP device 1655 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 1656 break; 1657 } 1658 } 1659 } 1660 1661 private class SettingsObserver extends ContentObserver { 1662 1663 SettingsObserver() { 1664 super(new Handler()); 1665 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1666 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 1667 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1668 Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this); 1669 } 1670 1671 @Override 1672 public void onChange(boolean selfChange) { 1673 super.onChange(selfChange); 1674 synchronized (mSettingsLock) { 1675 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 1676 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 1677 0); 1678 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 1679 /* 1680 * Ensure all stream types that should be affected by ringer mode 1681 * are in the proper state. 1682 */ 1683 mRingerModeAffectedStreams = ringerModeAffectedStreams; 1684 setRingerModeInt(getRingerMode(), false); 1685 } 1686 1687 int notificationsUseRingVolume = Settings.System.getInt(mContentResolver, 1688 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1689 1); 1690 if (notificationsUseRingVolume != mNotificationsUseRingVolume) { 1691 mNotificationsUseRingVolume = notificationsUseRingVolume; 1692 if (mNotificationsUseRingVolume == 1) { 1693 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 1694 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1695 System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]); 1696 } else { 1697 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; 1698 mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName( 1699 System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]); 1700 // Persist notification volume volume as it was not persisted while aliased to ring volume 1701 // and persist with no delay as there might be registered observers of the persisted 1702 // notification volume. 1703 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, 1704 SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0); 1705 } 1706 } 1707 } 1708 } 1709 } 1710 1711 private void makeA2dpDeviceAvailable(String address) { 1712 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1713 AudioSystem.DEVICE_STATE_AVAILABLE, 1714 address); 1715 // Reset A2DP suspend state each time a new sink is connected 1716 AudioSystem.setParameters("A2dpSuspended=false"); 1717 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 1718 address); 1719 } 1720 1721 private void makeA2dpDeviceUnavailableNow(String address) { 1722 Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 1723 mContext.sendBroadcast(noisyIntent); 1724 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1725 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1726 address); 1727 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1728 } 1729 1730 private void makeA2dpDeviceUnavailableLater(String address) { 1731 // the device will be made unavailable later, so consider it disconnected right away 1732 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1733 // send the delayed message to make the device unavailable later 1734 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 1735 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 1736 1737 } 1738 1739 private void cancelA2dpDeviceTimeout(String address) { 1740 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 1741 } 1742 1743 /** 1744 * Receiver for misc intent broadcasts the Phone app cares about. 1745 */ 1746 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 1747 @Override 1748 public void onReceive(Context context, Intent intent) { 1749 String action = intent.getAction(); 1750 1751 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 1752 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1753 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1754 int config; 1755 switch (dockState) { 1756 case Intent.EXTRA_DOCK_STATE_DESK: 1757 config = AudioSystem.FORCE_BT_DESK_DOCK; 1758 break; 1759 case Intent.EXTRA_DOCK_STATE_CAR: 1760 config = AudioSystem.FORCE_BT_CAR_DOCK; 1761 break; 1762 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 1763 default: 1764 config = AudioSystem.FORCE_NONE; 1765 } 1766 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 1767 } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) { 1768 int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 1769 BluetoothA2dp.STATE_DISCONNECTED); 1770 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1771 String address = btDevice.getAddress(); 1772 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 1773 ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); 1774 1775 if (isConnected && 1776 state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) { 1777 if (btDevice.isBluetoothDock()) { 1778 if (state == BluetoothA2dp.STATE_DISCONNECTED) { 1779 // introduction of a delay for transient disconnections of docks when 1780 // power is rapidly turned off/on, this message will be canceled if 1781 // we reconnect the dock under a preset delay 1782 makeA2dpDeviceUnavailableLater(address); 1783 // the next time isConnected is evaluated, it will be false for the dock 1784 } 1785 } else { 1786 makeA2dpDeviceUnavailableNow(address); 1787 } 1788 } else if (!isConnected && 1789 (state == BluetoothA2dp.STATE_CONNECTED || 1790 state == BluetoothA2dp.STATE_PLAYING)) { 1791 if (btDevice.isBluetoothDock()) { 1792 // this could be a reconnection after a transient disconnection 1793 cancelA2dpDeviceTimeout(address); 1794 } 1795 makeA2dpDeviceAvailable(address); 1796 } 1797 } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) { 1798 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 1799 BluetoothHeadset.STATE_ERROR); 1800 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 1801 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 1802 String address = null; 1803 if (btDevice != null) { 1804 address = btDevice.getAddress(); 1805 BluetoothClass btClass = btDevice.getBluetoothClass(); 1806 if (btClass != null) { 1807 switch (btClass.getDeviceClass()) { 1808 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 1809 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 1810 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 1811 break; 1812 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 1813 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 1814 break; 1815 } 1816 } 1817 } 1818 1819 boolean isConnected = (mConnectedDevices.containsKey(device) && 1820 ((String)mConnectedDevices.get(device)).equals(address)); 1821 1822 if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) { 1823 AudioSystem.setDeviceConnectionState(device, 1824 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1825 address); 1826 mConnectedDevices.remove(device); 1827 mBluetoothHeadsetConnected = false; 1828 clearAllScoClients(); 1829 } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) { 1830 AudioSystem.setDeviceConnectionState(device, 1831 AudioSystem.DEVICE_STATE_AVAILABLE, 1832 address); 1833 mConnectedDevices.put(new Integer(device), address); 1834 mBluetoothHeadsetConnected = true; 1835 } 1836 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1837 int state = intent.getIntExtra("state", 0); 1838 int microphone = intent.getIntExtra("microphone", 0); 1839 1840 if (microphone != 0) { 1841 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1842 if (state == 0 && isConnected) { 1843 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1844 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1845 ""); 1846 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1847 } else if (state == 1 && !isConnected) { 1848 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1849 AudioSystem.DEVICE_STATE_AVAILABLE, 1850 ""); 1851 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); 1852 } 1853 } else { 1854 boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1855 if (state == 0 && isConnected) { 1856 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1857 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1858 ""); 1859 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1860 } else if (state == 1 && !isConnected) { 1861 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1862 AudioSystem.DEVICE_STATE_AVAILABLE, 1863 ""); 1864 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); 1865 } 1866 } 1867 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 1868 int state = intent.getIntExtra(BluetoothHeadset.EXTRA_AUDIO_STATE, 1869 BluetoothHeadset.STATE_ERROR); 1870 synchronized (mScoClients) { 1871 if (!mScoClients.isEmpty()) { 1872 switch (state) { 1873 case BluetoothHeadset.AUDIO_STATE_CONNECTED: 1874 state = AudioManager.SCO_AUDIO_STATE_CONNECTED; 1875 break; 1876 case BluetoothHeadset.AUDIO_STATE_DISCONNECTED: 1877 state = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 1878 break; 1879 default: 1880 state = AudioManager.SCO_AUDIO_STATE_ERROR; 1881 break; 1882 } 1883 if (state != AudioManager.SCO_AUDIO_STATE_ERROR) { 1884 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 1885 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1886 mContext.sendStickyBroadcast(newIntent); 1887 } 1888 } 1889 } 1890 } 1891 } 1892 } 1893 1894 //========================================================================================== 1895 // AudioFocus 1896 //========================================================================================== 1897 /** 1898 * Flag to indicate that the top of the audio focus stack needs to recover focus 1899 * but hasn't been signaled yet. 1900 */ 1901 private boolean mHasUndispatchedAudioFocus = false; 1902 1903 private void checkForUndispatchedAudioFocusChange(int prevMode, int newMode) { 1904 // when exiting a call 1905 if ((prevMode == AudioSystem.MODE_IN_CALL) && (newMode != AudioSystem.MODE_IN_CALL)) { 1906 // check for undispatched remote control focus gain 1907 if (mHasUndispatchedAudioFocus) { 1908 notifyTopOfAudioFocusStack(); 1909 } 1910 } 1911 } 1912 1913 private void notifyTopOfAudioFocusStack() { 1914 // notify the top of the stack it gained focus 1915 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 1916 if (canReassignAudioFocus()) { 1917 try { 1918 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 1919 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 1920 mHasUndispatchedAudioFocus = false; 1921 } catch (RemoteException e) { 1922 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 1923 e.printStackTrace(); 1924 } 1925 } else { 1926 mHasUndispatchedAudioFocus = true; 1927 } 1928 } 1929 } 1930 1931 private static class FocusStackEntry { 1932 public int mStreamType = -1;// no stream type 1933 public boolean mIsTransportControlReceiver = false; 1934 public IAudioFocusDispatcher mFocusDispatcher = null; 1935 public IBinder mSourceRef = null; 1936 public String mClientId; 1937 public int mFocusChangeType; 1938 1939 public FocusStackEntry() { 1940 } 1941 1942 public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver, 1943 IAudioFocusDispatcher afl, IBinder source, String id) { 1944 mStreamType = streamType; 1945 mIsTransportControlReceiver = isTransportControlReceiver; 1946 mFocusDispatcher = afl; 1947 mSourceRef = source; 1948 mClientId = id; 1949 mFocusChangeType = duration; 1950 } 1951 } 1952 1953 private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 1954 1955 /** 1956 * Helper function: 1957 * Display in the log the current entries in the audio focus stack 1958 */ 1959 private void dumpFocusStack(PrintWriter pw) { 1960 pw.println("Audio Focus stack entries:"); 1961 synchronized(mFocusStack) { 1962 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1963 while(stackIterator.hasNext()) { 1964 FocusStackEntry fse = stackIterator.next(); 1965 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 1966 + " -- duration: " +fse.mFocusChangeType); 1967 } 1968 } 1969 } 1970 1971 /** 1972 * Helper function: 1973 * Remove a focus listener from the focus stack. 1974 * @param focusListenerToRemove the focus listener 1975 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 1976 * focus, notify the next item in the stack it gained focus. 1977 */ 1978 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 1979 // is the current top of the focus stack abandoning focus? (because of death or request) 1980 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 1981 { 1982 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 1983 mFocusStack.pop(); 1984 if (signal) { 1985 // notify the new top of the stack it gained focus 1986 notifyTopOfAudioFocusStack(); 1987 } 1988 } else { 1989 // focus is abandoned by a client that's not at the top of the stack, 1990 // no need to update focus. 1991 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 1992 while(stackIterator.hasNext()) { 1993 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 1994 if(fse.mClientId.equals(clientToRemove)) { 1995 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 1996 + fse.mClientId); 1997 mFocusStack.remove(fse); 1998 } 1999 } 2000 } 2001 } 2002 2003 /** 2004 * Helper function: 2005 * Remove focus listeners from the focus stack for a particular client. 2006 */ 2007 private void removeFocusStackEntryForClient(IBinder cb) { 2008 // is the owner of the audio focus part of the client to remove? 2009 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 2010 mFocusStack.peek().mSourceRef.equals(cb); 2011 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 2012 while(stackIterator.hasNext()) { 2013 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 2014 if(fse.mSourceRef.equals(cb)) { 2015 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 2016 + fse.mClientId); 2017 mFocusStack.remove(fse); 2018 } 2019 } 2020 if (isTopOfStackForClientToRemove) { 2021 // we removed an entry at the top of the stack: 2022 // notify the new top of the stack it gained focus. 2023 notifyTopOfAudioFocusStack(); 2024 } 2025 } 2026 2027 /** 2028 * Helper function: 2029 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 2030 */ 2031 private boolean canReassignAudioFocus() { 2032 // focus requests are rejected during a phone call 2033 if (getMode() == AudioSystem.MODE_IN_CALL) { 2034 Log.i(TAG, " AudioFocus can't be reassigned during a call, exiting"); 2035 return false; 2036 } 2037 return true; 2038 } 2039 2040 /** 2041 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 2042 * stack if necessary. 2043 */ 2044 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 2045 private IBinder mCb; // To be notified of client's death 2046 2047 AudioFocusDeathHandler(IBinder cb) { 2048 mCb = cb; 2049 } 2050 2051 public void binderDied() { 2052 synchronized(mFocusStack) { 2053 Log.w(TAG, " AudioFocus audio focus client died"); 2054 removeFocusStackEntryForClient(mCb); 2055 } 2056 } 2057 2058 public IBinder getBinder() { 2059 return mCb; 2060 } 2061 } 2062 2063 2064 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 2065 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 2066 IAudioFocusDispatcher fd, String clientId) { 2067 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 2068 // the main stream type for the audio focus request is currently not used. It may 2069 // potentially be used to handle multiple stream type-dependent audio focuses. 2070 2071 if ((cb == null) || !cb.pingBinder()) { 2072 Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting"); 2073 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2074 } 2075 2076 if (!canReassignAudioFocus()) { 2077 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 2078 } 2079 2080 synchronized(mFocusStack) { 2081 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 2082 // if focus is already owned by this client and the reason for acquiring the focus 2083 // hasn't changed, don't do anything 2084 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 2085 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2086 } 2087 // the reason for the audio focus request has changed: remove the current top of 2088 // stack and respond as if we had a new focus owner 2089 mFocusStack.pop(); 2090 } 2091 2092 // notify current top of stack it is losing focus 2093 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 2094 try { 2095 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 2096 -1 * focusChangeHint, // loss and gain codes are inverse of each other 2097 mFocusStack.peek().mClientId); 2098 } catch (RemoteException e) { 2099 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 2100 e.printStackTrace(); 2101 } 2102 } 2103 2104 // focus requester might already be somewhere below in the stack, remove it 2105 removeFocusStackEntry(clientId, false); 2106 2107 // push focus requester at the top of the audio focus stack 2108 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb, 2109 clientId)); 2110 }//synchronized(mFocusStack) 2111 2112 // handle the potential premature death of the new holder of the focus 2113 // (premature death == death before abandoning focus) 2114 // Register for client death notification 2115 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 2116 try { 2117 cb.linkToDeath(afdh, 0); 2118 } catch (RemoteException e) { 2119 // client has already died! 2120 Log.w(TAG, " AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 2121 } 2122 2123 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2124 } 2125 2126 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 2127 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 2128 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 2129 2130 // this will take care of notifying the new focus owner if needed 2131 synchronized(mFocusStack) { 2132 removeFocusStackEntry(clientId, true); 2133 } 2134 2135 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 2136 } 2137 2138 2139 public void unregisterAudioFocusClient(String clientId) { 2140 synchronized(mFocusStack) { 2141 removeFocusStackEntry(clientId, false); 2142 } 2143 } 2144 2145 2146 //========================================================================================== 2147 // RemoteControl 2148 //========================================================================================== 2149 /** 2150 * Receiver for media button intents. Handles the dispatching of the media button event 2151 * to one of the registered listeners, or if there was none, resumes the intent broadcast 2152 * to the rest of the system. 2153 */ 2154 private class MediaButtonBroadcastReceiver extends BroadcastReceiver { 2155 @Override 2156 public void onReceive(Context context, Intent intent) { 2157 String action = intent.getAction(); 2158 if (!Intent.ACTION_MEDIA_BUTTON.equals(action)) { 2159 return; 2160 } 2161 KeyEvent event = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 2162 if (event != null) { 2163 // if in a call or ringing, do not break the current phone app behavior 2164 // TODO modify this to let the phone app specifically get the RC focus 2165 // add modify the phone app to take advantage of the new API 2166 if ((getMode() == AudioSystem.MODE_IN_CALL) || 2167 (getMode() == AudioSystem.MODE_RINGTONE)) { 2168 return; 2169 } 2170 synchronized(mRCStack) { 2171 if (!mRCStack.empty()) { 2172 // create a new intent specifically aimed at the current registered listener 2173 Intent targetedIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 2174 targetedIntent.putExtras(intent.getExtras()); 2175 targetedIntent.setComponent(mRCStack.peek().mReceiverComponent); 2176 // trap the current broadcast 2177 abortBroadcast(); 2178 //Log.v(TAG, " Sending intent" + targetedIntent); 2179 context.sendBroadcast(targetedIntent, null); 2180 } 2181 } 2182 } 2183 } 2184 } 2185 2186 private static class RemoteControlStackEntry { 2187 public ComponentName mReceiverComponent;// always non null 2188 // TODO implement registration expiration? 2189 //public int mRegistrationTime; 2190 2191 public RemoteControlStackEntry() { 2192 } 2193 2194 public RemoteControlStackEntry(ComponentName r) { 2195 mReceiverComponent = r; 2196 } 2197 } 2198 2199 private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 2200 2201 /** 2202 * Helper function: 2203 * Display in the log the current entries in the remote control focus stack 2204 */ 2205 private void dumpRCStack(PrintWriter pw) { 2206 pw.println("Remote Control stack entries:"); 2207 synchronized(mRCStack) { 2208 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2209 while(stackIterator.hasNext()) { 2210 RemoteControlStackEntry fse = stackIterator.next(); 2211 pw.println(" receiver:" + fse.mReceiverComponent); 2212 } 2213 } 2214 } 2215 2216 /** 2217 * Helper function: 2218 * Set the new remote control receiver at the top of the RC focus stack 2219 */ 2220 private void pushMediaButtonReceiver(ComponentName newReceiver) { 2221 // already at top of stack? 2222 if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(newReceiver)) { 2223 return; 2224 } 2225 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2226 while(stackIterator.hasNext()) { 2227 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2228 if(rcse.mReceiverComponent.equals(newReceiver)) { 2229 mRCStack.remove(rcse); 2230 break; 2231 } 2232 } 2233 mRCStack.push(new RemoteControlStackEntry(newReceiver)); 2234 } 2235 2236 /** 2237 * Helper function: 2238 * Remove the remote control receiver from the RC focus stack 2239 */ 2240 private void removeMediaButtonReceiver(ComponentName newReceiver) { 2241 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 2242 while(stackIterator.hasNext()) { 2243 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 2244 if(rcse.mReceiverComponent.equals(newReceiver)) { 2245 mRCStack.remove(rcse); 2246 break; 2247 } 2248 } 2249 } 2250 2251 2252 /** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */ 2253 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 2254 Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver); 2255 2256 synchronized(mRCStack) { 2257 pushMediaButtonReceiver(eventReceiver); 2258 } 2259 } 2260 2261 /** see AudioManager.unregisterMediaButtonEventReceiver(ComponentName eventReceiver) */ 2262 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 2263 Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver); 2264 2265 synchronized(mRCStack) { 2266 removeMediaButtonReceiver(eventReceiver); 2267 } 2268 } 2269 2270 2271 @Override 2272 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2273 // TODO probably a lot more to do here than just the audio focus and remote control stacks 2274 dumpFocusStack(pw); 2275 dumpRCStack(pw); 2276 } 2277 2278 2279} 2280