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