AudioService.java revision 6ee9952bc20be72b9419cb653c9e2e833889a3d3
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19import android.app.ActivityManagerNative; 20import android.content.BroadcastReceiver; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.bluetooth.BluetoothA2dp; 26import android.bluetooth.BluetoothClass; 27import android.bluetooth.BluetoothDevice; 28import android.bluetooth.BluetoothIntent; 29import android.bluetooth.BluetoothHeadset; 30 31import android.content.pm.PackageManager; 32import android.database.ContentObserver; 33import android.media.MediaPlayer.OnCompletionListener; 34import android.media.MediaPlayer.OnErrorListener; 35import android.os.Binder; 36import android.os.Environment; 37import android.os.Handler; 38import android.os.IBinder; 39import android.os.Looper; 40import android.os.Message; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.Settings; 44import android.provider.Settings.System; 45import android.util.Log; 46import android.view.VolumePanel; 47import android.os.SystemProperties; 48 49import com.android.internal.telephony.ITelephony; 50 51import java.io.IOException; 52import java.util.ArrayList; 53import java.util.HashMap; 54import java.util.Iterator; 55import java.util.Map; 56import java.util.Set; 57 58 59/** 60 * The implementation of the volume manager service. 61 * <p> 62 * This implementation focuses on delivering a responsive UI. Most methods are 63 * asynchronous to external calls. For example, the task of setting a volume 64 * will update our internal state, but in a separate thread will set the system 65 * volume and later persist to the database. Similarly, setting the ringer mode 66 * will update the state and broadcast a change and in a separate thread later 67 * persist the ringer mode. 68 * 69 * @hide 70 */ 71public class AudioService extends IAudioService.Stub { 72 73 private static final String TAG = "AudioService"; 74 75 /** How long to delay before persisting a change in volume/ringer mode. */ 76 private static final int PERSIST_DELAY = 3000; 77 78 private Context mContext; 79 private ContentResolver mContentResolver; 80 81 /** The UI */ 82 private VolumePanel mVolumePanel; 83 84 // sendMsg() flags 85 /** Used when a message should be shared across all stream types. */ 86 private static final int SHARED_MSG = -1; 87 /** If the msg is already queued, replace it with this one. */ 88 private static final int SENDMSG_REPLACE = 0; 89 /** If the msg is already queued, ignore this one and leave the old. */ 90 private static final int SENDMSG_NOOP = 1; 91 /** If the msg is already queued, queue this one and leave the old. */ 92 private static final int SENDMSG_QUEUE = 2; 93 94 // AudioHandler message.whats 95 private static final int MSG_SET_SYSTEM_VOLUME = 0; 96 private static final int MSG_PERSIST_VOLUME = 1; 97 private static final int MSG_PERSIST_RINGER_MODE = 3; 98 private static final int MSG_PERSIST_VIBRATE_SETTING = 4; 99 private static final int MSG_MEDIA_SERVER_DIED = 5; 100 private static final int MSG_MEDIA_SERVER_STARTED = 6; 101 private static final int MSG_PLAY_SOUND_EFFECT = 7; 102 103 /** @see AudioSystemThread */ 104 private AudioSystemThread mAudioSystemThread; 105 /** @see AudioHandler */ 106 private AudioHandler mAudioHandler; 107 /** @see VolumeStreamState */ 108 private VolumeStreamState[] mStreamStates; 109 private SettingsObserver mSettingsObserver; 110 111 private int mMode; 112 private Object mSettingsLock = new Object(); 113 private boolean mMediaServerOk; 114 115 private SoundPool mSoundPool; 116 private Object mSoundEffectsLock = new Object(); 117 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 118 private static final int SOUND_EFFECT_VOLUME = 1000; 119 120 /* Sound effect file names */ 121 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 122 private static final String[] SOUND_EFFECT_FILES = new String[] { 123 "Effect_Tick.ogg", 124 "KeypressStandard.ogg", 125 "KeypressSpacebar.ogg", 126 "KeypressDelete.ogg", 127 "KeypressReturn.ogg" 128 }; 129 130 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 131 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 132 * uses soundpool (second column) */ 133 private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 134 {0, -1}, // FX_KEY_CLICK 135 {0, -1}, // FX_FOCUS_NAVIGATION_UP 136 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 137 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 138 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 139 {1, -1}, // FX_KEYPRESS_STANDARD 140 {2, -1}, // FX_KEYPRESS_SPACEBAR 141 {3, -1}, // FX_FOCUS_DELETE 142 {4, -1} // FX_FOCUS_RETURN 143 }; 144 145 /** @hide Maximum volume index values for audio streams */ 146 private int[] MAX_STREAM_VOLUME = new int[] { 147 5, // STREAM_VOICE_CALL 148 7, // STREAM_SYSTEM 149 7, // STREAM_RING 150 15, // STREAM_MUSIC 151 7, // STREAM_ALARM 152 7, // STREAM_NOTIFICATION 153 15, // STREAM_BLUETOOTH_SCO 154 7, // STREAM_SYSTEM_ENFORCED 155 15, // STREAM_DTMF 156 15 // STREAM_TTS 157 }; 158 /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings 159 * of another stream: This avoids multiplying the volume settings for hidden 160 * stream types that follow other stream behavior for volume settings 161 * NOTE: do not create loops in aliases! */ 162 private int[] STREAM_VOLUME_ALIAS = new int[] { 163 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 164 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM 165 AudioSystem.STREAM_RING, // STREAM_RING 166 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 167 AudioSystem.STREAM_ALARM, // STREAM_ALARM 168 AudioSystem.STREAM_NOTIFICATION, // STREAM_NOTIFICATION 169 AudioSystem.STREAM_VOICE_CALL, // STREAM_BLUETOOTH_SCO 170 AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM_ENFORCED 171 AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF 172 AudioSystem.STREAM_MUSIC // STREAM_TTS 173 }; 174 175 private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 176 public void onError(int error) { 177 switch (error) { 178 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 179 if (mMediaServerOk) { 180 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 181 null, 1500); 182 } 183 break; 184 case AudioSystem.AUDIO_STATUS_OK: 185 if (!mMediaServerOk) { 186 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, 187 null, 0); 188 } 189 break; 190 default: 191 break; 192 } 193 } 194 }; 195 196 /** 197 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 198 * {@link AudioManager#RINGER_MODE_SILENT}, or 199 * {@link AudioManager#RINGER_MODE_VIBRATE}. 200 */ 201 private int mRingerMode; 202 203 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 204 private int mRingerModeAffectedStreams; 205 206 /** @see System#MUTE_STREAMS_AFFECTED */ 207 private int mMuteAffectedStreams; 208 209 /** 210 * Has multiple bits per vibrate type to indicate the type's vibrate 211 * setting. See {@link #setVibrateSetting(int, int)}. 212 * <p> 213 * NOTE: This is not the final decision of whether vibrate is on/off for the 214 * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. 215 */ 216 private int mVibrateSetting; 217 218 /** @see System#NOTIFICATIONS_USE_RING_VOLUME */ 219 private int mNotificationsUseRingVolume; 220 221 // Broadcast receiver for device connections intent broadcasts 222 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 223 224 //TODO: use common definitions with HeadsetObserver 225 private static final int BIT_HEADSET = (1 << 0); 226 private static final int BIT_HEADSET_NO_MIC = (1 << 1); 227 private static final int BIT_TTY = (1 << 2); 228 private static final int BIT_FM_HEADSET = (1 << 3); 229 private static final int BIT_FM_SPEAKER = (1 << 4); 230 231 private int mHeadsetState; 232 233 // Devices currently connected 234 private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 235 236 // Forced device usage for communications 237 private int mForcedUseForComm; 238 239 /////////////////////////////////////////////////////////////////////////// 240 // Construction 241 /////////////////////////////////////////////////////////////////////////// 242 243 /** @hide */ 244 public AudioService(Context context) { 245 mContext = context; 246 mContentResolver = context.getContentResolver(); 247 248 // Intialized volume 249 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 250 "ro.config.vc_call_vol_steps", 251 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 252 253 mVolumePanel = new VolumePanel(context, this); 254 mSettingsObserver = new SettingsObserver(); 255 mMode = AudioSystem.MODE_NORMAL; 256 mHeadsetState = 0; 257 mForcedUseForComm = AudioSystem.FORCE_NONE; 258 createAudioSystemThread(); 259 readPersistedSettings(); 260 createStreamStates(); 261 mMediaServerOk = true; 262 AudioSystem.setErrorCallback(mAudioSystemCallback); 263 loadSoundEffects(); 264 265 // Register for device connection intent broadcasts. 266 IntentFilter intentFilter = 267 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 268 intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION); 269 intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION); 270 context.registerReceiver(mReceiver, intentFilter); 271 272 } 273 274 private void createAudioSystemThread() { 275 mAudioSystemThread = new AudioSystemThread(); 276 mAudioSystemThread.start(); 277 waitForAudioHandlerCreation(); 278 } 279 280 /** Waits for the volume handler to be created by the other thread. */ 281 private void waitForAudioHandlerCreation() { 282 synchronized(this) { 283 while (mAudioHandler == null) { 284 try { 285 // Wait for mAudioHandler to be set by the other thread 286 wait(); 287 } catch (InterruptedException e) { 288 Log.e(TAG, "Interrupted while waiting on volume handler."); 289 } 290 } 291 } 292 } 293 294 private void createStreamStates() { 295 int numStreamTypes = AudioSystem.getNumStreamTypes(); 296 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 297 298 for (int i = 0; i < numStreamTypes; i++) { 299 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i); 300 } 301 302 // Correct stream index values for streams with aliases 303 for (int i = 0; i < numStreamTypes; i++) { 304 if (STREAM_VOLUME_ALIAS[i] != i) { 305 int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i); 306 streams[i].mIndex = streams[i].getValidIndex(index); 307 setStreamVolumeIndex(i, index); 308 index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i); 309 streams[i].mLastAudibleIndex = streams[i].getValidIndex(index); 310 } 311 } 312 } 313 314 private void readPersistedSettings() { 315 final ContentResolver cr = mContentResolver; 316 317 mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 318 319 mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); 320 321 mRingerModeAffectedStreams = Settings.System.getInt(cr, 322 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 323 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 324 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 325 326 mMuteAffectedStreams = System.getInt(cr, 327 System.MUTE_STREAMS_AFFECTED, 328 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 329 330 mNotificationsUseRingVolume = System.getInt(cr, 331 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1); 332 333 if (mNotificationsUseRingVolume == 1) { 334 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 335 } 336 // Each stream will read its own persisted settings 337 338 // Broadcast the sticky intent 339 broadcastRingerMode(); 340 341 // Broadcast vibrate settings 342 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 343 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 344 } 345 346 private void setStreamVolumeIndex(int stream, int index) { 347 AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10); 348 } 349 350 private int rescaleIndex(int index, int srcStream, int dstStream) { 351 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 352 } 353 354 /////////////////////////////////////////////////////////////////////////// 355 // IPC methods 356 /////////////////////////////////////////////////////////////////////////// 357 358 /** @see AudioManager#adjustVolume(int, int) */ 359 public void adjustVolume(int direction, int flags) { 360 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 361 } 362 363 /** @see AudioManager#adjustVolume(int, int, int) */ 364 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 365 366 int streamType = getActiveStreamType(suggestedStreamType); 367 368 // Don't play sound on other streams 369 if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { 370 flags &= ~AudioManager.FLAG_PLAY_SOUND; 371 } 372 373 adjustStreamVolume(streamType, direction, flags); 374 } 375 376 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 377 public void adjustStreamVolume(int streamType, int direction, int flags) { 378 ensureValidDirection(direction); 379 ensureValidStreamType(streamType); 380 381 382 VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; 383 final int oldIndex = streamState.mIndex; 384 boolean adjustVolume = true; 385 386 // If either the client forces allowing ringer modes for this adjustment, 387 // or the stream type is one that is affected by ringer modes 388 if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 389 || streamType == AudioSystem.STREAM_RING) { 390 // Check if the ringer mode changes with this volume adjustment. If 391 // it does, it will handle adjusting the volume, so we won't below 392 adjustVolume = checkForRingerModeChange(oldIndex, direction); 393 } 394 395 if (adjustVolume && streamState.adjustIndex(direction)) { 396 // Post message to set system volume (it in turn will post a message 397 // to persist). Do not change volume if stream is muted. 398 if (streamState.muteCount() == 0) { 399 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0, 400 streamState, 0); 401 } 402 } 403 404 // UI 405 mVolumePanel.postVolumeChanged(streamType, flags); 406 // Broadcast Intent 407 sendVolumeUpdate(streamType); 408 } 409 410 /** @see AudioManager#setStreamVolume(int, int, int) */ 411 public void setStreamVolume(int streamType, int index, int flags) { 412 ensureValidStreamType(streamType); 413 index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); 414 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); 415 416 // UI, etc. 417 mVolumePanel.postVolumeChanged(streamType, flags); 418 // Broadcast Intent 419 sendVolumeUpdate(streamType); 420 } 421 422 private void sendVolumeUpdate(int streamType) { 423 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 424 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 425 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType)); 426 427 // Currently, sending the intent only when the stream is BLUETOOTH_SCO 428 if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) { 429 mContext.sendBroadcast(intent); 430 } 431 } 432 433 /** 434 * Sets the stream state's index, and posts a message to set system volume. 435 * This will not call out to the UI. Assumes a valid stream type. 436 * 437 * @param streamType Type of the stream 438 * @param index Desired volume index of the stream 439 * @param force If true, set the volume even if the desired volume is same 440 * as the current volume. 441 * @param lastAudible If true, stores new index as last audible one 442 */ 443 private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) { 444 VolumeStreamState streamState = mStreamStates[streamType]; 445 if (streamState.setIndex(index, lastAudible) || force) { 446 // Post message to set system volume (it in turn will post a message 447 // to persist). Do not change volume if stream is muted. 448 if (streamState.muteCount() == 0) { 449 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, 450 streamState, 0); 451 } 452 } 453 } 454 455 /** @see AudioManager#setStreamSolo(int, boolean) */ 456 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 457 for (int stream = 0; stream < mStreamStates.length; stream++) { 458 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 459 // Bring back last audible volume 460 mStreamStates[stream].mute(cb, state); 461 } 462 } 463 464 /** @see AudioManager#setStreamMute(int, boolean) */ 465 public void setStreamMute(int streamType, boolean state, IBinder cb) { 466 if (isStreamAffectedByMute(streamType)) { 467 mStreamStates[streamType].mute(cb, state); 468 } 469 } 470 471 /** @see AudioManager#getStreamVolume(int) */ 472 public int getStreamVolume(int streamType) { 473 ensureValidStreamType(streamType); 474 return (mStreamStates[streamType].mIndex + 5) / 10; 475 } 476 477 /** @see AudioManager#getStreamMaxVolume(int) */ 478 public int getStreamMaxVolume(int streamType) { 479 ensureValidStreamType(streamType); 480 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 481 } 482 483 /** @see AudioManager#getRingerMode() */ 484 public int getRingerMode() { 485 return mRingerMode; 486 } 487 488 /** @see AudioManager#setRingerMode(int) */ 489 public void setRingerMode(int ringerMode) { 490 synchronized (mSettingsLock) { 491 if (ringerMode != mRingerMode) { 492 setRingerModeInt(ringerMode, true); 493 // Send sticky broadcast 494 broadcastRingerMode(); 495 } 496 } 497 } 498 499 private void setRingerModeInt(int ringerMode, boolean persist) { 500 mRingerMode = ringerMode; 501 502 // Adjust volumes via posting message 503 int numStreamTypes = AudioSystem.getNumStreamTypes(); 504 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 505 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 506 if (!isStreamAffectedByRingerMode(streamType)) continue; 507 // Bring back last audible volume 508 setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, 509 false, false); 510 } 511 } else { 512 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 513 if (isStreamAffectedByRingerMode(streamType)) { 514 // Either silent or vibrate, either way volume is 0 515 setStreamVolumeInt(streamType, 0, false, false); 516 } else { 517 // restore stream volume in the case the stream changed from affected 518 // to non affected by ringer mode. Does not arm to do it for streams that 519 // are not affected as well. 520 setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex, 521 false, false); 522 } 523 } 524 } 525 526 // Post a persist ringer mode msg 527 if (persist) { 528 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, 529 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 530 } 531 } 532 533 /** @see AudioManager#shouldVibrate(int) */ 534 public boolean shouldVibrate(int vibrateType) { 535 536 switch (getVibrateSetting(vibrateType)) { 537 538 case AudioManager.VIBRATE_SETTING_ON: 539 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 540 541 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 542 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 543 544 case AudioManager.VIBRATE_SETTING_OFF: 545 // Phone ringer should always vibrate in vibrate mode 546 if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { 547 return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; 548 } 549 550 default: 551 return false; 552 } 553 } 554 555 /** @see AudioManager#getVibrateSetting(int) */ 556 public int getVibrateSetting(int vibrateType) { 557 return (mVibrateSetting >> (vibrateType * 2)) & 3; 558 } 559 560 /** @see AudioManager#setVibrateSetting(int, int) */ 561 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 562 563 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 564 565 // Broadcast change 566 broadcastVibrateSetting(vibrateType); 567 568 // Post message to set ringer mode (it in turn will post a message 569 // to persist) 570 sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, 571 null, 0); 572 } 573 574 /** 575 * @see #setVibrateSetting(int, int) 576 */ 577 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 578 int vibrateSetting) { 579 580 // First clear the existing setting. Each vibrate type has two bits in 581 // the value. Note '3' is '11' in binary. 582 existingValue &= ~(3 << (vibrateType * 2)); 583 584 // Set into the old value 585 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 586 587 return existingValue; 588 } 589 590 /** @see AudioManager#setMode(int) */ 591 public void setMode(int mode) { 592 if (!checkAudioSettingsPermission("setMode()")) { 593 return; 594 } 595 596 if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) { 597 return; 598 } 599 600 synchronized (mSettingsLock) { 601 if (mode == AudioSystem.MODE_CURRENT) { 602 mode = mMode; 603 } 604 if (mode != mMode) { 605 if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { 606 mMode = mode; 607 } 608 } 609 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 610 int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; 611 setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true); 612 } 613 } 614 615 /** @see AudioManager#getMode() */ 616 public int getMode() { 617 return mMode; 618 } 619 620 /** @see AudioManager#playSoundEffect(int) */ 621 public void playSoundEffect(int effectType) { 622 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 623 effectType, SOUND_EFFECT_VOLUME, null, 0); 624 } 625 626 /** @see AudioManager#playSoundEffect(int, float) */ 627 public void playSoundEffectVolume(int effectType, float volume) { 628 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, 629 effectType, (int) (volume * 1000), null, 0); 630 } 631 632 /** 633 * Loads samples into the soundpool. 634 * This method must be called at when sound effects are enabled 635 */ 636 public boolean loadSoundEffects() { 637 synchronized (mSoundEffectsLock) { 638 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 639 if (mSoundPool == null) { 640 return false; 641 } 642 /* 643 * poolId table: The value -1 in this table indicates that corresponding 644 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 645 * Once loaded, the value in poolId is the sample ID and the same 646 * sample can be reused for another effect using the same file. 647 */ 648 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 649 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 650 poolId[fileIdx] = -1; 651 } 652 /* 653 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 654 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 655 * this indicates we have a valid sample loaded for this effect. 656 */ 657 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 658 // Do not load sample if this effect uses the MediaPlayer 659 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 660 continue; 661 } 662 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 663 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 664 int sampleId = mSoundPool.load(filePath, 0); 665 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 666 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 667 if (sampleId <= 0) { 668 Log.w(TAG, "Soundpool could not load file: "+filePath); 669 } 670 } else { 671 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 672 } 673 } 674 } 675 676 return true; 677 } 678 679 /** 680 * Unloads samples from the sound pool. 681 * This method can be called to free some memory when 682 * sound effects are disabled. 683 */ 684 public void unloadSoundEffects() { 685 synchronized (mSoundEffectsLock) { 686 if (mSoundPool == null) { 687 return; 688 } 689 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 690 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 691 poolId[fileIdx] = 0; 692 } 693 694 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 695 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 696 continue; 697 } 698 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 699 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 700 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 701 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 702 } 703 } 704 mSoundPool = null; 705 } 706 } 707 708 /** @see AudioManager#reloadAudioSettings() */ 709 public void reloadAudioSettings() { 710 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 711 readPersistedSettings(); 712 713 // restore volume settings 714 int numStreamTypes = AudioSystem.getNumStreamTypes(); 715 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 716 VolumeStreamState streamState = mStreamStates[streamType]; 717 718 String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; 719 String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 720 int index = Settings.System.getInt(mContentResolver, 721 settingName, 722 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 723 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 724 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 725 } else { 726 index *= 10; 727 } 728 streamState.mIndex = streamState.getValidIndex(index); 729 730 index = (index + 5) / 10; 731 index = Settings.System.getInt(mContentResolver, 732 lastAudibleSettingName, 733 (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 734 if (STREAM_VOLUME_ALIAS[streamType] != streamType) { 735 index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); 736 } else { 737 index *= 10; 738 } 739 streamState.mLastAudibleIndex = streamState.getValidIndex(index); 740 741 // unmute stream that whas muted but is not affect by mute anymore 742 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 743 int size = streamState.mDeathHandlers.size(); 744 for (int i = 0; i < size; i++) { 745 streamState.mDeathHandlers.get(i).mMuteCount = 1; 746 streamState.mDeathHandlers.get(i).mute(false); 747 } 748 } 749 // apply stream volume 750 if (streamState.muteCount() == 0) { 751 setStreamVolumeIndex(streamType, streamState.mIndex); 752 } 753 } 754 755 // apply new ringer mode 756 setRingerModeInt(getRingerMode(), false); 757 } 758 759 /** @see AudioManager#setSpeakerphoneOn() */ 760 public void setSpeakerphoneOn(boolean on){ 761 if (on) { 762 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER); 763 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 764 } else { 765 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 766 mForcedUseForComm = AudioSystem.FORCE_NONE; 767 } 768 } 769 770 /** @see AudioManager#isSpeakerphoneOn() */ 771 public boolean isSpeakerphoneOn() { 772 if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 773 return true; 774 } else { 775 return false; 776 } 777 } 778 779 /** @see AudioManager#setBluetoothScoOn() */ 780 public void setBluetoothScoOn(boolean on){ 781 if (on) { 782 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO); 783 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO); 784 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 785 } else { 786 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE); 787 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE); 788 mForcedUseForComm = AudioSystem.FORCE_NONE; 789 } 790 } 791 792 /** @see AudioManager#isBluetoothScoOn() */ 793 public boolean isBluetoothScoOn() { 794 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 795 return true; 796 } else { 797 return false; 798 } 799 } 800 801 /////////////////////////////////////////////////////////////////////////// 802 // Internal methods 803 /////////////////////////////////////////////////////////////////////////// 804 805 /** 806 * Checks if the adjustment should change ringer mode instead of just 807 * adjusting volume. If so, this will set the proper ringer mode and volume 808 * indices on the stream states. 809 */ 810 private boolean checkForRingerModeChange(int oldIndex, int direction) { 811 boolean adjustVolumeIndex = true; 812 int newRingerMode = mRingerMode; 813 814 if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && (oldIndex + 5) / 10 == 1 815 && direction == AudioManager.ADJUST_LOWER) { 816 newRingerMode = AudioManager.RINGER_MODE_VIBRATE; 817 } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { 818 if (direction == AudioManager.ADJUST_RAISE) { 819 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 820 } else if (direction == AudioManager.ADJUST_LOWER) { 821 newRingerMode = AudioManager.RINGER_MODE_SILENT; 822 } 823 } else if (direction == AudioManager.ADJUST_RAISE 824 && mRingerMode == AudioManager.RINGER_MODE_SILENT) { 825 newRingerMode = AudioManager.RINGER_MODE_VIBRATE; 826 } 827 828 if (newRingerMode != mRingerMode) { 829 setRingerMode(newRingerMode); 830 831 /* 832 * If we are changing ringer modes, do not increment/decrement the 833 * volume index. Instead, the handler for the message above will 834 * take care of changing the index. 835 */ 836 adjustVolumeIndex = false; 837 } 838 839 return adjustVolumeIndex; 840 } 841 842 public boolean isStreamAffectedByRingerMode(int streamType) { 843 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 844 } 845 846 public boolean isStreamAffectedByMute(int streamType) { 847 return (mMuteAffectedStreams & (1 << streamType)) != 0; 848 } 849 850 private void ensureValidDirection(int direction) { 851 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 852 throw new IllegalArgumentException("Bad direction " + direction); 853 } 854 } 855 856 private void ensureValidStreamType(int streamType) { 857 if (streamType < 0 || streamType >= mStreamStates.length) { 858 throw new IllegalArgumentException("Bad stream type " + streamType); 859 } 860 } 861 862 private int getActiveStreamType(int suggestedStreamType) { 863 boolean isOffhook = false; 864 try { 865 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 866 if (phone != null) isOffhook = phone.isOffhook(); 867 } catch (RemoteException e) { 868 Log.w(TAG, "Couldn't connect to phone service", e); 869 } 870 871 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) { 872 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 873 return AudioSystem.STREAM_BLUETOOTH_SCO; 874 } else if (isOffhook) { 875 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 876 return AudioSystem.STREAM_VOICE_CALL; 877 } else if (AudioSystem.isMusicActive()) { 878 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 879 return AudioSystem.STREAM_MUSIC; 880 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 881 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); 882 return AudioSystem.STREAM_RING; 883 } else { 884 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 885 return suggestedStreamType; 886 } 887 } 888 889 private void broadcastRingerMode() { 890 // Send sticky broadcast 891 if (ActivityManagerNative.isSystemReady()) { 892 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 893 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); 894 long origCallerIdentityToken = Binder.clearCallingIdentity(); 895 mContext.sendStickyBroadcast(broadcast); 896 Binder.restoreCallingIdentity(origCallerIdentityToken); 897 } 898 } 899 900 private void broadcastVibrateSetting(int vibrateType) { 901 // Send broadcast 902 if (ActivityManagerNative.isSystemReady()) { 903 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 904 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 905 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 906 mContext.sendBroadcast(broadcast); 907 } 908 } 909 910 // Message helper methods 911 private static int getMsg(int baseMsg, int streamType) { 912 return (baseMsg & 0xffff) | streamType << 16; 913 } 914 915 private static int getMsgBase(int msg) { 916 return msg & 0xffff; 917 } 918 919 private static void sendMsg(Handler handler, int baseMsg, int streamType, 920 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 921 int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); 922 923 if (existingMsgPolicy == SENDMSG_REPLACE) { 924 handler.removeMessages(msg); 925 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 926 return; 927 } 928 929 handler 930 .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 931 } 932 933 boolean checkAudioSettingsPermission(String method) { 934 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 935 == PackageManager.PERMISSION_GRANTED) { 936 return true; 937 } 938 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 939 + Binder.getCallingPid() 940 + ", uid=" + Binder.getCallingUid(); 941 Log.w(TAG, msg); 942 return false; 943 } 944 945 946 /////////////////////////////////////////////////////////////////////////// 947 // Inner classes 948 /////////////////////////////////////////////////////////////////////////// 949 950 public class VolumeStreamState { 951 private final String mVolumeIndexSettingName; 952 private final String mLastAudibleVolumeIndexSettingName; 953 private final int mStreamType; 954 955 private int mIndexMax; 956 private int mIndex; 957 private int mLastAudibleIndex; 958 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death 959 960 private VolumeStreamState(String settingName, int streamType) { 961 962 mVolumeIndexSettingName = settingName; 963 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 964 965 mStreamType = streamType; 966 967 final ContentResolver cr = mContentResolver; 968 mIndexMax = MAX_STREAM_VOLUME[streamType]; 969 mIndex = Settings.System.getInt(cr, 970 mVolumeIndexSettingName, 971 AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 972 mLastAudibleIndex = Settings.System.getInt(cr, 973 mLastAudibleVolumeIndexSettingName, 974 (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); 975 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 976 mIndexMax *= 10; 977 mIndex = getValidIndex(10 * mIndex); 978 mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); 979 setStreamVolumeIndex(streamType, mIndex); 980 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 981 } 982 983 public boolean adjustIndex(int deltaIndex) { 984 return setIndex(mIndex + deltaIndex * 10, true); 985 } 986 987 public boolean setIndex(int index, boolean lastAudible) { 988 int oldIndex = mIndex; 989 mIndex = getValidIndex(index); 990 991 if (oldIndex != mIndex) { 992 if (lastAudible) { 993 mLastAudibleIndex = mIndex; 994 } 995 // Apply change to all streams using this one as alias 996 int numStreamTypes = AudioSystem.getNumStreamTypes(); 997 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 998 if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { 999 mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); 1000 } 1001 } 1002 return true; 1003 } else { 1004 return false; 1005 } 1006 } 1007 1008 public int getMaxIndex() { 1009 return mIndexMax; 1010 } 1011 1012 public void mute(IBinder cb, boolean state) { 1013 VolumeDeathHandler handler = getDeathHandler(cb, state); 1014 if (handler == null) { 1015 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 1016 return; 1017 } 1018 handler.mute(state); 1019 } 1020 1021 private int getValidIndex(int index) { 1022 if (index < 0) { 1023 return 0; 1024 } else if (index > mIndexMax) { 1025 return mIndexMax; 1026 } 1027 1028 return index; 1029 } 1030 1031 private class VolumeDeathHandler implements IBinder.DeathRecipient { 1032 private IBinder mICallback; // To be notified of client's death 1033 private int mMuteCount; // Number of active mutes for this client 1034 1035 VolumeDeathHandler(IBinder cb) { 1036 mICallback = cb; 1037 } 1038 1039 public void mute(boolean state) { 1040 synchronized(mDeathHandlers) { 1041 if (state) { 1042 if (mMuteCount == 0) { 1043 // Register for client death notification 1044 try { 1045 mICallback.linkToDeath(this, 0); 1046 mDeathHandlers.add(this); 1047 // If the stream is not yet muted by any client, set lvel to 0 1048 if (muteCount() == 0) { 1049 setIndex(0, false); 1050 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1051 VolumeStreamState.this, 0); 1052 } 1053 } catch (RemoteException e) { 1054 // Client has died! 1055 binderDied(); 1056 mDeathHandlers.notify(); 1057 return; 1058 } 1059 } else { 1060 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 1061 } 1062 mMuteCount++; 1063 } else { 1064 if (mMuteCount == 0) { 1065 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 1066 } else { 1067 mMuteCount--; 1068 if (mMuteCount == 0) { 1069 // Unregistr from client death notification 1070 mDeathHandlers.remove(this); 1071 mICallback.unlinkToDeath(this, 0); 1072 if (muteCount() == 0) { 1073 // If the stream is not mut any more, restore it's volume if 1074 // ringer mode allows it 1075 if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 1076 setIndex(mLastAudibleIndex, false); 1077 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, 1078 VolumeStreamState.this, 0); 1079 } 1080 } 1081 } 1082 } 1083 } 1084 mDeathHandlers.notify(); 1085 } 1086 } 1087 1088 public void binderDied() { 1089 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 1090 if (mMuteCount != 0) { 1091 // Reset all active mute requests from this client. 1092 mMuteCount = 1; 1093 mute(false); 1094 } 1095 } 1096 } 1097 1098 private int muteCount() { 1099 int count = 0; 1100 int size = mDeathHandlers.size(); 1101 for (int i = 0; i < size; i++) { 1102 count += mDeathHandlers.get(i).mMuteCount; 1103 } 1104 return count; 1105 } 1106 1107 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 1108 synchronized(mDeathHandlers) { 1109 VolumeDeathHandler handler; 1110 int size = mDeathHandlers.size(); 1111 for (int i = 0; i < size; i++) { 1112 handler = mDeathHandlers.get(i); 1113 if (cb.equals(handler.mICallback)) { 1114 return handler; 1115 } 1116 } 1117 // If this is the first mute request for this client, create a new 1118 // client death handler. Otherwise, it is an out of sequence unmute request. 1119 if (state) { 1120 handler = new VolumeDeathHandler(cb); 1121 } else { 1122 Log.w(TAG, "stream was not muted by this client"); 1123 handler = null; 1124 } 1125 return handler; 1126 } 1127 } 1128 } 1129 1130 /** Thread that handles native AudioSystem control. */ 1131 private class AudioSystemThread extends Thread { 1132 AudioSystemThread() { 1133 super("AudioService"); 1134 } 1135 1136 @Override 1137 public void run() { 1138 // Set this thread up so the handler will work on it 1139 Looper.prepare(); 1140 1141 synchronized(AudioService.this) { 1142 mAudioHandler = new AudioHandler(); 1143 1144 // Notify that the handler has been created 1145 AudioService.this.notify(); 1146 } 1147 1148 // Listen for volume change requests that are set by VolumePanel 1149 Looper.loop(); 1150 } 1151 } 1152 1153 /** Handles internal volume messages in separate volume thread. */ 1154 private class AudioHandler extends Handler { 1155 1156 private void setSystemVolume(VolumeStreamState streamState) { 1157 1158 // Adjust volume 1159 setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); 1160 1161 // Apply change to all streams using this one as alias 1162 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1163 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1164 if (streamType != streamState.mStreamType && 1165 STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { 1166 setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); 1167 } 1168 } 1169 1170 // Post a persist volume msg 1171 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, 1172 SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY); 1173 } 1174 1175 private void persistVolume(VolumeStreamState streamState) { 1176 System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, 1177 (streamState.mIndex + 5)/ 10); 1178 System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, 1179 (streamState.mLastAudibleIndex + 5) / 10); 1180 } 1181 1182 private void persistRingerMode() { 1183 System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); 1184 } 1185 1186 private void persistVibrateSetting() { 1187 System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); 1188 } 1189 1190 private void playSoundEffect(int effectType, int volume) { 1191 synchronized (mSoundEffectsLock) { 1192 if (mSoundPool == null) { 1193 return; 1194 } 1195 1196 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 1197 float v = (float) volume / 1000.0f; 1198 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f); 1199 } else { 1200 MediaPlayer mediaPlayer = new MediaPlayer(); 1201 if (mediaPlayer != null) { 1202 try { 1203 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 1204 mediaPlayer.setDataSource(filePath); 1205 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 1206 mediaPlayer.prepare(); 1207 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 1208 public void onCompletion(MediaPlayer mp) { 1209 cleanupPlayer(mp); 1210 } 1211 }); 1212 mediaPlayer.setOnErrorListener(new OnErrorListener() { 1213 public boolean onError(MediaPlayer mp, int what, int extra) { 1214 cleanupPlayer(mp); 1215 return true; 1216 } 1217 }); 1218 mediaPlayer.start(); 1219 } catch (IOException ex) { 1220 Log.w(TAG, "MediaPlayer IOException: "+ex); 1221 } catch (IllegalArgumentException ex) { 1222 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 1223 } catch (IllegalStateException ex) { 1224 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1225 } 1226 } 1227 } 1228 } 1229 } 1230 1231 private void cleanupPlayer(MediaPlayer mp) { 1232 if (mp != null) { 1233 try { 1234 mp.stop(); 1235 mp.release(); 1236 } catch (IllegalStateException ex) { 1237 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 1238 } 1239 } 1240 } 1241 1242 @Override 1243 public void handleMessage(Message msg) { 1244 int baseMsgWhat = getMsgBase(msg.what); 1245 1246 switch (baseMsgWhat) { 1247 1248 case MSG_SET_SYSTEM_VOLUME: 1249 setSystemVolume((VolumeStreamState) msg.obj); 1250 break; 1251 1252 case MSG_PERSIST_VOLUME: 1253 persistVolume((VolumeStreamState) msg.obj); 1254 break; 1255 1256 case MSG_PERSIST_RINGER_MODE: 1257 persistRingerMode(); 1258 break; 1259 1260 case MSG_PERSIST_VIBRATE_SETTING: 1261 persistVibrateSetting(); 1262 break; 1263 1264 case MSG_MEDIA_SERVER_DIED: 1265 Log.e(TAG, "Media server died."); 1266 // Force creation of new IAudioflinger interface 1267 mMediaServerOk = false; 1268 AudioSystem.isMusicActive(); 1269 break; 1270 1271 case MSG_MEDIA_SERVER_STARTED: 1272 Log.e(TAG, "Media server started."); 1273 // Restore device connection states 1274 Set set = mConnectedDevices.entrySet(); 1275 Iterator i = set.iterator(); 1276 while(i.hasNext()){ 1277 Map.Entry device = (Map.Entry)i.next(); 1278 AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(), 1279 AudioSystem.DEVICE_STATE_AVAILABLE, 1280 (String)device.getValue()); 1281 } 1282 1283 // Restore call state 1284 AudioSystem.setPhoneState(mMode); 1285 1286 // Restore forced usage for communcations and record 1287 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 1288 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 1289 1290 // Restore stream volumes 1291 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1292 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1293 int index; 1294 VolumeStreamState streamState = mStreamStates[streamType]; 1295 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 1296 if (streamState.muteCount() == 0) { 1297 index = streamState.mIndex; 1298 } else { 1299 index = 0; 1300 } 1301 setStreamVolumeIndex(streamType, index); 1302 } 1303 1304 // Restore ringer mode 1305 setRingerModeInt(getRingerMode(), false); 1306 1307 mMediaServerOk = true; 1308 break; 1309 1310 case MSG_PLAY_SOUND_EFFECT: 1311 playSoundEffect(msg.arg1, msg.arg2); 1312 break; 1313 } 1314 } 1315 } 1316 1317 private class SettingsObserver extends ContentObserver { 1318 1319 SettingsObserver() { 1320 super(new Handler()); 1321 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1322 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 1323 mContentResolver.registerContentObserver(Settings.System.getUriFor( 1324 Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this); 1325 } 1326 1327 @Override 1328 public void onChange(boolean selfChange) { 1329 super.onChange(selfChange); 1330 synchronized (mSettingsLock) { 1331 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 1332 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 1333 0); 1334 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 1335 /* 1336 * Ensure all stream types that should be affected by ringer mode 1337 * are in the proper state. 1338 */ 1339 mRingerModeAffectedStreams = ringerModeAffectedStreams; 1340 setRingerModeInt(getRingerMode(), false); 1341 } 1342 1343 int notificationsUseRingVolume = Settings.System.getInt(mContentResolver, 1344 Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1345 1); 1346 if (notificationsUseRingVolume != mNotificationsUseRingVolume) { 1347 mNotificationsUseRingVolume = notificationsUseRingVolume; 1348 if (mNotificationsUseRingVolume == 1) { 1349 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING; 1350 } else { 1351 STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; 1352 // Persist notification volume volume as it was not persisted while aliased to ring volume 1353 sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION, 1354 SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY); 1355 } 1356 } 1357 } 1358 } 1359 } 1360 1361 /** 1362 * Receiver for misc intent broadcasts the Phone app cares about. 1363 */ 1364 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 1365 @Override 1366 public void onReceive(Context context, Intent intent) { 1367 String action = intent.getAction(); 1368 1369 if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) { 1370 int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE, 1371 BluetoothA2dp.STATE_DISCONNECTED); 1372 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE); 1373 String address = btDevice.getAddress(); 1374 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 1375 ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address)); 1376 1377 if (isConnected && 1378 state != BluetoothA2dp.STATE_CONNECTED && state != BluetoothA2dp.STATE_PLAYING) { 1379 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1380 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1381 address); 1382 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 1383 } else if (!isConnected && 1384 (state == BluetoothA2dp.STATE_CONNECTED || state != BluetoothA2dp.STATE_PLAYING)){ 1385 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 1386 AudioSystem.DEVICE_STATE_AVAILABLE, 1387 address); 1388 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 1389 address); 1390 } 1391 } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) { 1392 int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE, 1393 BluetoothHeadset.STATE_ERROR); 1394 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 1395 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE); 1396 String address = null; 1397 int btClass = BluetoothClass.ERROR; 1398 if (btDevice != null) { 1399 address = btDevice.getAddress(); 1400 btClass = btDevice.getBluetoothClass(); 1401 if (BluetoothClass.Device.Major.getDeviceMajor(btClass) == 1402 BluetoothClass.Device.Major.AUDIO_VIDEO) { 1403 switch (BluetoothClass.Device.getDevice(btClass)) { 1404 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 1405 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 1406 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 1407 break; 1408 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 1409 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 1410 break; 1411 default: 1412 break; 1413 } 1414 } 1415 } 1416 1417 boolean isConnected = (mConnectedDevices.containsKey(device) && 1418 ((String)mConnectedDevices.get(device)).equals(address)); 1419 1420 if (isConnected && state != BluetoothHeadset.STATE_CONNECTED) { 1421 AudioSystem.setDeviceConnectionState(device, 1422 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1423 address); 1424 mConnectedDevices.remove(device); 1425 } else if (!isConnected && state == BluetoothHeadset.STATE_CONNECTED) { 1426 AudioSystem.setDeviceConnectionState(device, 1427 AudioSystem.DEVICE_STATE_AVAILABLE, 1428 address); 1429 mConnectedDevices.put(new Integer(device), address); 1430 } 1431 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 1432 int state = intent.getIntExtra("state", 0); 1433 if ((state & BIT_HEADSET) == 0 && 1434 (mHeadsetState & BIT_HEADSET) != 0) { 1435 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1436 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1437 ""); 1438 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET); 1439 } else if ((state & BIT_HEADSET) != 0 && 1440 (mHeadsetState & BIT_HEADSET) == 0) { 1441 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, 1442 AudioSystem.DEVICE_STATE_AVAILABLE, 1443 ""); 1444 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), ""); 1445 } 1446 if ((state & BIT_HEADSET_NO_MIC) == 0 && 1447 (mHeadsetState & BIT_HEADSET_NO_MIC) != 0) { 1448 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1449 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1450 ""); 1451 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); 1452 } else if ((state & BIT_HEADSET_NO_MIC) != 0 && 1453 (mHeadsetState & BIT_HEADSET_NO_MIC) == 0) { 1454 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, 1455 AudioSystem.DEVICE_STATE_AVAILABLE, 1456 ""); 1457 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), ""); 1458 } 1459 if ((state & BIT_TTY) == 0 && 1460 (mHeadsetState & BIT_TTY) != 0) { 1461 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY, 1462 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1463 ""); 1464 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY); 1465 } else if ((state & BIT_TTY) != 0 && 1466 (mHeadsetState & BIT_TTY) == 0) { 1467 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY, 1468 AudioSystem.DEVICE_STATE_AVAILABLE, 1469 ""); 1470 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), ""); 1471 } 1472 if ((state & BIT_FM_HEADSET) == 0 && 1473 (mHeadsetState & BIT_FM_HEADSET) != 0) { 1474 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE, 1475 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1476 ""); 1477 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE); 1478 } else if ((state & BIT_FM_HEADSET) != 0 && 1479 (mHeadsetState & BIT_FM_HEADSET) == 0) { 1480 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE, 1481 AudioSystem.DEVICE_STATE_AVAILABLE, 1482 ""); 1483 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), ""); 1484 } 1485 if ((state & BIT_FM_SPEAKER) == 0 && 1486 (mHeadsetState & BIT_FM_SPEAKER) != 0) { 1487 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, 1488 AudioSystem.DEVICE_STATE_UNAVAILABLE, 1489 ""); 1490 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER); 1491 } else if ((state & BIT_FM_SPEAKER) != 0 && 1492 (mHeadsetState & BIT_FM_SPEAKER) == 0) { 1493 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER, 1494 AudioSystem.DEVICE_STATE_AVAILABLE, 1495 ""); 1496 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), ""); 1497 } 1498 mHeadsetState = state; 1499 } 1500 } 1501 } 1502} 1503