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