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