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