AudioService.java revision 3172d5e3e7520a745fa37b71fc1c7bf244b57085
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 static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK; 20import static android.media.AudioManager.RINGER_MODE_NORMAL; 21import static android.media.AudioManager.RINGER_MODE_SILENT; 22import static android.media.AudioManager.RINGER_MODE_VIBRATE; 23 24import android.app.Activity; 25import android.app.ActivityManagerNative; 26import android.app.KeyguardManager; 27import android.app.PendingIntent; 28import android.app.PendingIntent.CanceledException; 29import android.app.PendingIntent.OnFinished; 30import android.bluetooth.BluetoothA2dp; 31import android.bluetooth.BluetoothAdapter; 32import android.bluetooth.BluetoothClass; 33import android.bluetooth.BluetoothDevice; 34import android.bluetooth.BluetoothHeadset; 35import android.bluetooth.BluetoothProfile; 36import android.content.BroadcastReceiver; 37import android.content.ComponentName; 38import android.content.ContentResolver; 39import android.content.Context; 40import android.content.Intent; 41import android.content.IntentFilter; 42import android.content.pm.PackageManager; 43import android.content.res.Configuration; 44import android.database.ContentObserver; 45import android.media.MediaPlayer.OnCompletionListener; 46import android.media.MediaPlayer.OnErrorListener; 47import android.os.Binder; 48import android.os.Bundle; 49import android.os.Environment; 50import android.os.Handler; 51import android.os.IBinder; 52import android.os.Looper; 53import android.os.Message; 54import android.os.PowerManager; 55import android.os.RemoteException; 56import android.os.ServiceManager; 57import android.os.SystemProperties; 58import android.os.Vibrator; 59import android.provider.Settings; 60import android.provider.Settings.System; 61import android.telephony.PhoneStateListener; 62import android.telephony.TelephonyManager; 63import android.util.Log; 64import android.view.KeyEvent; 65import android.view.VolumePanel; 66 67import com.android.internal.telephony.ITelephony; 68 69import java.io.FileDescriptor; 70import java.io.IOException; 71import java.io.PrintWriter; 72import java.util.ArrayList; 73import java.util.concurrent.ConcurrentHashMap; 74import java.util.HashMap; 75import java.util.Iterator; 76import java.util.List; 77import java.util.Map; 78import java.util.NoSuchElementException; 79import java.util.Set; 80import java.util.Stack; 81 82/** 83 * The implementation of the volume manager service. 84 * <p> 85 * This implementation focuses on delivering a responsive UI. Most methods are 86 * asynchronous to external calls. For example, the task of setting a volume 87 * will update our internal state, but in a separate thread will set the system 88 * volume and later persist to the database. Similarly, setting the ringer mode 89 * will update the state and broadcast a change and in a separate thread later 90 * persist the ringer mode. 91 * 92 * @hide 93 */ 94public class AudioService extends IAudioService.Stub implements OnFinished { 95 96 private static final String TAG = "AudioService"; 97 98 /** Debug remote control client/display feature */ 99 protected static final boolean DEBUG_RC = false; 100 101 /** How long to delay before persisting a change in volume/ringer mode. */ 102 private static final int PERSIST_DELAY = 500; 103 104 private Context mContext; 105 private ContentResolver mContentResolver; 106 private boolean mVoiceCapable; 107 108 /** The UI */ 109 private VolumePanel mVolumePanel; 110 111 // sendMsg() flags 112 /** If the msg is already queued, replace it with this one. */ 113 private static final int SENDMSG_REPLACE = 0; 114 /** If the msg is already queued, ignore this one and leave the old. */ 115 private static final int SENDMSG_NOOP = 1; 116 /** If the msg is already queued, queue this one and leave the old. */ 117 private static final int SENDMSG_QUEUE = 2; 118 119 // AudioHandler message.whats 120 private static final int MSG_SET_DEVICE_VOLUME = 0; 121 private static final int MSG_PERSIST_VOLUME = 1; 122 private static final int MSG_PERSIST_MASTER_VOLUME = 2; 123 private static final int MSG_PERSIST_RINGER_MODE = 3; 124 private static final int MSG_MEDIA_SERVER_DIED = 4; 125 private static final int MSG_MEDIA_SERVER_STARTED = 5; 126 private static final int MSG_PLAY_SOUND_EFFECT = 6; 127 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7; 128 private static final int MSG_LOAD_SOUND_EFFECTS = 8; 129 private static final int MSG_SET_FORCE_USE = 9; 130 private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10; 131 private static final int MSG_BT_HEADSET_CNCT_FAILED = 11; 132 private static final int MSG_RCDISPLAY_CLEAR = 12; 133 private static final int MSG_RCDISPLAY_UPDATE = 13; 134 private static final int MSG_SET_ALL_VOLUMES = 14; 135 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15; 136 137 138 // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be 139 // persisted 140 private static final int PERSIST_CURRENT = 0x1; 141 private static final int PERSIST_LAST_AUDIBLE = 0x2; 142 143 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 144 // Timeout for connection to bluetooth headset service 145 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 146 147 /** @see AudioSystemThread */ 148 private AudioSystemThread mAudioSystemThread; 149 /** @see AudioHandler */ 150 private AudioHandler mAudioHandler; 151 /** @see VolumeStreamState */ 152 private VolumeStreamState[] mStreamStates; 153 private SettingsObserver mSettingsObserver; 154 155 private int mMode; 156 // protects mRingerMode 157 private final Object mSettingsLock = new Object(); 158 159 private boolean mMediaServerOk; 160 161 private SoundPool mSoundPool; 162 private final Object mSoundEffectsLock = new Object(); 163 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 164 private static final int SOUND_EFFECT_VOLUME = 1000; 165 166 // Internally master volume is a float in the 0.0 - 1.0 range, 167 // but to support integer based AudioManager API we translate it to 0 - 100 168 private static final int MAX_MASTER_VOLUME = 100; 169 170 // Maximum volume adjust steps allowed in a single batch call. 171 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 172 173 /* Sound effect file names */ 174 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 175 private static final String[] SOUND_EFFECT_FILES = new String[] { 176 "Effect_Tick.ogg", 177 "KeypressStandard.ogg", 178 "KeypressSpacebar.ogg", 179 "KeypressDelete.ogg", 180 "KeypressReturn.ogg" 181 }; 182 183 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 184 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 185 * uses soundpool (second column) */ 186 private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 187 {0, -1}, // FX_KEY_CLICK 188 {0, -1}, // FX_FOCUS_NAVIGATION_UP 189 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 190 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 191 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 192 {1, -1}, // FX_KEYPRESS_STANDARD 193 {2, -1}, // FX_KEYPRESS_SPACEBAR 194 {3, -1}, // FX_FOCUS_DELETE 195 {4, -1} // FX_FOCUS_RETURN 196 }; 197 198 /** @hide Maximum volume index values for audio streams */ 199 private final int[] MAX_STREAM_VOLUME = new int[] { 200 5, // STREAM_VOICE_CALL 201 7, // STREAM_SYSTEM 202 7, // STREAM_RING 203 15, // STREAM_MUSIC 204 7, // STREAM_ALARM 205 7, // STREAM_NOTIFICATION 206 15, // STREAM_BLUETOOTH_SCO 207 7, // STREAM_SYSTEM_ENFORCED 208 15, // STREAM_DTMF 209 15 // STREAM_TTS 210 }; 211 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 212 * of another stream: This avoids multiplying the volume settings for hidden 213 * stream types that follow other stream behavior for volume settings 214 * NOTE: do not create loops in aliases! 215 * Some streams alias to different streams according to device category (phone or tablet) or 216 * use case (in call s off call...).See updateStreamVolumeAlias() for more details 217 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 218 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 219 private final int[] STREAM_VOLUME_ALIAS = new int[] { 220 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 221 AudioSystem.STREAM_RING, // STREAM_SYSTEM 222 AudioSystem.STREAM_RING, // STREAM_RING 223 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 224 AudioSystem.STREAM_ALARM, // STREAM_ALARM 225 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 226 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 227 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 228 AudioSystem.STREAM_RING, // STREAM_DTMF 229 AudioSystem.STREAM_MUSIC // STREAM_TTS 230 }; 231 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 232 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 233 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 234 AudioSystem.STREAM_RING, // STREAM_RING 235 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 236 AudioSystem.STREAM_ALARM, // STREAM_ALARM 237 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 238 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 239 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 240 AudioSystem.STREAM_MUSIC, // STREAM_DTMF 241 AudioSystem.STREAM_MUSIC // STREAM_TTS 242 }; 243 private int[] mStreamVolumeAlias; 244 245 // stream names used by dumpStreamStates() 246 private final String[] STREAM_NAMES = new String[] { 247 "STREAM_VOICE_CALL", 248 "STREAM_SYSTEM", 249 "STREAM_RING", 250 "STREAM_MUSIC", 251 "STREAM_ALARM", 252 "STREAM_NOTIFICATION", 253 "STREAM_BLUETOOTH_SCO", 254 "STREAM_SYSTEM_ENFORCED", 255 "STREAM_DTMF", 256 "STREAM_TTS" 257 }; 258 259 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 260 public void onError(int error) { 261 switch (error) { 262 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 263 if (mMediaServerOk) { 264 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 265 null, 1500); 266 mMediaServerOk = false; 267 } 268 break; 269 case AudioSystem.AUDIO_STATUS_OK: 270 if (!mMediaServerOk) { 271 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 272 null, 0); 273 mMediaServerOk = true; 274 } 275 break; 276 default: 277 break; 278 } 279 } 280 }; 281 282 /** 283 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 284 * {@link AudioManager#RINGER_MODE_SILENT}, or 285 * {@link AudioManager#RINGER_MODE_VIBRATE}. 286 */ 287 // protected by mSettingsLock 288 private int mRingerMode; 289 290 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 291 private int mRingerModeAffectedStreams; 292 293 // Streams currently muted by ringer mode 294 private int mRingerModeMutedStreams; 295 296 /** @see System#MUTE_STREAMS_AFFECTED */ 297 private int mMuteAffectedStreams; 298 299 /** 300 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. 301 * mVibrateSetting is just maintained during deprecation period but vibration policy is 302 * now only controlled by mHasVibrator and mRingerMode 303 */ 304 private int mVibrateSetting; 305 306 // Is there a vibrator 307 private final boolean mHasVibrator; 308 309 // Broadcast receiver for device connections intent broadcasts 310 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 311 312 // Used to alter media button redirection when the phone is ringing. 313 private boolean mIsRinging = false; 314 315 // Devices currently connected 316 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 317 318 // Forced device usage for communications 319 private int mForcedUseForComm; 320 321 // True if we have master volume support 322 private final boolean mUseMasterVolume; 323 324 private final int[] mMasterVolumeRamp; 325 326 // List of binder death handlers for setMode() client processes. 327 // The last process to have called setMode() is at the top of the list. 328 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 329 330 // List of clients having issued a SCO start request 331 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 332 333 // BluetoothHeadset API to control SCO connection 334 private BluetoothHeadset mBluetoothHeadset; 335 336 // Bluetooth headset device 337 private BluetoothDevice mBluetoothHeadsetDevice; 338 339 // Indicate if SCO audio connection is currently active and if the initiator is 340 // audio service (internal) or bluetooth headset (external) 341 private int mScoAudioState; 342 // SCO audio state is not active 343 private static final int SCO_STATE_INACTIVE = 0; 344 // SCO audio activation request waiting for headset service to connect 345 private static final int SCO_STATE_ACTIVATE_REQ = 1; 346 // SCO audio state is active or starting due to a local request to start a virtual call 347 private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 348 // SCO audio deactivation request waiting for headset service to connect 349 private static final int SCO_STATE_DEACTIVATE_REQ = 5; 350 351 // SCO audio state is active due to an action in BT handsfree (either voice recognition or 352 // in call audio) 353 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 354 // Deactivation request for all SCO connections (initiated by audio mode change) 355 // waiting for headset service to connect 356 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 357 358 // Current connection state indicated by bluetooth headset 359 private int mScoConnectionState; 360 361 // true if boot sequence has been completed 362 private boolean mBootCompleted; 363 // listener for SoundPool sample load completion indication 364 private SoundPoolCallback mSoundPoolCallBack; 365 // thread for SoundPool listener 366 private SoundPoolListenerThread mSoundPoolListenerThread; 367 // message looper for SoundPool listener 368 private Looper mSoundPoolLooper = null; 369 // default volume applied to sound played with playSoundEffect() 370 private static final int SOUND_EFFECT_DEFAULT_VOLUME_DB = 0; 371 // volume applied to sound played with playSoundEffect() read from ro.config.sound_fx_volume 372 private int SOUND_EFFECT_VOLUME_DB; 373 // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification 374 // stopped 375 private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; 376 // previous volume adjustment direction received by checkForRingerModeChange() 377 private int mPrevVolDirection = AudioManager.ADJUST_SAME; 378 // Keyguard manager proxy 379 private KeyguardManager mKeyguardManager; 380 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 381 // is controlled by Vol keys. 382 private int mVolumeControlStream = -1; 383 private final Object mForceControlStreamLock = new Object(); 384 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 385 // server process so in theory it is not necessary to monitor the client death. 386 // However it is good to be ready for future evolutions. 387 private ForceControlStreamClient mForceControlStreamClient = null; 388 // Used to play ringtones outside system_server 389 private volatile IRingtonePlayer mRingtonePlayer; 390 391 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 392 393 /////////////////////////////////////////////////////////////////////////// 394 // Construction 395 /////////////////////////////////////////////////////////////////////////// 396 397 /** @hide */ 398 public AudioService(Context context) { 399 mContext = context; 400 mContentResolver = context.getContentResolver(); 401 mVoiceCapable = mContext.getResources().getBoolean( 402 com.android.internal.R.bool.config_voice_capable); 403 404 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 405 mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "mediaKeyEvent"); 406 407 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 408 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); 409 410 // Intialized volume 411 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 412 "ro.config.vc_call_vol_steps", 413 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 414 415 SOUND_EFFECT_VOLUME_DB = SystemProperties.getInt( 416 "ro.config.sound_fx_volume", 417 SOUND_EFFECT_DEFAULT_VOLUME_DB); 418 419 mVolumePanel = new VolumePanel(context, this); 420 mMode = AudioSystem.MODE_NORMAL; 421 mForcedUseForComm = AudioSystem.FORCE_NONE; 422 createAudioSystemThread(); 423 readPersistedSettings(); 424 mSettingsObserver = new SettingsObserver(); 425 updateStreamVolumeAlias(false /*updateVolumes*/); 426 createStreamStates(); 427 428 mMediaServerOk = true; 429 430 // Call setRingerModeInt() to apply correct mute 431 // state on streams affected by ringer mode. 432 mRingerModeMutedStreams = 0; 433 setRingerModeInt(getRingerMode(), false); 434 435 AudioSystem.setErrorCallback(mAudioSystemCallback); 436 437 // Register for device connection intent broadcasts. 438 IntentFilter intentFilter = 439 new IntentFilter(Intent.ACTION_HEADSET_PLUG); 440 441 intentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); 442 intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 443 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 444 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 445 intentFilter.addAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 446 intentFilter.addAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 447 intentFilter.addAction(Intent.ACTION_HDMI_AUDIO_PLUG); 448 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 449 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 450 intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 451 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 452 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 453 454 // Register a configuration change listener only if requested by system properties 455 // to monitor orientation changes (off by default) 456 if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 457 Log.v(TAG, "monitoring device orientation"); 458 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 459 // initialize orientation in AudioSystem 460 setOrientationForAudioSystem(); 461 } 462 463 context.registerReceiver(mReceiver, intentFilter); 464 465 // Register for package removal intent broadcasts for media button receiver persistence 466 IntentFilter pkgFilter = new IntentFilter(); 467 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 468 pkgFilter.addDataScheme("package"); 469 context.registerReceiver(mReceiver, pkgFilter); 470 471 // Register for phone state monitoring 472 TelephonyManager tmgr = (TelephonyManager) 473 context.getSystemService(Context.TELEPHONY_SERVICE); 474 tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 475 476 mUseMasterVolume = context.getResources().getBoolean( 477 com.android.internal.R.bool.config_useMasterVolume); 478 restoreMasterVolume(); 479 480 mMasterVolumeRamp = context.getResources().getIntArray( 481 com.android.internal.R.array.config_masterVolumeRamp); 482 } 483 484 private void createAudioSystemThread() { 485 mAudioSystemThread = new AudioSystemThread(); 486 mAudioSystemThread.start(); 487 waitForAudioHandlerCreation(); 488 } 489 490 /** Waits for the volume handler to be created by the other thread. */ 491 private void waitForAudioHandlerCreation() { 492 synchronized(this) { 493 while (mAudioHandler == null) { 494 try { 495 // Wait for mAudioHandler to be set by the other thread 496 wait(); 497 } catch (InterruptedException e) { 498 Log.e(TAG, "Interrupted while waiting on volume handler."); 499 } 500 } 501 } 502 } 503 504 private void createStreamStates() { 505 int numStreamTypes = AudioSystem.getNumStreamTypes(); 506 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 507 508 for (int i = 0; i < numStreamTypes; i++) { 509 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 510 } 511 512 // Correct stream index values for streams with aliases 513 for (int i = 0; i < numStreamTypes; i++) { 514 int device = getDeviceForStream(i); 515 if (mStreamVolumeAlias[i] != i) { 516 int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */), 517 mStreamVolumeAlias[i], 518 i); 519 synchronized (streams[i]) { 520 streams[i].mIndex.put(device, streams[i].getValidIndex(index)); 521 streams[i].applyDeviceVolume(device); 522 index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */), 523 mStreamVolumeAlias[i], 524 i); 525 streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index)); 526 } 527 } 528 } 529 } 530 531 private void dumpStreamStates(PrintWriter pw) { 532 pw.println("\nStream volumes (device: index)"); 533 int numStreamTypes = AudioSystem.getNumStreamTypes(); 534 for (int i = 0; i < numStreamTypes; i++) { 535 pw.println("- "+STREAM_NAMES[i]+":"); 536 mStreamStates[i].dump(pw); 537 pw.println(""); 538 } 539 } 540 541 542 private void updateStreamVolumeAlias(boolean updateVolumes) { 543 int dtmfStreamAlias; 544 if (mVoiceCapable) { 545 mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 546 dtmfStreamAlias = AudioSystem.STREAM_RING; 547 } else { 548 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 549 dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 550 } 551 if (isInCommunication()) { 552 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 553 } 554 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 555 if (updateVolumes) { 556 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 557 false /*lastAudible*/); 558 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 559 true /*lastAudible*/); 560 sendMsg(mAudioHandler, 561 MSG_SET_ALL_VOLUMES, 562 SENDMSG_QUEUE, 563 0, 564 0, 565 mStreamStates[AudioSystem.STREAM_DTMF], 0); 566 } 567 } 568 569 private void readPersistedSettings() { 570 final ContentResolver cr = mContentResolver; 571 572 int ringerModeFromSettings = 573 System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 574 int ringerMode = ringerModeFromSettings; 575 // sanity check in case the settings are restored from a device with incompatible 576 // ringer modes 577 if (!AudioManager.isValidRingerMode(ringerMode)) { 578 ringerMode = AudioManager.RINGER_MODE_NORMAL; 579 } 580 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 581 ringerMode = AudioManager.RINGER_MODE_SILENT; 582 } 583 if (ringerMode != ringerModeFromSettings) { 584 System.putInt(cr, System.MODE_RINGER, ringerMode); 585 } 586 synchronized(mSettingsLock) { 587 mRingerMode = ringerMode; 588 } 589 590 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting 591 // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated. 592 mVibrateSetting = getValueForVibrateSetting(0, 593 AudioManager.VIBRATE_TYPE_NOTIFICATION, 594 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 595 : AudioManager.VIBRATE_SETTING_OFF); 596 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, 597 AudioManager.VIBRATE_TYPE_RINGER, 598 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 599 : AudioManager.VIBRATE_SETTING_OFF); 600 601 // make sure settings for ringer mode are consistent with device type: non voice capable 602 // devices (tablets) include media stream in silent mode whereas phones don't. 603 mRingerModeAffectedStreams = Settings.System.getInt(cr, 604 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 605 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 606 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 607 if (mVoiceCapable) { 608 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 609 } else { 610 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 611 } 612 Settings.System.putInt(cr, 613 Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams); 614 615 mMuteAffectedStreams = System.getInt(cr, 616 System.MUTE_STREAMS_AFFECTED, 617 ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 618 619 boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1; 620 AudioSystem.setMasterMute(masterMute); 621 broadcastMasterMuteStatus(masterMute); 622 623 // Each stream will read its own persisted settings 624 625 // Broadcast the sticky intent 626 broadcastRingerMode(ringerMode); 627 628 // Broadcast vibrate settings 629 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 630 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 631 632 // Restore the default media button receiver from the system settings 633 restoreMediaButtonReceiver(); 634 } 635 636 private int rescaleIndex(int index, int srcStream, int dstStream) { 637 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 638 } 639 640 /////////////////////////////////////////////////////////////////////////// 641 // IPC methods 642 /////////////////////////////////////////////////////////////////////////// 643 644 /** @see AudioManager#adjustVolume(int, int) */ 645 public void adjustVolume(int direction, int flags) { 646 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 647 } 648 649 /** @see AudioManager#adjustVolume(int, int, int) */ 650 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 651 652 int streamType; 653 if (mVolumeControlStream != -1) { 654 streamType = mVolumeControlStream; 655 } else { 656 streamType = getActiveStreamType(suggestedStreamType); 657 } 658 659 // Play sounds on STREAM_RING only and if lock screen is not on. 660 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && 661 ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) 662 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { 663 flags &= ~AudioManager.FLAG_PLAY_SOUND; 664 } 665 666 adjustStreamVolume(streamType, direction, flags); 667 } 668 669 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 670 public void adjustStreamVolume(int streamType, int direction, int flags) { 671 ensureValidDirection(direction); 672 ensureValidStreamType(streamType); 673 674 // use stream type alias here so that streams with same alias have the same behavior, 675 // including with regard to silent mode control (e.g the use of STREAM_RING below and in 676 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) 677 int streamTypeAlias = mStreamVolumeAlias[streamType]; 678 VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 679 680 final int device = getDeviceForStream(streamTypeAlias); 681 // get last audible index if stream is muted, current index otherwise 682 final int oldIndex = streamState.getIndex(device, 683 (streamState.muteCount() != 0) /* lastAudible */); 684 boolean adjustVolume = true; 685 686 // If either the client forces allowing ringer modes for this adjustment, 687 // or the stream type is one that is affected by ringer modes 688 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 689 (streamTypeAlias == getMasterStreamType())) { 690 int ringerMode = getRingerMode(); 691 // do not vibrate if already in vibrate mode 692 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 693 flags &= ~AudioManager.FLAG_VIBRATE; 694 } 695 // Check if the ringer mode changes with this volume adjustment. If 696 // it does, it will handle adjusting the volume, so we won't below 697 adjustVolume = checkForRingerModeChange(oldIndex, direction); 698 } 699 700 // If stream is muted, adjust last audible index only 701 int index; 702 if (streamState.muteCount() != 0) { 703 if (adjustVolume) { 704 // adjust volume on all stream types sharing the same alias otherwise a query 705 // on last audible index for an alias would not give the correct value 706 int numStreamTypes = AudioSystem.getNumStreamTypes(); 707 for (int i = numStreamTypes - 1; i >= 0; i--) { 708 if (mStreamVolumeAlias[i] == streamTypeAlias) { 709 VolumeStreamState s = mStreamStates[i]; 710 711 s.adjustLastAudibleIndex(direction, device); 712 // Post a persist volume msg 713 sendMsg(mAudioHandler, 714 MSG_PERSIST_VOLUME, 715 SENDMSG_QUEUE, 716 PERSIST_LAST_AUDIBLE, 717 device, 718 s, 719 PERSIST_DELAY); 720 } 721 } 722 } 723 index = streamState.getIndex(device, true /* lastAudible */); 724 } else { 725 if (adjustVolume && streamState.adjustIndex(direction, device)) { 726 // Post message to set system volume (it in turn will post a message 727 // to persist). Do not change volume if stream is muted. 728 sendMsg(mAudioHandler, 729 MSG_SET_DEVICE_VOLUME, 730 SENDMSG_QUEUE, 731 device, 732 0, 733 streamState, 734 0); 735 } 736 index = streamState.getIndex(device, false /* lastAudible */); 737 } 738 739 sendVolumeUpdate(streamType, oldIndex, index, flags); 740 } 741 742 /** @see AudioManager#adjustMasterVolume(int) */ 743 public void adjustMasterVolume(int steps, int flags) { 744 ensureValidSteps(steps); 745 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 746 int delta = 0; 747 int numSteps = Math.abs(steps); 748 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER; 749 for (int i = 0; i < numSteps; ++i) { 750 delta = findVolumeDelta(direction, volume); 751 volume += delta; 752 } 753 754 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps); 755 setMasterVolume(volume, flags); 756 } 757 758 /** @see AudioManager#setStreamVolume(int, int, int) */ 759 public void setStreamVolume(int streamType, int index, int flags) { 760 ensureValidStreamType(streamType); 761 VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]]; 762 763 final int device = getDeviceForStream(streamType); 764 // get last audible index if stream is muted, current index otherwise 765 final int oldIndex = streamState.getIndex(device, 766 (streamState.muteCount() != 0) /* lastAudible */); 767 768 // setting volume on master stream type also controls silent mode 769 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 770 (mStreamVolumeAlias[streamType] == getMasterStreamType())) { 771 int newRingerMode; 772 if (index == 0) { 773 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE 774 : AudioManager.RINGER_MODE_SILENT; 775 setStreamVolumeInt(mStreamVolumeAlias[streamType], 776 index, 777 device, 778 false, 779 true); 780 } else { 781 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 782 } 783 setRingerMode(newRingerMode); 784 } 785 786 index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); 787 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true); 788 // get last audible index if stream is muted, current index otherwise 789 index = streamState.getIndex(device, 790 (streamState.muteCount() != 0) /* lastAudible */); 791 792 sendVolumeUpdate(streamType, oldIndex, index, flags); 793 } 794 795 /** @see AudioManager#forceVolumeControlStream(int) */ 796 public void forceVolumeControlStream(int streamType, IBinder cb) { 797 synchronized(mForceControlStreamLock) { 798 mVolumeControlStream = streamType; 799 if (mVolumeControlStream == -1) { 800 if (mForceControlStreamClient != null) { 801 mForceControlStreamClient.release(); 802 mForceControlStreamClient = null; 803 } 804 } else { 805 mForceControlStreamClient = new ForceControlStreamClient(cb); 806 } 807 } 808 } 809 810 private class ForceControlStreamClient implements IBinder.DeathRecipient { 811 private IBinder mCb; // To be notified of client's death 812 813 ForceControlStreamClient(IBinder cb) { 814 if (cb != null) { 815 try { 816 cb.linkToDeath(this, 0); 817 } catch (RemoteException e) { 818 // Client has died! 819 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death"); 820 cb = null; 821 } 822 } 823 mCb = cb; 824 } 825 826 public void binderDied() { 827 synchronized(mForceControlStreamLock) { 828 Log.w(TAG, "SCO client died"); 829 if (mForceControlStreamClient != this) { 830 Log.w(TAG, "unregistered control stream client died"); 831 } else { 832 mForceControlStreamClient = null; 833 mVolumeControlStream = -1; 834 } 835 } 836 } 837 838 public void release() { 839 if (mCb != null) { 840 mCb.unlinkToDeath(this, 0); 841 mCb = null; 842 } 843 } 844 } 845 846 private int findVolumeDelta(int direction, int volume) { 847 int delta = 0; 848 if (direction == AudioManager.ADJUST_RAISE) { 849 if (volume == MAX_MASTER_VOLUME) { 850 return 0; 851 } 852 // This is the default value if we make it to the end 853 delta = mMasterVolumeRamp[1]; 854 // If we're raising the volume move down the ramp array until we 855 // find the volume we're above and use that groups delta. 856 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) { 857 if (volume >= mMasterVolumeRamp[i - 1]) { 858 delta = mMasterVolumeRamp[i]; 859 break; 860 } 861 } 862 } else if (direction == AudioManager.ADJUST_LOWER){ 863 if (volume == 0) { 864 return 0; 865 } 866 int length = mMasterVolumeRamp.length; 867 // This is the default value if we make it to the end 868 delta = -mMasterVolumeRamp[length - 1]; 869 // If we're lowering the volume move up the ramp array until we 870 // find the volume we're below and use the group below it's delta 871 for (int i = 2; i < length; i += 2) { 872 if (volume <= mMasterVolumeRamp[i]) { 873 delta = -mMasterVolumeRamp[i - 1]; 874 break; 875 } 876 } 877 } 878 return delta; 879 } 880 881 // UI update and Broadcast Intent 882 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { 883 if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { 884 streamType = AudioSystem.STREAM_NOTIFICATION; 885 } 886 887 mVolumePanel.postVolumeChanged(streamType, flags); 888 889 oldIndex = (oldIndex + 5) / 10; 890 index = (index + 5) / 10; 891 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 892 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 893 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 894 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 895 mContext.sendBroadcast(intent); 896 } 897 898 // UI update and Broadcast Intent 899 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { 900 mVolumePanel.postMasterVolumeChanged(flags); 901 902 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); 903 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); 904 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume); 905 mContext.sendBroadcast(intent); 906 } 907 908 // UI update and Broadcast Intent 909 private void sendMasterMuteUpdate(boolean muted, int flags) { 910 mVolumePanel.postMasterMuteChanged(flags); 911 broadcastMasterMuteStatus(muted); 912 } 913 914 private void broadcastMasterMuteStatus(boolean muted) { 915 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 916 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 917 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 918 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 919 long origCallerIdentityToken = Binder.clearCallingIdentity(); 920 mContext.sendStickyBroadcast(intent); 921 Binder.restoreCallingIdentity(origCallerIdentityToken); 922 } 923 924 /** 925 * Sets the stream state's index, and posts a message to set system volume. 926 * This will not call out to the UI. Assumes a valid stream type. 927 * 928 * @param streamType Type of the stream 929 * @param index Desired volume index of the stream 930 * @param device the device whose volume must be changed 931 * @param force If true, set the volume even if the desired volume is same 932 * as the current volume. 933 * @param lastAudible If true, stores new index as last audible one 934 */ 935 private void setStreamVolumeInt(int streamType, 936 int index, 937 int device, 938 boolean force, 939 boolean lastAudible) { 940 VolumeStreamState streamState = mStreamStates[streamType]; 941 942 // If stream is muted, set last audible index only 943 if (streamState.muteCount() != 0) { 944 // Do not allow last audible index to be 0 945 if (index != 0) { 946 streamState.setLastAudibleIndex(index, device); 947 // Post a persist volume msg 948 sendMsg(mAudioHandler, 949 MSG_PERSIST_VOLUME, 950 SENDMSG_QUEUE, 951 PERSIST_LAST_AUDIBLE, 952 device, 953 streamState, 954 PERSIST_DELAY); 955 } 956 } else { 957 if (streamState.setIndex(index, device, lastAudible) || force) { 958 // Post message to set system volume (it in turn will post a message 959 // to persist). 960 sendMsg(mAudioHandler, 961 MSG_SET_DEVICE_VOLUME, 962 SENDMSG_QUEUE, 963 device, 964 0, 965 streamState, 966 0); 967 } 968 } 969 } 970 971 /** @see AudioManager#setStreamSolo(int, boolean) */ 972 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 973 for (int stream = 0; stream < mStreamStates.length; stream++) { 974 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 975 // Bring back last audible volume 976 mStreamStates[stream].mute(cb, state); 977 } 978 } 979 980 /** @see AudioManager#setStreamMute(int, boolean) */ 981 public void setStreamMute(int streamType, boolean state, IBinder cb) { 982 if (isStreamAffectedByMute(streamType)) { 983 mStreamStates[streamType].mute(cb, state); 984 } 985 } 986 987 /** get stream mute state. */ 988 public boolean isStreamMute(int streamType) { 989 return (mStreamStates[streamType].muteCount() != 0); 990 } 991 992 /** @see AudioManager#setMasterMute(boolean, IBinder) */ 993 public void setMasterMute(boolean state, int flags, IBinder cb) { 994 if (state != AudioSystem.getMasterMute()) { 995 AudioSystem.setMasterMute(state); 996 // Post a persist master volume msg 997 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1 998 : 0, 0, null, PERSIST_DELAY); 999 sendMasterMuteUpdate(state, flags); 1000 } 1001 } 1002 1003 /** get master mute state. */ 1004 public boolean isMasterMute() { 1005 return AudioSystem.getMasterMute(); 1006 } 1007 1008 /** @see AudioManager#getStreamVolume(int) */ 1009 public int getStreamVolume(int streamType) { 1010 ensureValidStreamType(streamType); 1011 int device = getDeviceForStream(streamType); 1012 return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10; 1013 } 1014 1015 public int getMasterVolume() { 1016 if (isMasterMute()) return 0; 1017 return getLastAudibleMasterVolume(); 1018 } 1019 1020 public void setMasterVolume(int volume, int flags) { 1021 if (volume < 0) { 1022 volume = 0; 1023 } else if (volume > MAX_MASTER_VOLUME) { 1024 volume = MAX_MASTER_VOLUME; 1025 } 1026 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags); 1027 } 1028 1029 private void doSetMasterVolume(float volume, int flags) { 1030 // don't allow changing master volume when muted 1031 if (!AudioSystem.getMasterMute()) { 1032 int oldVolume = getMasterVolume(); 1033 AudioSystem.setMasterVolume(volume); 1034 1035 int newVolume = getMasterVolume(); 1036 if (newVolume != oldVolume) { 1037 // Post a persist master volume msg 1038 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE, 1039 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY); 1040 } 1041 // Send the volume update regardless whether there was a change. 1042 sendMasterVolumeUpdate(flags, oldVolume, newVolume); 1043 } 1044 } 1045 1046 /** @see AudioManager#getStreamMaxVolume(int) */ 1047 public int getStreamMaxVolume(int streamType) { 1048 ensureValidStreamType(streamType); 1049 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 1050 } 1051 1052 public int getMasterMaxVolume() { 1053 return MAX_MASTER_VOLUME; 1054 } 1055 1056 /** Get last audible volume before stream was muted. */ 1057 public int getLastAudibleStreamVolume(int streamType) { 1058 ensureValidStreamType(streamType); 1059 int device = getDeviceForStream(streamType); 1060 return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10; 1061 } 1062 1063 /** Get last audible master volume before it was muted. */ 1064 public int getLastAudibleMasterVolume() { 1065 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 1066 } 1067 1068 /** @see AudioManager#getMasterStreamType(int) */ 1069 public int getMasterStreamType() { 1070 if (mVoiceCapable) { 1071 return AudioSystem.STREAM_RING; 1072 } else { 1073 return AudioSystem.STREAM_MUSIC; 1074 } 1075 } 1076 1077 /** @see AudioManager#getRingerMode() */ 1078 public int getRingerMode() { 1079 synchronized(mSettingsLock) { 1080 return mRingerMode; 1081 } 1082 } 1083 1084 private void ensureValidRingerMode(int ringerMode) { 1085 if (!AudioManager.isValidRingerMode(ringerMode)) { 1086 throw new IllegalArgumentException("Bad ringer mode " + ringerMode); 1087 } 1088 } 1089 1090 /** @see AudioManager#setRingerMode(int) */ 1091 public void setRingerMode(int ringerMode) { 1092 ensureValidRingerMode(ringerMode); 1093 if (ringerMode != getRingerMode()) { 1094 setRingerModeInt(ringerMode, true); 1095 // Send sticky broadcast 1096 broadcastRingerMode(ringerMode); 1097 } 1098 } 1099 1100 private void setRingerModeInt(int ringerMode, boolean persist) { 1101 synchronized(mSettingsLock) { 1102 mRingerMode = ringerMode; 1103 } 1104 1105 // Mute stream if not previously muted by ringer mode and ringer mode 1106 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 1107 // Unmute stream if previously muted by ringer mode and ringer mode 1108 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 1109 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1110 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1111 if (isStreamMutedByRingerMode(streamType)) { 1112 if (!isStreamAffectedByRingerMode(streamType) || 1113 ringerMode == AudioManager.RINGER_MODE_NORMAL) { 1114 // ring and notifications volume should never be 0 when not silenced 1115 // on voice capable devices 1116 if (mVoiceCapable && 1117 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { 1118 synchronized (mStreamStates[streamType]) { 1119 Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); 1120 Iterator i = set.iterator(); 1121 while (i.hasNext()) { 1122 Map.Entry entry = (Map.Entry)i.next(); 1123 if ((Integer)entry.getValue() == 0) { 1124 entry.setValue(10); 1125 } 1126 } 1127 } 1128 } 1129 mStreamStates[streamType].mute(null, false); 1130 mRingerModeMutedStreams &= ~(1 << streamType); 1131 } 1132 } else { 1133 if (isStreamAffectedByRingerMode(streamType) && 1134 ringerMode != AudioManager.RINGER_MODE_NORMAL) { 1135 mStreamStates[streamType].mute(null, true); 1136 mRingerModeMutedStreams |= (1 << streamType); 1137 } 1138 } 1139 } 1140 1141 // Post a persist ringer mode msg 1142 if (persist) { 1143 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, 1144 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 1145 } 1146 } 1147 1148 private void restoreMasterVolume() { 1149 if (mUseMasterVolume) { 1150 float volume = Settings.System.getFloat(mContentResolver, 1151 Settings.System.VOLUME_MASTER, -1.0f); 1152 if (volume >= 0.0f) { 1153 AudioSystem.setMasterVolume(volume); 1154 } 1155 } 1156 } 1157 1158 /** @see AudioManager#shouldVibrate(int) */ 1159 public boolean shouldVibrate(int vibrateType) { 1160 if (!mHasVibrator) return false; 1161 1162 switch (getVibrateSetting(vibrateType)) { 1163 1164 case AudioManager.VIBRATE_SETTING_ON: 1165 return getRingerMode() != AudioManager.RINGER_MODE_SILENT; 1166 1167 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 1168 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; 1169 1170 case AudioManager.VIBRATE_SETTING_OFF: 1171 // return false, even for incoming calls 1172 return false; 1173 1174 default: 1175 return false; 1176 } 1177 } 1178 1179 /** @see AudioManager#getVibrateSetting(int) */ 1180 public int getVibrateSetting(int vibrateType) { 1181 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF; 1182 return (mVibrateSetting >> (vibrateType * 2)) & 3; 1183 } 1184 1185 /** @see AudioManager#setVibrateSetting(int, int) */ 1186 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1187 1188 if (!mHasVibrator) return; 1189 1190 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 1191 1192 // Broadcast change 1193 broadcastVibrateSetting(vibrateType); 1194 1195 } 1196 1197 /** 1198 * @see #setVibrateSetting(int, int) 1199 */ 1200 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 1201 int vibrateSetting) { 1202 1203 // First clear the existing setting. Each vibrate type has two bits in 1204 // the value. Note '3' is '11' in binary. 1205 existingValue &= ~(3 << (vibrateType * 2)); 1206 1207 // Set into the old value 1208 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 1209 1210 return existingValue; 1211 } 1212 1213 private class SetModeDeathHandler implements IBinder.DeathRecipient { 1214 private IBinder mCb; // To be notified of client's death 1215 private int mPid; 1216 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 1217 1218 SetModeDeathHandler(IBinder cb, int pid) { 1219 mCb = cb; 1220 mPid = pid; 1221 } 1222 1223 public void binderDied() { 1224 int newModeOwnerPid = 0; 1225 synchronized(mSetModeDeathHandlers) { 1226 Log.w(TAG, "setMode() client died"); 1227 int index = mSetModeDeathHandlers.indexOf(this); 1228 if (index < 0) { 1229 Log.w(TAG, "unregistered setMode() client died"); 1230 } else { 1231 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid); 1232 } 1233 } 1234 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1235 // SCO connections not started by the application changing the mode 1236 if (newModeOwnerPid != 0) { 1237 disconnectBluetoothSco(newModeOwnerPid); 1238 } 1239 } 1240 1241 public int getPid() { 1242 return mPid; 1243 } 1244 1245 public void setMode(int mode) { 1246 mMode = mode; 1247 } 1248 1249 public int getMode() { 1250 return mMode; 1251 } 1252 1253 public IBinder getBinder() { 1254 return mCb; 1255 } 1256 } 1257 1258 /** @see AudioManager#setMode(int) */ 1259 public void setMode(int mode, IBinder cb) { 1260 if (!checkAudioSettingsPermission("setMode()")) { 1261 return; 1262 } 1263 1264 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { 1265 return; 1266 } 1267 1268 int newModeOwnerPid = 0; 1269 synchronized(mSetModeDeathHandlers) { 1270 if (mode == AudioSystem.MODE_CURRENT) { 1271 mode = mMode; 1272 } 1273 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid()); 1274 } 1275 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1276 // SCO connections not started by the application changing the mode 1277 if (newModeOwnerPid != 0) { 1278 disconnectBluetoothSco(newModeOwnerPid); 1279 } 1280 } 1281 1282 // must be called synchronized on mSetModeDeathHandlers 1283 // setModeInt() returns a valid PID if the audio mode was successfully set to 1284 // any mode other than NORMAL. 1285 int setModeInt(int mode, IBinder cb, int pid) { 1286 int newModeOwnerPid = 0; 1287 if (cb == null) { 1288 Log.e(TAG, "setModeInt() called with null binder"); 1289 return newModeOwnerPid; 1290 } 1291 1292 SetModeDeathHandler hdlr = null; 1293 Iterator iter = mSetModeDeathHandlers.iterator(); 1294 while (iter.hasNext()) { 1295 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 1296 if (h.getPid() == pid) { 1297 hdlr = h; 1298 // Remove from client list so that it is re-inserted at top of list 1299 iter.remove(); 1300 hdlr.getBinder().unlinkToDeath(hdlr, 0); 1301 break; 1302 } 1303 } 1304 int status = AudioSystem.AUDIO_STATUS_OK; 1305 do { 1306 if (mode == AudioSystem.MODE_NORMAL) { 1307 // get new mode from client at top the list if any 1308 if (!mSetModeDeathHandlers.isEmpty()) { 1309 hdlr = mSetModeDeathHandlers.get(0); 1310 cb = hdlr.getBinder(); 1311 mode = hdlr.getMode(); 1312 } 1313 } else { 1314 if (hdlr == null) { 1315 hdlr = new SetModeDeathHandler(cb, pid); 1316 } 1317 // Register for client death notification 1318 try { 1319 cb.linkToDeath(hdlr, 0); 1320 } catch (RemoteException e) { 1321 // Client has died! 1322 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 1323 } 1324 1325 // Last client to call setMode() is always at top of client list 1326 // as required by SetModeDeathHandler.binderDied() 1327 mSetModeDeathHandlers.add(0, hdlr); 1328 hdlr.setMode(mode); 1329 } 1330 1331 if (mode != mMode) { 1332 status = AudioSystem.setPhoneState(mode); 1333 if (status == AudioSystem.AUDIO_STATUS_OK) { 1334 mMode = mode; 1335 } else { 1336 if (hdlr != null) { 1337 mSetModeDeathHandlers.remove(hdlr); 1338 cb.unlinkToDeath(hdlr, 0); 1339 } 1340 // force reading new top of mSetModeDeathHandlers stack 1341 mode = AudioSystem.MODE_NORMAL; 1342 } 1343 } else { 1344 status = AudioSystem.AUDIO_STATUS_OK; 1345 } 1346 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty()); 1347 1348 if (status == AudioSystem.AUDIO_STATUS_OK) { 1349 if (mode != AudioSystem.MODE_NORMAL) { 1350 if (mSetModeDeathHandlers.isEmpty()) { 1351 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack"); 1352 } else { 1353 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); 1354 } 1355 } 1356 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 1357 int device = getDeviceForStream(streamType); 1358 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); 1359 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); 1360 1361 updateStreamVolumeAlias(true /*updateVolumes*/); 1362 } 1363 return newModeOwnerPid; 1364 } 1365 1366 /** @see AudioManager#getMode() */ 1367 public int getMode() { 1368 return mMode; 1369 } 1370 1371 /** @see AudioManager#playSoundEffect(int) */ 1372 public void playSoundEffect(int effectType) { 1373 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1374 effectType, -1, null, 0); 1375 } 1376 1377 /** @see AudioManager#playSoundEffect(int, float) */ 1378 public void playSoundEffectVolume(int effectType, float volume) { 1379 loadSoundEffects(); 1380 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1381 effectType, (int) (volume * 1000), null, 0); 1382 } 1383 1384 /** 1385 * Loads samples into the soundpool. 1386 * This method must be called at first when sound effects are enabled 1387 */ 1388 public boolean loadSoundEffects() { 1389 int status; 1390 1391 synchronized (mSoundEffectsLock) { 1392 if (!mBootCompleted) { 1393 Log.w(TAG, "loadSoundEffects() called before boot complete"); 1394 return false; 1395 } 1396 1397 if (mSoundPool != null) { 1398 return true; 1399 } 1400 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 1401 1402 try { 1403 mSoundPoolCallBack = null; 1404 mSoundPoolListenerThread = new SoundPoolListenerThread(); 1405 mSoundPoolListenerThread.start(); 1406 // Wait for mSoundPoolCallBack to be set by the other thread 1407 mSoundEffectsLock.wait(); 1408 } catch (InterruptedException e) { 1409 Log.w(TAG, "Interrupted while waiting sound pool listener thread."); 1410 } 1411 1412 if (mSoundPoolCallBack == null) { 1413 Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread"); 1414 if (mSoundPoolLooper != null) { 1415 mSoundPoolLooper.quit(); 1416 mSoundPoolLooper = null; 1417 } 1418 mSoundPoolListenerThread = null; 1419 mSoundPool.release(); 1420 mSoundPool = null; 1421 return false; 1422 } 1423 /* 1424 * poolId table: The value -1 in this table indicates that corresponding 1425 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 1426 * Once loaded, the value in poolId is the sample ID and the same 1427 * sample can be reused for another effect using the same file. 1428 */ 1429 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 1430 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 1431 poolId[fileIdx] = -1; 1432 } 1433 /* 1434 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 1435 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 1436 * this indicates we have a valid sample loaded for this effect. 1437 */ 1438 1439 int lastSample = 0; 1440 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1441 // Do not load sample if this effect uses the MediaPlayer 1442 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 1443 continue; 1444 } 1445 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 1446 String filePath = Environment.getRootDirectory() 1447 + SOUND_EFFECTS_PATH 1448 + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 1449 int sampleId = mSoundPool.load(filePath, 0); 1450 if (sampleId <= 0) { 1451 Log.w(TAG, "Soundpool could not load file: "+filePath); 1452 } else { 1453 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 1454 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 1455 lastSample = sampleId; 1456 } 1457 } else { 1458 SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 1459 } 1460 } 1461 // wait for all samples to be loaded 1462 if (lastSample != 0) { 1463 mSoundPoolCallBack.setLastSample(lastSample); 1464 1465 try { 1466 mSoundEffectsLock.wait(); 1467 status = mSoundPoolCallBack.status(); 1468 } catch (java.lang.InterruptedException e) { 1469 Log.w(TAG, "Interrupted while waiting sound pool callback."); 1470 status = -1; 1471 } 1472 } else { 1473 status = -1; 1474 } 1475 1476 if (mSoundPoolLooper != null) { 1477 mSoundPoolLooper.quit(); 1478 mSoundPoolLooper = null; 1479 } 1480 mSoundPoolListenerThread = null; 1481 if (status != 0) { 1482 Log.w(TAG, 1483 "loadSoundEffects(), Error " 1484 + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1) 1485 + " while loading samples"); 1486 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1487 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) { 1488 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1489 } 1490 } 1491 1492 mSoundPool.release(); 1493 mSoundPool = null; 1494 } 1495 } 1496 return (status == 0); 1497 } 1498 1499 /** 1500 * Unloads samples from the sound pool. 1501 * This method can be called to free some memory when 1502 * sound effects are disabled. 1503 */ 1504 public void unloadSoundEffects() { 1505 synchronized (mSoundEffectsLock) { 1506 if (mSoundPool == null) { 1507 return; 1508 } 1509 1510 mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS); 1511 mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT); 1512 1513 int[] poolId = new int[SOUND_EFFECT_FILES.length]; 1514 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 1515 poolId[fileIdx] = 0; 1516 } 1517 1518 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1519 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 1520 continue; 1521 } 1522 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 1523 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 1524 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1525 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 1526 } 1527 } 1528 mSoundPool.release(); 1529 mSoundPool = null; 1530 } 1531 } 1532 1533 class SoundPoolListenerThread extends Thread { 1534 public SoundPoolListenerThread() { 1535 super("SoundPoolListenerThread"); 1536 } 1537 1538 @Override 1539 public void run() { 1540 1541 Looper.prepare(); 1542 mSoundPoolLooper = Looper.myLooper(); 1543 1544 synchronized (mSoundEffectsLock) { 1545 if (mSoundPool != null) { 1546 mSoundPoolCallBack = new SoundPoolCallback(); 1547 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack); 1548 } 1549 mSoundEffectsLock.notify(); 1550 } 1551 Looper.loop(); 1552 } 1553 } 1554 1555 private final class SoundPoolCallback implements 1556 android.media.SoundPool.OnLoadCompleteListener { 1557 1558 int mStatus; 1559 int mLastSample; 1560 1561 public int status() { 1562 return mStatus; 1563 } 1564 1565 public void setLastSample(int sample) { 1566 mLastSample = sample; 1567 } 1568 1569 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 1570 synchronized (mSoundEffectsLock) { 1571 if (status != 0) { 1572 mStatus = status; 1573 } 1574 if (sampleId == mLastSample) { 1575 mSoundEffectsLock.notify(); 1576 } 1577 } 1578 } 1579 } 1580 1581 /** @see AudioManager#reloadAudioSettings() */ 1582 public void reloadAudioSettings() { 1583 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 1584 readPersistedSettings(); 1585 1586 // restore volume settings 1587 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1588 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 1589 VolumeStreamState streamState = mStreamStates[streamType]; 1590 1591 synchronized (streamState) { 1592 streamState.readSettings(); 1593 1594 // unmute stream that was muted but is not affect by mute anymore 1595 if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 1596 int size = streamState.mDeathHandlers.size(); 1597 for (int i = 0; i < size; i++) { 1598 streamState.mDeathHandlers.get(i).mMuteCount = 1; 1599 streamState.mDeathHandlers.get(i).mute(false); 1600 } 1601 } 1602 // apply stream volume 1603 if (streamState.muteCount() == 0) { 1604 streamState.applyAllVolumes(); 1605 } 1606 } 1607 } 1608 1609 // apply new ringer mode 1610 setRingerModeInt(getRingerMode(), false); 1611 } 1612 1613 /** @see AudioManager#setSpeakerphoneOn() */ 1614 public void setSpeakerphoneOn(boolean on){ 1615 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 1616 return; 1617 } 1618 mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; 1619 1620 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1621 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1622 } 1623 1624 /** @see AudioManager#isSpeakerphoneOn() */ 1625 public boolean isSpeakerphoneOn() { 1626 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER); 1627 } 1628 1629 /** @see AudioManager#setBluetoothScoOn() */ 1630 public void setBluetoothScoOn(boolean on){ 1631 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 1632 return; 1633 } 1634 mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 1635 1636 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1637 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1638 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1639 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); 1640 } 1641 1642 /** @see AudioManager#isBluetoothScoOn() */ 1643 public boolean isBluetoothScoOn() { 1644 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); 1645 } 1646 1647 /** @see AudioManager#startBluetoothSco() */ 1648 public void startBluetoothSco(IBinder cb){ 1649 if (!checkAudioSettingsPermission("startBluetoothSco()") || 1650 !mBootCompleted) { 1651 return; 1652 } 1653 ScoClient client = getScoClient(cb, true); 1654 client.incCount(); 1655 } 1656 1657 /** @see AudioManager#stopBluetoothSco() */ 1658 public void stopBluetoothSco(IBinder cb){ 1659 if (!checkAudioSettingsPermission("stopBluetoothSco()") || 1660 !mBootCompleted) { 1661 return; 1662 } 1663 ScoClient client = getScoClient(cb, false); 1664 if (client != null) { 1665 client.decCount(); 1666 } 1667 } 1668 1669 private class ScoClient implements IBinder.DeathRecipient { 1670 private IBinder mCb; // To be notified of client's death 1671 private int mCreatorPid; 1672 private int mStartcount; // number of SCO connections started by this client 1673 1674 ScoClient(IBinder cb) { 1675 mCb = cb; 1676 mCreatorPid = Binder.getCallingPid(); 1677 mStartcount = 0; 1678 } 1679 1680 public void binderDied() { 1681 synchronized(mScoClients) { 1682 Log.w(TAG, "SCO client died"); 1683 int index = mScoClients.indexOf(this); 1684 if (index < 0) { 1685 Log.w(TAG, "unregistered SCO client died"); 1686 } else { 1687 clearCount(true); 1688 mScoClients.remove(this); 1689 } 1690 } 1691 } 1692 1693 public void incCount() { 1694 synchronized(mScoClients) { 1695 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); 1696 if (mStartcount == 0) { 1697 try { 1698 mCb.linkToDeath(this, 0); 1699 } catch (RemoteException e) { 1700 // client has already died! 1701 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 1702 } 1703 } 1704 mStartcount++; 1705 } 1706 } 1707 1708 public void decCount() { 1709 synchronized(mScoClients) { 1710 if (mStartcount == 0) { 1711 Log.w(TAG, "ScoClient.decCount() already 0"); 1712 } else { 1713 mStartcount--; 1714 if (mStartcount == 0) { 1715 try { 1716 mCb.unlinkToDeath(this, 0); 1717 } catch (NoSuchElementException e) { 1718 Log.w(TAG, "decCount() going to 0 but not registered to binder"); 1719 } 1720 } 1721 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1722 } 1723 } 1724 } 1725 1726 public void clearCount(boolean stopSco) { 1727 synchronized(mScoClients) { 1728 if (mStartcount != 0) { 1729 try { 1730 mCb.unlinkToDeath(this, 0); 1731 } catch (NoSuchElementException e) { 1732 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder"); 1733 } 1734 } 1735 mStartcount = 0; 1736 if (stopSco) { 1737 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1738 } 1739 } 1740 } 1741 1742 public int getCount() { 1743 return mStartcount; 1744 } 1745 1746 public IBinder getBinder() { 1747 return mCb; 1748 } 1749 1750 public int getPid() { 1751 return mCreatorPid; 1752 } 1753 1754 public int totalCount() { 1755 synchronized(mScoClients) { 1756 int count = 0; 1757 int size = mScoClients.size(); 1758 for (int i = 0; i < size; i++) { 1759 count += mScoClients.get(i).getCount(); 1760 } 1761 return count; 1762 } 1763 } 1764 1765 private void requestScoState(int state) { 1766 checkScoAudioState(); 1767 if (totalCount() == 0) { 1768 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 1769 // Make sure that the state transitions to CONNECTING even if we cannot initiate 1770 // the connection. 1771 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); 1772 // Accept SCO audio activation only in NORMAL audio mode or if the mode is 1773 // currently controlled by the same client process. 1774 synchronized(mSetModeDeathHandlers) { 1775 if ((mSetModeDeathHandlers.isEmpty() || 1776 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) && 1777 (mScoAudioState == SCO_STATE_INACTIVE || 1778 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 1779 if (mScoAudioState == SCO_STATE_INACTIVE) { 1780 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1781 if (mBluetoothHeadset.startScoUsingVirtualVoiceCall( 1782 mBluetoothHeadsetDevice)) { 1783 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1784 } else { 1785 broadcastScoConnectionState( 1786 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1787 } 1788 } else if (getBluetoothHeadset()) { 1789 mScoAudioState = SCO_STATE_ACTIVATE_REQ; 1790 } 1791 } else { 1792 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1793 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); 1794 } 1795 } else { 1796 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1797 } 1798 } 1799 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED && 1800 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 1801 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { 1802 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { 1803 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1804 if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1805 mBluetoothHeadsetDevice)) { 1806 mScoAudioState = SCO_STATE_INACTIVE; 1807 broadcastScoConnectionState( 1808 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1809 } 1810 } else if (getBluetoothHeadset()) { 1811 mScoAudioState = SCO_STATE_DEACTIVATE_REQ; 1812 } 1813 } else { 1814 mScoAudioState = SCO_STATE_INACTIVE; 1815 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1816 } 1817 } 1818 } 1819 } 1820 } 1821 1822 private void checkScoAudioState() { 1823 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null && 1824 mScoAudioState == SCO_STATE_INACTIVE && 1825 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) 1826 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 1827 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 1828 } 1829 } 1830 1831 private ScoClient getScoClient(IBinder cb, boolean create) { 1832 synchronized(mScoClients) { 1833 ScoClient client = null; 1834 int size = mScoClients.size(); 1835 for (int i = 0; i < size; i++) { 1836 client = mScoClients.get(i); 1837 if (client.getBinder() == cb) 1838 return client; 1839 } 1840 if (create) { 1841 client = new ScoClient(cb); 1842 mScoClients.add(client); 1843 } 1844 return client; 1845 } 1846 } 1847 1848 public void clearAllScoClients(int exceptPid, boolean stopSco) { 1849 synchronized(mScoClients) { 1850 ScoClient savedClient = null; 1851 int size = mScoClients.size(); 1852 for (int i = 0; i < size; i++) { 1853 ScoClient cl = mScoClients.get(i); 1854 if (cl.getPid() != exceptPid) { 1855 cl.clearCount(stopSco); 1856 } else { 1857 savedClient = cl; 1858 } 1859 } 1860 mScoClients.clear(); 1861 if (savedClient != null) { 1862 mScoClients.add(savedClient); 1863 } 1864 } 1865 } 1866 1867 private boolean getBluetoothHeadset() { 1868 boolean result = false; 1869 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1870 if (adapter != null) { 1871 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 1872 BluetoothProfile.HEADSET); 1873 } 1874 // If we could not get a bluetooth headset proxy, send a failure message 1875 // without delay to reset the SCO audio state and clear SCO clients. 1876 // If we could get a proxy, send a delayed failure message that will reset our state 1877 // in case we don't receive onServiceConnected(). 1878 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1879 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); 1880 return result; 1881 } 1882 1883 private void disconnectBluetoothSco(int exceptPid) { 1884 synchronized(mScoClients) { 1885 checkScoAudioState(); 1886 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL || 1887 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1888 if (mBluetoothHeadsetDevice != null) { 1889 if (mBluetoothHeadset != null) { 1890 if (!mBluetoothHeadset.stopVoiceRecognition( 1891 mBluetoothHeadsetDevice)) { 1892 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1893 SENDMSG_REPLACE, 0, 0, null, 0); 1894 } 1895 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && 1896 getBluetoothHeadset()) { 1897 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ; 1898 } 1899 } 1900 } else { 1901 clearAllScoClients(exceptPid, true); 1902 } 1903 } 1904 } 1905 1906 private void resetBluetoothSco() { 1907 synchronized(mScoClients) { 1908 clearAllScoClients(0, false); 1909 mScoAudioState = SCO_STATE_INACTIVE; 1910 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1911 } 1912 } 1913 1914 private void broadcastScoConnectionState(int state) { 1915 if (state != mScoConnectionState) { 1916 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); 1917 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1918 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, 1919 mScoConnectionState); 1920 mContext.sendStickyBroadcast(newIntent); 1921 mScoConnectionState = state; 1922 } 1923 } 1924 1925 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 1926 new BluetoothProfile.ServiceListener() { 1927 public void onServiceConnected(int profile, BluetoothProfile proxy) { 1928 BluetoothDevice btDevice; 1929 List<BluetoothDevice> deviceList; 1930 switch(profile) { 1931 case BluetoothProfile.A2DP: 1932 BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 1933 deviceList = a2dp.getConnectedDevices(); 1934 if (deviceList.size() > 0) { 1935 btDevice = deviceList.get(0); 1936 handleA2dpConnectionStateChange(btDevice, a2dp.getConnectionState(btDevice)); 1937 } 1938 break; 1939 1940 case BluetoothProfile.HEADSET: 1941 synchronized (mScoClients) { 1942 // Discard timeout message 1943 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 1944 mBluetoothHeadset = (BluetoothHeadset) proxy; 1945 deviceList = mBluetoothHeadset.getConnectedDevices(); 1946 if (deviceList.size() > 0) { 1947 mBluetoothHeadsetDevice = deviceList.get(0); 1948 } else { 1949 mBluetoothHeadsetDevice = null; 1950 } 1951 // Refresh SCO audio state 1952 checkScoAudioState(); 1953 // Continue pending action if any 1954 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || 1955 mScoAudioState == SCO_STATE_DEACTIVATE_REQ || 1956 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1957 boolean status = false; 1958 if (mBluetoothHeadsetDevice != null) { 1959 switch (mScoAudioState) { 1960 case SCO_STATE_ACTIVATE_REQ: 1961 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 1962 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 1963 mBluetoothHeadsetDevice); 1964 break; 1965 case SCO_STATE_DEACTIVATE_REQ: 1966 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1967 mBluetoothHeadsetDevice); 1968 break; 1969 case SCO_STATE_DEACTIVATE_EXT_REQ: 1970 status = mBluetoothHeadset.stopVoiceRecognition( 1971 mBluetoothHeadsetDevice); 1972 } 1973 } 1974 if (!status) { 1975 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1976 SENDMSG_REPLACE, 0, 0, null, 0); 1977 } 1978 } 1979 } 1980 break; 1981 1982 default: 1983 break; 1984 } 1985 } 1986 public void onServiceDisconnected(int profile) { 1987 switch(profile) { 1988 case BluetoothProfile.A2DP: 1989 synchronized (mConnectedDevices) { 1990 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { 1991 makeA2dpDeviceUnavailableNow( 1992 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); 1993 } 1994 } 1995 break; 1996 1997 case BluetoothProfile.HEADSET: 1998 synchronized (mScoClients) { 1999 mBluetoothHeadset = null; 2000 } 2001 break; 2002 2003 default: 2004 break; 2005 } 2006 } 2007 }; 2008 2009 /////////////////////////////////////////////////////////////////////////// 2010 // Internal methods 2011 /////////////////////////////////////////////////////////////////////////// 2012 2013 /** 2014 * Checks if the adjustment should change ringer mode instead of just 2015 * adjusting volume. If so, this will set the proper ringer mode and volume 2016 * indices on the stream states. 2017 */ 2018 private boolean checkForRingerModeChange(int oldIndex, int direction) { 2019 boolean adjustVolumeIndex = true; 2020 int ringerMode = getRingerMode(); 2021 int uiIndex = (oldIndex + 5) / 10; 2022 2023 switch (ringerMode) { 2024 case RINGER_MODE_NORMAL: 2025 if (direction == AudioManager.ADJUST_LOWER) { 2026 if (mHasVibrator) { 2027 if (uiIndex == 1) { 2028 ringerMode = RINGER_MODE_VIBRATE; 2029 } 2030 } else { 2031 if (uiIndex == 0 && mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2032 ringerMode = RINGER_MODE_SILENT; 2033 } 2034 } 2035 } 2036 break; 2037 case RINGER_MODE_VIBRATE: 2038 if (!mHasVibrator) { 2039 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" + 2040 "but no vibrator is present"); 2041 break; 2042 } 2043 if ((direction == AudioManager.ADJUST_LOWER)) { 2044 if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2045 ringerMode = RINGER_MODE_SILENT; 2046 } 2047 } else if (direction == AudioManager.ADJUST_RAISE) { 2048 ringerMode = RINGER_MODE_NORMAL; 2049 } 2050 adjustVolumeIndex = false; 2051 break; 2052 case RINGER_MODE_SILENT: 2053 if (direction == AudioManager.ADJUST_RAISE) { 2054 if (mHasVibrator) { 2055 ringerMode = RINGER_MODE_VIBRATE; 2056 } else { 2057 ringerMode = RINGER_MODE_NORMAL; 2058 } 2059 } 2060 adjustVolumeIndex = false; 2061 break; 2062 default: 2063 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode); 2064 break; 2065 } 2066 2067 setRingerMode(ringerMode); 2068 2069 mPrevVolDirection = direction; 2070 2071 return adjustVolumeIndex; 2072 } 2073 2074 public boolean isStreamAffectedByRingerMode(int streamType) { 2075 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 2076 } 2077 2078 private boolean isStreamMutedByRingerMode(int streamType) { 2079 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 2080 } 2081 2082 public boolean isStreamAffectedByMute(int streamType) { 2083 return (mMuteAffectedStreams & (1 << streamType)) != 0; 2084 } 2085 2086 private void ensureValidDirection(int direction) { 2087 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 2088 throw new IllegalArgumentException("Bad direction " + direction); 2089 } 2090 } 2091 2092 private void ensureValidSteps(int steps) { 2093 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 2094 throw new IllegalArgumentException("Bad volume adjust steps " + steps); 2095 } 2096 } 2097 2098 private void ensureValidStreamType(int streamType) { 2099 if (streamType < 0 || streamType >= mStreamStates.length) { 2100 throw new IllegalArgumentException("Bad stream type " + streamType); 2101 } 2102 } 2103 2104 private boolean isInCommunication() { 2105 boolean isOffhook = false; 2106 2107 if (mVoiceCapable) { 2108 try { 2109 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 2110 if (phone != null) isOffhook = phone.isOffhook(); 2111 } catch (RemoteException e) { 2112 Log.w(TAG, "Couldn't connect to phone service", e); 2113 } 2114 } 2115 return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 2116 } 2117 2118 private int getActiveStreamType(int suggestedStreamType) { 2119 if (mVoiceCapable) { 2120 if (isInCommunication()) { 2121 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2122 == AudioSystem.FORCE_BT_SCO) { 2123 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2124 return AudioSystem.STREAM_BLUETOOTH_SCO; 2125 } else { 2126 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2127 return AudioSystem.STREAM_VOICE_CALL; 2128 } 2129 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 2130 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); 2131 return AudioSystem.STREAM_MUSIC; 2132 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2133 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..." 2134 // + " b/c USE_DEFAULT_STREAM_TYPE..."); 2135 return AudioSystem.STREAM_RING; 2136 } else { 2137 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 2138 return suggestedStreamType; 2139 } 2140 } else { 2141 if (isInCommunication()) { 2142 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2143 == AudioSystem.FORCE_BT_SCO) { 2144 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2145 return AudioSystem.STREAM_BLUETOOTH_SCO; 2146 } else { 2147 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2148 return AudioSystem.STREAM_VOICE_CALL; 2149 } 2150 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 2151 NOTIFICATION_VOLUME_DELAY_MS) || 2152 AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 2153 NOTIFICATION_VOLUME_DELAY_MS)) { 2154 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION..."); 2155 return AudioSystem.STREAM_NOTIFICATION; 2156 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) || 2157 (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE)) { 2158 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC " 2159 // + " b/c USE_DEFAULT_STREAM_TYPE..."); 2160 return AudioSystem.STREAM_MUSIC; 2161 } else { 2162 // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); 2163 return suggestedStreamType; 2164 } 2165 } 2166 } 2167 2168 private void broadcastRingerMode(int ringerMode) { 2169 // Send sticky broadcast 2170 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2171 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 2172 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2173 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2174 long origCallerIdentityToken = Binder.clearCallingIdentity(); 2175 mContext.sendStickyBroadcast(broadcast); 2176 Binder.restoreCallingIdentity(origCallerIdentityToken); 2177 } 2178 2179 private void broadcastVibrateSetting(int vibrateType) { 2180 // Send broadcast 2181 if (ActivityManagerNative.isSystemReady()) { 2182 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 2183 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 2184 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 2185 mContext.sendBroadcast(broadcast); 2186 } 2187 } 2188 2189 // Message helper methods 2190 2191 private static void sendMsg(Handler handler, int msg, 2192 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 2193 2194 if (existingMsgPolicy == SENDMSG_REPLACE) { 2195 handler.removeMessages(msg); 2196 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 2197 return; 2198 } 2199 2200 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 2201 } 2202 2203 boolean checkAudioSettingsPermission(String method) { 2204 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 2205 == PackageManager.PERMISSION_GRANTED) { 2206 return true; 2207 } 2208 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 2209 + Binder.getCallingPid() 2210 + ", uid=" + Binder.getCallingUid(); 2211 Log.w(TAG, msg); 2212 return false; 2213 } 2214 2215 private int getDeviceForStream(int stream) { 2216 int device = AudioSystem.getDevicesForStream(stream); 2217 if ((device & (device - 1)) != 0) { 2218 // Multiple device selection is either: 2219 // - speaker + one other device: give priority to speaker in this case. 2220 // - one A2DP device + another device: happens with duplicated output. In this case 2221 // retain the device on the A2DP output as the other must not correspond to an active 2222 // selection if not the speaker. 2223 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 2224 device = AudioSystem.DEVICE_OUT_SPEAKER; 2225 } else { 2226 device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 2227 } 2228 } 2229 return device; 2230 } 2231 2232 /////////////////////////////////////////////////////////////////////////// 2233 // Inner classes 2234 /////////////////////////////////////////////////////////////////////////// 2235 2236 public class VolumeStreamState { 2237 private final int mStreamType; 2238 2239 private String mVolumeIndexSettingName; 2240 private String mLastAudibleVolumeIndexSettingName; 2241 private int mIndexMax; 2242 private final ConcurrentHashMap<Integer, Integer> mIndex = 2243 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 2244 private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex = 2245 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 2246 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 2247 2248 private VolumeStreamState(String settingName, int streamType) { 2249 2250 mVolumeIndexSettingName = settingName; 2251 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 2252 2253 mStreamType = streamType; 2254 mIndexMax = MAX_STREAM_VOLUME[streamType]; 2255 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2256 mIndexMax *= 10; 2257 2258 readSettings(); 2259 2260 applyAllVolumes(); 2261 2262 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 2263 } 2264 2265 public String getSettingNameForDevice(boolean lastAudible, int device) { 2266 String name = lastAudible ? 2267 mLastAudibleVolumeIndexSettingName : 2268 mVolumeIndexSettingName; 2269 String suffix = AudioSystem.getDeviceName(device); 2270 if (suffix.isEmpty()) { 2271 return name; 2272 } 2273 return name + "_" + suffix; 2274 } 2275 2276 public synchronized void readSettings() { 2277 int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 2278 2279 for (int i = 0; remainingDevices != 0; i++) { 2280 int device = (1 << i); 2281 if ((device & remainingDevices) == 0) { 2282 continue; 2283 } 2284 remainingDevices &= ~device; 2285 2286 // retrieve current volume for device 2287 String name = getSettingNameForDevice(false /* lastAudible */, device); 2288 // if no volume stored for current stream and device, use default volume if default 2289 // device, continue otherwise 2290 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 2291 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 2292 int index = Settings.System.getInt(mContentResolver, name, defaultIndex); 2293 if (index == -1) { 2294 continue; 2295 } 2296 2297 // retrieve last audible volume for device 2298 name = getSettingNameForDevice(true /* lastAudible */, device); 2299 // use stored last audible index if present, otherwise use current index if not 0 2300 // or default index 2301 defaultIndex = (index > 0) ? 2302 index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2303 int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex); 2304 2305 // a last audible index of 0 should never be stored for ring and notification 2306 // streams on phones (voice capable devices). 2307 // same for system stream on phones and tablets 2308 if ((lastAudibleIndex == 0) && 2309 ((mVoiceCapable && 2310 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2311 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 2312 lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2313 // Correct the data base 2314 sendMsg(mAudioHandler, 2315 MSG_PERSIST_VOLUME, 2316 SENDMSG_QUEUE, 2317 PERSIST_LAST_AUDIBLE, 2318 device, 2319 this, 2320 PERSIST_DELAY); 2321 } 2322 mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex)); 2323 // the initial index should never be 0 for ring and notification streams on phones 2324 // (voice capable devices) if not in silent or vibrate mode. 2325 // same for system stream on phones and tablets 2326 if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) && 2327 ((mVoiceCapable && 2328 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2329 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 2330 index = lastAudibleIndex; 2331 // Correct the data base 2332 sendMsg(mAudioHandler, 2333 MSG_PERSIST_VOLUME, 2334 SENDMSG_QUEUE, 2335 PERSIST_CURRENT, 2336 device, 2337 this, 2338 PERSIST_DELAY); 2339 } 2340 mIndex.put(device, getValidIndex(10 * index)); 2341 } 2342 } 2343 2344 public void applyDeviceVolume(int device) { 2345 AudioSystem.setStreamVolumeIndex(mStreamType, 2346 (getIndex(device, false /* lastAudible */) + 5)/10, 2347 device); 2348 } 2349 2350 public synchronized void applyAllVolumes() { 2351 // apply default volume first: by convention this will reset all 2352 // devices volumes in audio policy manager to the supplied value 2353 AudioSystem.setStreamVolumeIndex(mStreamType, 2354 (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, 2355 AudioSystem.DEVICE_OUT_DEFAULT); 2356 // then apply device specific volumes 2357 Set set = mIndex.entrySet(); 2358 Iterator i = set.iterator(); 2359 while (i.hasNext()) { 2360 Map.Entry entry = (Map.Entry)i.next(); 2361 int device = ((Integer)entry.getKey()).intValue(); 2362 if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 2363 AudioSystem.setStreamVolumeIndex(mStreamType, 2364 ((Integer)entry.getValue() + 5)/10, 2365 device); 2366 } 2367 } 2368 } 2369 2370 public boolean adjustIndex(int deltaIndex, int device) { 2371 return setIndex(getIndex(device, 2372 false /* lastAudible */) + deltaIndex * 10, 2373 device, 2374 true /* lastAudible */); 2375 } 2376 2377 public synchronized boolean setIndex(int index, int device, boolean lastAudible) { 2378 int oldIndex = getIndex(device, false /* lastAudible */); 2379 index = getValidIndex(index); 2380 mIndex.put(device, getValidIndex(index)); 2381 2382 if (oldIndex != index) { 2383 if (lastAudible) { 2384 mLastAudibleIndex.put(device, index); 2385 } 2386 // Apply change to all streams using this one as alias 2387 // if changing volume of current device, also change volume of current 2388 // device on aliased stream 2389 boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2390 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2391 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2392 if (streamType != mStreamType && 2393 mStreamVolumeAlias[streamType] == mStreamType) { 2394 int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2395 mStreamStates[streamType].setIndex(scaledIndex, 2396 device, 2397 lastAudible); 2398 if (currentDevice) { 2399 mStreamStates[streamType].setIndex(scaledIndex, 2400 getDeviceForStream(streamType), 2401 lastAudible); 2402 } 2403 } 2404 } 2405 return true; 2406 } else { 2407 return false; 2408 } 2409 } 2410 2411 public synchronized int getIndex(int device, boolean lastAudible) { 2412 ConcurrentHashMap <Integer, Integer> indexes; 2413 if (lastAudible) { 2414 indexes = mLastAudibleIndex; 2415 } else { 2416 indexes = mIndex; 2417 } 2418 Integer index = indexes.get(device); 2419 if (index == null) { 2420 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 2421 index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); 2422 } 2423 return index.intValue(); 2424 } 2425 2426 public synchronized void setLastAudibleIndex(int index, int device) { 2427 mLastAudibleIndex.put(device, getValidIndex(index)); 2428 } 2429 2430 public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) { 2431 setLastAudibleIndex(getIndex(device, 2432 true /* lastAudible */) + deltaIndex * 10, 2433 device); 2434 } 2435 2436 public int getMaxIndex() { 2437 return mIndexMax; 2438 } 2439 2440 // only called by setAllIndexes() which is already synchronized 2441 public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { 2442 if (lastAudible) { 2443 return mLastAudibleIndex; 2444 } else { 2445 return mIndex; 2446 } 2447 } 2448 2449 public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { 2450 ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); 2451 Set set = indexes.entrySet(); 2452 Iterator i = set.iterator(); 2453 while (i.hasNext()) { 2454 Map.Entry entry = (Map.Entry)i.next(); 2455 int device = ((Integer)entry.getKey()).intValue(); 2456 int index = ((Integer)entry.getValue()).intValue(); 2457 index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 2458 setIndex(index, device, lastAudible); 2459 } 2460 } 2461 2462 public synchronized void mute(IBinder cb, boolean state) { 2463 VolumeDeathHandler handler = getDeathHandler(cb, state); 2464 if (handler == null) { 2465 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 2466 return; 2467 } 2468 handler.mute(state); 2469 } 2470 2471 public int getStreamType() { 2472 return mStreamType; 2473 } 2474 2475 private int getValidIndex(int index) { 2476 if (index < 0) { 2477 return 0; 2478 } else if (index > mIndexMax) { 2479 return mIndexMax; 2480 } 2481 2482 return index; 2483 } 2484 2485 private class VolumeDeathHandler implements IBinder.DeathRecipient { 2486 private IBinder mICallback; // To be notified of client's death 2487 private int mMuteCount; // Number of active mutes for this client 2488 2489 VolumeDeathHandler(IBinder cb) { 2490 mICallback = cb; 2491 } 2492 2493 // must be called while synchronized on parent VolumeStreamState 2494 public void mute(boolean state) { 2495 if (state) { 2496 if (mMuteCount == 0) { 2497 // Register for client death notification 2498 try { 2499 // mICallback can be 0 if muted by AudioService 2500 if (mICallback != null) { 2501 mICallback.linkToDeath(this, 0); 2502 } 2503 mDeathHandlers.add(this); 2504 // If the stream is not yet muted by any client, set level to 0 2505 if (muteCount() == 0) { 2506 Set set = mIndex.entrySet(); 2507 Iterator i = set.iterator(); 2508 while (i.hasNext()) { 2509 Map.Entry entry = (Map.Entry)i.next(); 2510 int device = ((Integer)entry.getKey()).intValue(); 2511 setIndex(0, device, false /* lastAudible */); 2512 } 2513 sendMsg(mAudioHandler, 2514 MSG_SET_ALL_VOLUMES, 2515 SENDMSG_QUEUE, 2516 0, 2517 0, 2518 VolumeStreamState.this, 0); 2519 } 2520 } catch (RemoteException e) { 2521 // Client has died! 2522 binderDied(); 2523 return; 2524 } 2525 } else { 2526 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 2527 } 2528 mMuteCount++; 2529 } else { 2530 if (mMuteCount == 0) { 2531 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 2532 } else { 2533 mMuteCount--; 2534 if (mMuteCount == 0) { 2535 // Unregister from client death notification 2536 mDeathHandlers.remove(this); 2537 // mICallback can be 0 if muted by AudioService 2538 if (mICallback != null) { 2539 mICallback.unlinkToDeath(this, 0); 2540 } 2541 if (muteCount() == 0) { 2542 // If the stream is not muted any more, restore its volume if 2543 // ringer mode allows it 2544 if (!isStreamAffectedByRingerMode(mStreamType) || 2545 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 2546 Set set = mIndex.entrySet(); 2547 Iterator i = set.iterator(); 2548 while (i.hasNext()) { 2549 Map.Entry entry = (Map.Entry)i.next(); 2550 int device = ((Integer)entry.getKey()).intValue(); 2551 setIndex(getIndex(device, 2552 true /* lastAudible */), 2553 device, 2554 false /* lastAudible */); 2555 } 2556 sendMsg(mAudioHandler, 2557 MSG_SET_ALL_VOLUMES, 2558 SENDMSG_QUEUE, 2559 0, 2560 0, 2561 VolumeStreamState.this, 0); 2562 } 2563 } 2564 } 2565 } 2566 } 2567 } 2568 2569 public void binderDied() { 2570 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 2571 if (mMuteCount != 0) { 2572 // Reset all active mute requests from this client. 2573 mMuteCount = 1; 2574 mute(false); 2575 } 2576 } 2577 } 2578 2579 private synchronized int muteCount() { 2580 int count = 0; 2581 int size = mDeathHandlers.size(); 2582 for (int i = 0; i < size; i++) { 2583 count += mDeathHandlers.get(i).mMuteCount; 2584 } 2585 return count; 2586 } 2587 2588 // only called by mute() which is already synchronized 2589 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 2590 VolumeDeathHandler handler; 2591 int size = mDeathHandlers.size(); 2592 for (int i = 0; i < size; i++) { 2593 handler = mDeathHandlers.get(i); 2594 if (cb == handler.mICallback) { 2595 return handler; 2596 } 2597 } 2598 // If this is the first mute request for this client, create a new 2599 // client death handler. Otherwise, it is an out of sequence unmute request. 2600 if (state) { 2601 handler = new VolumeDeathHandler(cb); 2602 } else { 2603 Log.w(TAG, "stream was not muted by this client"); 2604 handler = null; 2605 } 2606 return handler; 2607 } 2608 2609 private void dump(PrintWriter pw) { 2610 pw.print(" Current: "); 2611 Set set = mIndex.entrySet(); 2612 Iterator i = set.iterator(); 2613 while (i.hasNext()) { 2614 Map.Entry entry = (Map.Entry)i.next(); 2615 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2616 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2617 } 2618 pw.print("\n Last audible: "); 2619 set = mLastAudibleIndex.entrySet(); 2620 i = set.iterator(); 2621 while (i.hasNext()) { 2622 Map.Entry entry = (Map.Entry)i.next(); 2623 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2624 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2625 } 2626 } 2627 } 2628 2629 /** Thread that handles native AudioSystem control. */ 2630 private class AudioSystemThread extends Thread { 2631 AudioSystemThread() { 2632 super("AudioService"); 2633 } 2634 2635 @Override 2636 public void run() { 2637 // Set this thread up so the handler will work on it 2638 Looper.prepare(); 2639 2640 synchronized(AudioService.this) { 2641 mAudioHandler = new AudioHandler(); 2642 2643 // Notify that the handler has been created 2644 AudioService.this.notify(); 2645 } 2646 2647 // Listen for volume change requests that are set by VolumePanel 2648 Looper.loop(); 2649 } 2650 } 2651 2652 /** Handles internal volume messages in separate volume thread. */ 2653 private class AudioHandler extends Handler { 2654 2655 private void setDeviceVolume(VolumeStreamState streamState, int device) { 2656 2657 // Apply volume 2658 streamState.applyDeviceVolume(device); 2659 2660 // Apply change to all streams using this one as alias 2661 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2662 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2663 if (streamType != streamState.mStreamType && 2664 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 2665 mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 2666 } 2667 } 2668 2669 // Post a persist volume msg 2670 sendMsg(mAudioHandler, 2671 MSG_PERSIST_VOLUME, 2672 SENDMSG_QUEUE, 2673 PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, 2674 device, 2675 streamState, 2676 PERSIST_DELAY); 2677 2678 } 2679 2680 private void setAllVolumes(VolumeStreamState streamState) { 2681 2682 // Apply volume 2683 streamState.applyAllVolumes(); 2684 2685 // Apply change to all streams using this one as alias 2686 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2687 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2688 if (streamType != streamState.mStreamType && 2689 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 2690 mStreamStates[streamType].applyAllVolumes(); 2691 } 2692 } 2693 } 2694 2695 private void persistVolume(VolumeStreamState streamState, 2696 int persistType, 2697 int device) { 2698 if ((persistType & PERSIST_CURRENT) != 0) { 2699 System.putInt(mContentResolver, 2700 streamState.getSettingNameForDevice(false /* lastAudible */, device), 2701 (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10); 2702 } 2703 if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { 2704 System.putInt(mContentResolver, 2705 streamState.getSettingNameForDevice(true /* lastAudible */, device), 2706 (streamState.getIndex(device, true /* lastAudible */) + 5) / 10); 2707 } 2708 } 2709 2710 private void persistRingerMode(int ringerMode) { 2711 System.putInt(mContentResolver, System.MODE_RINGER, ringerMode); 2712 } 2713 2714 private void playSoundEffect(int effectType, int volume) { 2715 synchronized (mSoundEffectsLock) { 2716 if (mSoundPool == null) { 2717 return; 2718 } 2719 float volFloat; 2720 // use default if volume is not specified by caller 2721 if (volume < 0) { 2722 volFloat = (float)Math.pow(10, SOUND_EFFECT_VOLUME_DB/20); 2723 } else { 2724 volFloat = (float) volume / 1000.0f; 2725 } 2726 2727 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 2728 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 2729 } else { 2730 MediaPlayer mediaPlayer = new MediaPlayer(); 2731 try { 2732 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 2733 mediaPlayer.setDataSource(filePath); 2734 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 2735 mediaPlayer.prepare(); 2736 mediaPlayer.setVolume(volFloat, volFloat); 2737 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 2738 public void onCompletion(MediaPlayer mp) { 2739 cleanupPlayer(mp); 2740 } 2741 }); 2742 mediaPlayer.setOnErrorListener(new OnErrorListener() { 2743 public boolean onError(MediaPlayer mp, int what, int extra) { 2744 cleanupPlayer(mp); 2745 return true; 2746 } 2747 }); 2748 mediaPlayer.start(); 2749 } catch (IOException ex) { 2750 Log.w(TAG, "MediaPlayer IOException: "+ex); 2751 } catch (IllegalArgumentException ex) { 2752 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 2753 } catch (IllegalStateException ex) { 2754 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 2755 } 2756 } 2757 } 2758 } 2759 2760 private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { 2761 Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER, 2762 receiver == null ? "" : receiver.flattenToString()); 2763 } 2764 2765 private void cleanupPlayer(MediaPlayer mp) { 2766 if (mp != null) { 2767 try { 2768 mp.stop(); 2769 mp.release(); 2770 } catch (IllegalStateException ex) { 2771 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 2772 } 2773 } 2774 } 2775 2776 private void setForceUse(int usage, int config) { 2777 AudioSystem.setForceUse(usage, config); 2778 } 2779 2780 @Override 2781 public void handleMessage(Message msg) { 2782 2783 switch (msg.what) { 2784 2785 case MSG_SET_DEVICE_VOLUME: 2786 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 2787 break; 2788 2789 case MSG_SET_ALL_VOLUMES: 2790 setAllVolumes((VolumeStreamState) msg.obj); 2791 break; 2792 2793 case MSG_PERSIST_VOLUME: 2794 persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); 2795 break; 2796 2797 case MSG_PERSIST_MASTER_VOLUME: 2798 Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER, 2799 (float)msg.arg1 / (float)1000.0); 2800 break; 2801 2802 case MSG_PERSIST_MASTER_VOLUME_MUTE: 2803 Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE, 2804 msg.arg1); 2805 break; 2806 2807 case MSG_PERSIST_RINGER_MODE: 2808 // note that the value persisted is the current ringer mode, not the 2809 // value of ringer mode as of the time the request was made to persist 2810 persistRingerMode(getRingerMode()); 2811 break; 2812 2813 case MSG_MEDIA_SERVER_DIED: 2814 if (!mMediaServerOk) { 2815 Log.e(TAG, "Media server died."); 2816 // Force creation of new IAudioFlinger interface so that we are notified 2817 // when new media_server process is back to life. 2818 AudioSystem.setErrorCallback(mAudioSystemCallback); 2819 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 2820 null, 500); 2821 } 2822 break; 2823 2824 case MSG_MEDIA_SERVER_STARTED: 2825 Log.e(TAG, "Media server started."); 2826 // indicate to audio HAL that we start the reconfiguration phase after a media 2827 // server crash 2828 // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 2829 // process restarts after a crash, not the first time it is started. 2830 AudioSystem.setParameters("restarting=true"); 2831 2832 // Restore device connection states 2833 synchronized (mConnectedDevices) { 2834 Set set = mConnectedDevices.entrySet(); 2835 Iterator i = set.iterator(); 2836 while (i.hasNext()) { 2837 Map.Entry device = (Map.Entry)i.next(); 2838 AudioSystem.setDeviceConnectionState( 2839 ((Integer)device.getKey()).intValue(), 2840 AudioSystem.DEVICE_STATE_AVAILABLE, 2841 (String)device.getValue()); 2842 } 2843 } 2844 // Restore call state 2845 AudioSystem.setPhoneState(mMode); 2846 2847 // Restore forced usage for communcations and record 2848 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 2849 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 2850 2851 // Restore stream volumes 2852 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2853 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2854 VolumeStreamState streamState = mStreamStates[streamType]; 2855 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 2856 2857 streamState.applyAllVolumes(); 2858 } 2859 2860 // Restore ringer mode 2861 setRingerModeInt(getRingerMode(), false); 2862 2863 // Restore master volume 2864 restoreMasterVolume(); 2865 2866 // Reset device orientation (if monitored for this device) 2867 if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 2868 setOrientationForAudioSystem(); 2869 } 2870 2871 // indicate the end of reconfiguration phase to audio HAL 2872 AudioSystem.setParameters("restarting=false"); 2873 break; 2874 2875 case MSG_LOAD_SOUND_EFFECTS: 2876 loadSoundEffects(); 2877 break; 2878 2879 case MSG_PLAY_SOUND_EFFECT: 2880 playSoundEffect(msg.arg1, msg.arg2); 2881 break; 2882 2883 case MSG_BTA2DP_DOCK_TIMEOUT: 2884 // msg.obj == address of BTA2DP device 2885 synchronized (mConnectedDevices) { 2886 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 2887 } 2888 break; 2889 2890 case MSG_SET_FORCE_USE: 2891 setForceUse(msg.arg1, msg.arg2); 2892 break; 2893 2894 case MSG_PERSIST_MEDIABUTTONRECEIVER: 2895 onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); 2896 break; 2897 2898 case MSG_RCDISPLAY_CLEAR: 2899 onRcDisplayClear(); 2900 break; 2901 2902 case MSG_RCDISPLAY_UPDATE: 2903 // msg.obj is guaranteed to be non null 2904 onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); 2905 break; 2906 2907 case MSG_BT_HEADSET_CNCT_FAILED: 2908 resetBluetoothSco(); 2909 break; 2910 } 2911 } 2912 } 2913 2914 private class SettingsObserver extends ContentObserver { 2915 2916 SettingsObserver() { 2917 super(new Handler()); 2918 mContentResolver.registerContentObserver(Settings.System.getUriFor( 2919 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 2920 } 2921 2922 @Override 2923 public void onChange(boolean selfChange) { 2924 super.onChange(selfChange); 2925 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 2926 // However there appear to be some missing locks around mRingerModeMutedStreams 2927 // and mRingerModeAffectedStreams, so will leave this synchronized for now. 2928 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 2929 synchronized (mSettingsLock) { 2930 int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 2931 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 2932 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 2933 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 2934 if (mVoiceCapable) { 2935 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 2936 } else { 2937 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 2938 } 2939 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 2940 /* 2941 * Ensure all stream types that should be affected by ringer mode 2942 * are in the proper state. 2943 */ 2944 mRingerModeAffectedStreams = ringerModeAffectedStreams; 2945 setRingerModeInt(getRingerMode(), false); 2946 } 2947 } 2948 } 2949 } 2950 2951 // must be called synchronized on mConnectedDevices 2952 private void makeA2dpDeviceAvailable(String address) { 2953 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2954 AudioSystem.DEVICE_STATE_AVAILABLE, 2955 address); 2956 // Reset A2DP suspend state each time a new sink is connected 2957 AudioSystem.setParameters("A2dpSuspended=false"); 2958 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 2959 address); 2960 } 2961 2962 // must be called synchronized on mConnectedDevices 2963 private void makeA2dpDeviceUnavailableNow(String address) { 2964 Intent noisyIntent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); 2965 mContext.sendBroadcast(noisyIntent); 2966 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2967 AudioSystem.DEVICE_STATE_UNAVAILABLE, 2968 address); 2969 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 2970 } 2971 2972 // must be called synchronized on mConnectedDevices 2973 private void makeA2dpDeviceUnavailableLater(String address) { 2974 // prevent any activity on the A2DP audio output to avoid unwanted 2975 // reconnection of the sink. 2976 AudioSystem.setParameters("A2dpSuspended=true"); 2977 // the device will be made unavailable later, so consider it disconnected right away 2978 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 2979 // send the delayed message to make the device unavailable later 2980 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 2981 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 2982 2983 } 2984 2985 // must be called synchronized on mConnectedDevices 2986 private void cancelA2dpDeviceTimeout() { 2987 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 2988 } 2989 2990 // must be called synchronized on mConnectedDevices 2991 private boolean hasScheduledA2dpDockTimeout() { 2992 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 2993 } 2994 2995 private void handleA2dpConnectionStateChange(BluetoothDevice btDevice, int state) 2996 { 2997 if (btDevice == null) { 2998 return; 2999 } 3000 String address = btDevice.getAddress(); 3001 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3002 address = ""; 3003 } 3004 synchronized (mConnectedDevices) { 3005 boolean isConnected = 3006 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 3007 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 3008 3009 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 3010 if (btDevice.isBluetoothDock()) { 3011 if (state == BluetoothProfile.STATE_DISCONNECTED) { 3012 // introduction of a delay for transient disconnections of docks when 3013 // power is rapidly turned off/on, this message will be canceled if 3014 // we reconnect the dock under a preset delay 3015 makeA2dpDeviceUnavailableLater(address); 3016 // the next time isConnected is evaluated, it will be false for the dock 3017 } 3018 } else { 3019 makeA2dpDeviceUnavailableNow(address); 3020 } 3021 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 3022 if (btDevice.isBluetoothDock()) { 3023 // this could be a reconnection after a transient disconnection 3024 cancelA2dpDeviceTimeout(); 3025 mDockAddress = address; 3026 } else { 3027 // this could be a connection of another A2DP device before the timeout of 3028 // a dock: cancel the dock timeout, and make the dock unavailable now 3029 if(hasScheduledA2dpDockTimeout()) { 3030 cancelA2dpDeviceTimeout(); 3031 makeA2dpDeviceUnavailableNow(mDockAddress); 3032 } 3033 } 3034 makeA2dpDeviceAvailable(address); 3035 } 3036 } 3037 } 3038 3039 private boolean handleDeviceConnection(boolean connected, int device, String params) { 3040 synchronized (mConnectedDevices) { 3041 boolean isConnected = (mConnectedDevices.containsKey(device) && 3042 mConnectedDevices.get(device).equals(params)); 3043 3044 if (isConnected && !connected) { 3045 AudioSystem.setDeviceConnectionState(device, 3046 AudioSystem.DEVICE_STATE_UNAVAILABLE, 3047 params); 3048 mConnectedDevices.remove(device); 3049 return true; 3050 } else if (!isConnected && connected) { 3051 AudioSystem.setDeviceConnectionState(device, 3052 AudioSystem.DEVICE_STATE_AVAILABLE, 3053 params); 3054 mConnectedDevices.put(new Integer(device), params); 3055 return true; 3056 } 3057 } 3058 return false; 3059 } 3060 3061 /* cache of the address of the last dock the device was connected to */ 3062 private String mDockAddress; 3063 3064 /** 3065 * Receiver for misc intent broadcasts the Phone app cares about. 3066 */ 3067 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 3068 @Override 3069 public void onReceive(Context context, Intent intent) { 3070 String action = intent.getAction(); 3071 int device; 3072 int state; 3073 3074 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3075 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3076 Intent.EXTRA_DOCK_STATE_UNDOCKED); 3077 int config; 3078 switch (dockState) { 3079 case Intent.EXTRA_DOCK_STATE_DESK: 3080 config = AudioSystem.FORCE_BT_DESK_DOCK; 3081 break; 3082 case Intent.EXTRA_DOCK_STATE_CAR: 3083 config = AudioSystem.FORCE_BT_CAR_DOCK; 3084 break; 3085 case Intent.EXTRA_DOCK_STATE_LE_DESK: 3086 config = AudioSystem.FORCE_ANALOG_DOCK; 3087 break; 3088 case Intent.EXTRA_DOCK_STATE_HE_DESK: 3089 config = AudioSystem.FORCE_DIGITAL_DOCK; 3090 break; 3091 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3092 default: 3093 config = AudioSystem.FORCE_NONE; 3094 } 3095 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 3096 } else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) { 3097 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3098 BluetoothProfile.STATE_DISCONNECTED); 3099 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3100 3101 handleA2dpConnectionStateChange(btDevice, state); 3102 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 3103 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3104 BluetoothProfile.STATE_DISCONNECTED); 3105 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3106 String address = null; 3107 3108 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3109 if (btDevice == null) { 3110 return; 3111 } 3112 3113 address = btDevice.getAddress(); 3114 BluetoothClass btClass = btDevice.getBluetoothClass(); 3115 if (btClass != null) { 3116 switch (btClass.getDeviceClass()) { 3117 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3118 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3119 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3120 break; 3121 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3122 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3123 break; 3124 } 3125 } 3126 3127 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3128 address = ""; 3129 } 3130 3131 boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 3132 if (handleDeviceConnection(connected, device, address)) { 3133 synchronized (mScoClients) { 3134 if (connected) { 3135 mBluetoothHeadsetDevice = btDevice; 3136 } else { 3137 mBluetoothHeadsetDevice = null; 3138 resetBluetoothSco(); 3139 } 3140 } 3141 } 3142 } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) { 3143 state = intent.getIntExtra("state", 0); 3144 int microphone = intent.getIntExtra("microphone", 0); 3145 3146 if (microphone != 0) { 3147 device = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 3148 } else { 3149 device = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 3150 } 3151 handleDeviceConnection((state == 1), device, ""); 3152 } else if (action.equals(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG)) { 3153 state = intent.getIntExtra("state", 0); 3154 Log.v(TAG, "Broadcast Receiver: Got ACTION_ANALOG_AUDIO_DOCK_PLUG, state = "+state); 3155 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, ""); 3156 } else if (action.equals(Intent.ACTION_HDMI_AUDIO_PLUG)) { 3157 state = intent.getIntExtra("state", 0); 3158 Log.v(TAG, "Broadcast Receiver: Got ACTION_HDMI_AUDIO_PLUG, state = "+state); 3159 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_AUX_DIGITAL, ""); 3160 } else if (action.equals(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG)) { 3161 state = intent.getIntExtra("state", 0); 3162 Log.v(TAG, 3163 "Broadcast Receiver Got ACTION_DIGITAL_AUDIO_DOCK_PLUG, state = " + state); 3164 handleDeviceConnection((state == 1), AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, ""); 3165 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 3166 action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 3167 state = intent.getIntExtra("state", 0); 3168 int alsaCard = intent.getIntExtra("card", -1); 3169 int alsaDevice = intent.getIntExtra("device", -1); 3170 String params = "card=" + alsaCard + ";device=" + alsaDevice; 3171 device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3172 AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 3173 Log.v(TAG, "Broadcast Receiver: Got " 3174 + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3175 "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 3176 + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 3177 handleDeviceConnection((state == 1), device, params); 3178 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 3179 boolean broadcast = false; 3180 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 3181 synchronized (mScoClients) { 3182 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 3183 // broadcast intent if the connection was initated by AudioService 3184 if (!mScoClients.isEmpty() && 3185 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 3186 mScoAudioState == SCO_STATE_ACTIVATE_REQ || 3187 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 3188 broadcast = true; 3189 } 3190 switch (btState) { 3191 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 3192 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 3193 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3194 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3195 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3196 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3197 } 3198 break; 3199 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 3200 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 3201 mScoAudioState = SCO_STATE_INACTIVE; 3202 clearAllScoClients(0, false); 3203 break; 3204 case BluetoothHeadset.STATE_AUDIO_CONNECTING: 3205 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3206 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3207 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3208 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3209 } 3210 default: 3211 // do not broadcast CONNECTING or invalid state 3212 broadcast = false; 3213 break; 3214 } 3215 } 3216 if (broadcast) { 3217 broadcastScoConnectionState(scoAudioState); 3218 //FIXME: this is to maintain compatibility with deprecated intent 3219 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3220 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3221 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 3222 mContext.sendStickyBroadcast(newIntent); 3223 } 3224 } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 3225 mBootCompleted = true; 3226 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 3227 0, 0, null, 0); 3228 3229 mKeyguardManager = 3230 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 3231 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 3232 resetBluetoothSco(); 3233 getBluetoothHeadset(); 3234 //FIXME: this is to maintain compatibility with deprecated intent 3235 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3236 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3237 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 3238 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 3239 mContext.sendStickyBroadcast(newIntent); 3240 3241 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 3242 if (adapter != null) { 3243 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 3244 BluetoothProfile.A2DP); 3245 } 3246 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { 3247 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 3248 // a package is being removed, not replaced 3249 String packageName = intent.getData().getSchemeSpecificPart(); 3250 if (packageName != null) { 3251 removeMediaButtonReceiverForPackage(packageName); 3252 } 3253 } 3254 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 3255 AudioSystem.setParameters("screen_state=on"); 3256 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 3257 AudioSystem.setParameters("screen_state=off"); 3258 } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) { 3259 handleConfigurationChanged(context); 3260 } 3261 } 3262 } 3263 3264 //========================================================================================== 3265 // AudioFocus 3266 //========================================================================================== 3267 3268 /* constant to identify focus stack entry that is used to hold the focus while the phone 3269 * is ringing or during a call. Used by com.android.internal.telephony.CallManager when 3270 * entering and exiting calls. 3271 */ 3272 public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; 3273 3274 private final static Object mAudioFocusLock = new Object(); 3275 3276 private final static Object mRingingLock = new Object(); 3277 3278 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 3279 @Override 3280 public void onCallStateChanged(int state, String incomingNumber) { 3281 if (state == TelephonyManager.CALL_STATE_RINGING) { 3282 //Log.v(TAG, " CALL_STATE_RINGING"); 3283 synchronized(mRingingLock) { 3284 mIsRinging = true; 3285 } 3286 } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) 3287 || (state == TelephonyManager.CALL_STATE_IDLE)) { 3288 synchronized(mRingingLock) { 3289 mIsRinging = false; 3290 } 3291 } 3292 } 3293 }; 3294 3295 private void notifyTopOfAudioFocusStack() { 3296 // notify the top of the stack it gained focus 3297 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3298 if (canReassignAudioFocus()) { 3299 try { 3300 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3301 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 3302 } catch (RemoteException e) { 3303 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 3304 e.printStackTrace(); 3305 } 3306 } 3307 } 3308 } 3309 3310 private static class FocusStackEntry { 3311 public int mStreamType = -1;// no stream type 3312 public IAudioFocusDispatcher mFocusDispatcher = null; 3313 public IBinder mSourceRef = null; 3314 public String mClientId; 3315 public int mFocusChangeType; 3316 public AudioFocusDeathHandler mHandler; 3317 public String mPackageName; 3318 public int mCallingUid; 3319 3320 public FocusStackEntry() { 3321 } 3322 3323 public FocusStackEntry(int streamType, int duration, 3324 IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 3325 String pn, int uid) { 3326 mStreamType = streamType; 3327 mFocusDispatcher = afl; 3328 mSourceRef = source; 3329 mClientId = id; 3330 mFocusChangeType = duration; 3331 mHandler = hdlr; 3332 mPackageName = pn; 3333 mCallingUid = uid; 3334 } 3335 3336 public void unlinkToDeath() { 3337 try { 3338 if (mSourceRef != null && mHandler != null) { 3339 mSourceRef.unlinkToDeath(mHandler, 0); 3340 mHandler = null; 3341 } 3342 } catch (java.util.NoSuchElementException e) { 3343 Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); 3344 } 3345 } 3346 3347 @Override 3348 protected void finalize() throws Throwable { 3349 unlinkToDeath(); // unlink exception handled inside method 3350 super.finalize(); 3351 } 3352 } 3353 3354 private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 3355 3356 /** 3357 * Helper function: 3358 * Display in the log the current entries in the audio focus stack 3359 */ 3360 private void dumpFocusStack(PrintWriter pw) { 3361 pw.println("\nAudio Focus stack entries:"); 3362 synchronized(mAudioFocusLock) { 3363 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3364 while(stackIterator.hasNext()) { 3365 FocusStackEntry fse = stackIterator.next(); 3366 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 3367 + " -- duration: " + fse.mFocusChangeType 3368 + " -- uid: " + fse.mCallingUid); 3369 } 3370 } 3371 } 3372 3373 /** 3374 * Helper function: 3375 * Called synchronized on mAudioFocusLock 3376 * Remove a focus listener from the focus stack. 3377 * @param focusListenerToRemove the focus listener 3378 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 3379 * focus, notify the next item in the stack it gained focus. 3380 */ 3381 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 3382 // is the current top of the focus stack abandoning focus? (because of request, not death) 3383 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 3384 { 3385 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 3386 FocusStackEntry fse = mFocusStack.pop(); 3387 fse.unlinkToDeath(); 3388 if (signal) { 3389 // notify the new top of the stack it gained focus 3390 notifyTopOfAudioFocusStack(); 3391 // there's a new top of the stack, let the remote control know 3392 synchronized(mRCStack) { 3393 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3394 } 3395 } 3396 } else { 3397 // focus is abandoned by a client that's not at the top of the stack, 3398 // no need to update focus. 3399 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3400 while(stackIterator.hasNext()) { 3401 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3402 if(fse.mClientId.equals(clientToRemove)) { 3403 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3404 + fse.mClientId); 3405 stackIterator.remove(); 3406 fse.unlinkToDeath(); 3407 } 3408 } 3409 } 3410 } 3411 3412 /** 3413 * Helper function: 3414 * Called synchronized on mAudioFocusLock 3415 * Remove focus listeners from the focus stack for a particular client when it has died. 3416 */ 3417 private void removeFocusStackEntryForClient(IBinder cb) { 3418 // is the owner of the audio focus part of the client to remove? 3419 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 3420 mFocusStack.peek().mSourceRef.equals(cb); 3421 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3422 while(stackIterator.hasNext()) { 3423 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3424 if(fse.mSourceRef.equals(cb)) { 3425 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3426 + fse.mClientId); 3427 stackIterator.remove(); 3428 // the client just died, no need to unlink to its death 3429 } 3430 } 3431 if (isTopOfStackForClientToRemove) { 3432 // we removed an entry at the top of the stack: 3433 // notify the new top of the stack it gained focus. 3434 notifyTopOfAudioFocusStack(); 3435 // there's a new top of the stack, let the remote control know 3436 synchronized(mRCStack) { 3437 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3438 } 3439 } 3440 } 3441 3442 /** 3443 * Helper function: 3444 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 3445 */ 3446 private boolean canReassignAudioFocus() { 3447 // focus requests are rejected during a phone call or when the phone is ringing 3448 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 3449 if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { 3450 return false; 3451 } 3452 return true; 3453 } 3454 3455 /** 3456 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 3457 * stack if necessary. 3458 */ 3459 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 3460 private IBinder mCb; // To be notified of client's death 3461 3462 AudioFocusDeathHandler(IBinder cb) { 3463 mCb = cb; 3464 } 3465 3466 public void binderDied() { 3467 synchronized(mAudioFocusLock) { 3468 Log.w(TAG, " AudioFocus audio focus client died"); 3469 removeFocusStackEntryForClient(mCb); 3470 } 3471 } 3472 3473 public IBinder getBinder() { 3474 return mCb; 3475 } 3476 } 3477 3478 3479 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 3480 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 3481 IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 3482 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 3483 // the main stream type for the audio focus request is currently not used. It may 3484 // potentially be used to handle multiple stream type-dependent audio focuses. 3485 3486 // we need a valid binder callback for clients 3487 if (!cb.pingBinder()) { 3488 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 3489 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3490 } 3491 3492 synchronized(mAudioFocusLock) { 3493 if (!canReassignAudioFocus()) { 3494 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3495 } 3496 3497 // handle the potential premature death of the new holder of the focus 3498 // (premature death == death before abandoning focus) 3499 // Register for client death notification 3500 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 3501 try { 3502 cb.linkToDeath(afdh, 0); 3503 } catch (RemoteException e) { 3504 // client has already died! 3505 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 3506 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3507 } 3508 3509 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 3510 // if focus is already owned by this client and the reason for acquiring the focus 3511 // hasn't changed, don't do anything 3512 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 3513 // unlink death handler so it can be gc'ed. 3514 // linkToDeath() creates a JNI global reference preventing collection. 3515 cb.unlinkToDeath(afdh, 0); 3516 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3517 } 3518 // the reason for the audio focus request has changed: remove the current top of 3519 // stack and respond as if we had a new focus owner 3520 FocusStackEntry fse = mFocusStack.pop(); 3521 fse.unlinkToDeath(); 3522 } 3523 3524 // notify current top of stack it is losing focus 3525 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3526 try { 3527 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3528 -1 * focusChangeHint, // loss and gain codes are inverse of each other 3529 mFocusStack.peek().mClientId); 3530 } catch (RemoteException e) { 3531 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 3532 e.printStackTrace(); 3533 } 3534 } 3535 3536 // focus requester might already be somewhere below in the stack, remove it 3537 removeFocusStackEntry(clientId, false /* signal */); 3538 3539 // push focus requester at the top of the audio focus stack 3540 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, 3541 clientId, afdh, callingPackageName, Binder.getCallingUid())); 3542 3543 // there's a new top of the stack, let the remote control know 3544 synchronized(mRCStack) { 3545 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 3546 } 3547 }//synchronized(mAudioFocusLock) 3548 3549 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3550 } 3551 3552 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 3553 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 3554 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 3555 try { 3556 // this will take care of notifying the new focus owner if needed 3557 synchronized(mAudioFocusLock) { 3558 removeFocusStackEntry(clientId, true); 3559 } 3560 } catch (java.util.ConcurrentModificationException cme) { 3561 // Catching this exception here is temporary. It is here just to prevent 3562 // a crash seen when the "Silent" notification is played. This is believed to be fixed 3563 // but this try catch block is left just to be safe. 3564 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 3565 cme.printStackTrace(); 3566 } 3567 3568 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3569 } 3570 3571 3572 public void unregisterAudioFocusClient(String clientId) { 3573 synchronized(mAudioFocusLock) { 3574 removeFocusStackEntry(clientId, false); 3575 } 3576 } 3577 3578 3579 //========================================================================================== 3580 // RemoteControl 3581 //========================================================================================== 3582 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 3583 dispatchMediaKeyEvent(keyEvent, false /*needWakeLock*/); 3584 } 3585 3586 public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 3587 dispatchMediaKeyEvent(keyEvent, true /*needWakeLock*/); 3588 } 3589 3590 /** 3591 * Handles the dispatching of the media button events to one of the registered listeners, 3592 * or if there was none, broadcast a ACTION_MEDIA_BUTTON intent to the rest of the system. 3593 */ 3594 private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3595 // sanity check on the incoming key event 3596 if (!isValidMediaKeyEvent(keyEvent)) { 3597 Log.e(TAG, "not dispatching invalid media key event " + keyEvent); 3598 return; 3599 } 3600 // event filtering 3601 synchronized(mRingingLock) { 3602 if (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL) || 3603 (getMode() == AudioSystem.MODE_IN_COMMUNICATION) || 3604 (getMode() == AudioSystem.MODE_RINGTONE) ) { 3605 return; 3606 } 3607 } 3608 if (needWakeLock) { 3609 mMediaEventWakeLock.acquire(); 3610 } 3611 Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3612 keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3613 synchronized(mRCStack) { 3614 if (!mRCStack.empty()) { 3615 // send the intent that was registered by the client 3616 try { 3617 mRCStack.peek().mMediaIntent.send(mContext, 3618 needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, 3619 keyIntent, AudioService.this, mAudioHandler); 3620 } catch (CanceledException e) { 3621 Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); 3622 e.printStackTrace(); 3623 } 3624 } else { 3625 // legacy behavior when nobody registered their media button event receiver 3626 // through AudioManager 3627 if (needWakeLock) { 3628 keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3629 } 3630 mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3631 mAudioHandler, Activity.RESULT_OK, null, null); 3632 } 3633 } 3634 } 3635 3636 private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { 3637 if (keyEvent == null) { 3638 return false; 3639 } 3640 final int keyCode = keyEvent.getKeyCode(); 3641 switch (keyCode) { 3642 case KeyEvent.KEYCODE_MUTE: 3643 case KeyEvent.KEYCODE_HEADSETHOOK: 3644 case KeyEvent.KEYCODE_MEDIA_PLAY: 3645 case KeyEvent.KEYCODE_MEDIA_PAUSE: 3646 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 3647 case KeyEvent.KEYCODE_MEDIA_STOP: 3648 case KeyEvent.KEYCODE_MEDIA_NEXT: 3649 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 3650 case KeyEvent.KEYCODE_MEDIA_REWIND: 3651 case KeyEvent.KEYCODE_MEDIA_RECORD: 3652 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 3653 case KeyEvent.KEYCODE_MEDIA_CLOSE: 3654 case KeyEvent.KEYCODE_MEDIA_EJECT: 3655 break; 3656 default: 3657 return false; 3658 } 3659 return true; 3660 } 3661 3662 private PowerManager.WakeLock mMediaEventWakeLock; 3663 3664 private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number 3665 3666 // only set when wakelock was acquired, no need to check value when received 3667 private static final String EXTRA_WAKELOCK_ACQUIRED = 3668 "android.media.AudioService.WAKELOCK_ACQUIRED"; 3669 3670 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 3671 int resultCode, String resultData, Bundle resultExtras) { 3672 if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { 3673 mMediaEventWakeLock.release(); 3674 } 3675 } 3676 3677 BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { 3678 public void onReceive(Context context, Intent intent) { 3679 if (intent.getExtras().containsKey(EXTRA_WAKELOCK_ACQUIRED)) { 3680 mMediaEventWakeLock.release(); 3681 } 3682 } 3683 }; 3684 3685 private final Object mCurrentRcLock = new Object(); 3686 /** 3687 * The one remote control client which will receive a request for display information. 3688 * This object may be null. 3689 * Access protected by mCurrentRcLock. 3690 */ 3691 private IRemoteControlClient mCurrentRcClient = null; 3692 3693 private final static int RC_INFO_NONE = 0; 3694 private final static int RC_INFO_ALL = 3695 RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | 3696 RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | 3697 RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | 3698 RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; 3699 3700 /** 3701 * A monotonically increasing generation counter for mCurrentRcClient. 3702 * Only accessed with a lock on mCurrentRcLock. 3703 * No value wrap-around issues as we only act on equal values. 3704 */ 3705 private int mCurrentRcClientGen = 0; 3706 3707 /** 3708 * Inner class to monitor remote control client deaths, and remove the client for the 3709 * remote control stack if necessary. 3710 */ 3711 private class RcClientDeathHandler implements IBinder.DeathRecipient { 3712 private IBinder mCb; // To be notified of client's death 3713 private PendingIntent mMediaIntent; 3714 3715 RcClientDeathHandler(IBinder cb, PendingIntent pi) { 3716 mCb = cb; 3717 mMediaIntent = pi; 3718 } 3719 3720 public void binderDied() { 3721 Log.w(TAG, " RemoteControlClient died"); 3722 // remote control client died, make sure the displays don't use it anymore 3723 // by setting its remote control client to null 3724 registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); 3725 } 3726 3727 public IBinder getBinder() { 3728 return mCb; 3729 } 3730 } 3731 3732 private static class RemoteControlStackEntry { 3733 /** 3734 * The target for the ACTION_MEDIA_BUTTON events. 3735 * Always non null. 3736 */ 3737 public PendingIntent mMediaIntent; 3738 /** 3739 * The registered media button event receiver. 3740 * Always non null. 3741 */ 3742 public ComponentName mReceiverComponent; 3743 public String mCallingPackageName; 3744 public int mCallingUid; 3745 /** 3746 * Provides access to the information to display on the remote control. 3747 * May be null (when a media button event receiver is registered, 3748 * but no remote control client has been registered) */ 3749 public IRemoteControlClient mRcClient; 3750 public RcClientDeathHandler mRcClientDeathHandler; 3751 3752 /** precondition: mediaIntent != null, eventReceiver != null */ 3753 public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { 3754 mMediaIntent = mediaIntent; 3755 mReceiverComponent = eventReceiver; 3756 mCallingUid = -1; 3757 mRcClient = null; 3758 } 3759 3760 public void unlinkToRcClientDeath() { 3761 if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { 3762 try { 3763 mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); 3764 mRcClientDeathHandler = null; 3765 } catch (java.util.NoSuchElementException e) { 3766 // not much we can do here 3767 Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); 3768 e.printStackTrace(); 3769 } 3770 } 3771 } 3772 3773 @Override 3774 protected void finalize() throws Throwable { 3775 unlinkToRcClientDeath();// unlink exception handled inside method 3776 super.finalize(); 3777 } 3778 } 3779 3780 /** 3781 * The stack of remote control event receivers. 3782 * Code sections and methods that modify the remote control event receiver stack are 3783 * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either 3784 * stack, audio focus or RC, can lead to a change in the remote control display 3785 */ 3786 private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 3787 3788 /** 3789 * Helper function: 3790 * Display in the log the current entries in the remote control focus stack 3791 */ 3792 private void dumpRCStack(PrintWriter pw) { 3793 pw.println("\nRemote Control stack entries:"); 3794 synchronized(mRCStack) { 3795 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3796 while(stackIterator.hasNext()) { 3797 RemoteControlStackEntry rcse = stackIterator.next(); 3798 pw.println(" pi: " + rcse.mMediaIntent + 3799 " -- ercvr: " + rcse.mReceiverComponent + 3800 " -- client: " + rcse.mRcClient + 3801 " -- uid: " + rcse.mCallingUid); 3802 } 3803 } 3804 } 3805 3806 /** 3807 * Helper function: 3808 * Remove any entry in the remote control stack that has the same package name as packageName 3809 * Pre-condition: packageName != null 3810 */ 3811 private void removeMediaButtonReceiverForPackage(String packageName) { 3812 synchronized(mRCStack) { 3813 if (mRCStack.empty()) { 3814 return; 3815 } else { 3816 RemoteControlStackEntry oldTop = mRCStack.peek(); 3817 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3818 // iterate over the stack entries 3819 while(stackIterator.hasNext()) { 3820 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 3821 if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) { 3822 // a stack entry is from the package being removed, remove it from the stack 3823 stackIterator.remove(); 3824 rcse.unlinkToRcClientDeath(); 3825 } 3826 } 3827 if (mRCStack.empty()) { 3828 // no saved media button receiver 3829 mAudioHandler.sendMessage( 3830 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 3831 null)); 3832 } else if (oldTop != mRCStack.peek()) { 3833 // the top of the stack has changed, save it in the system settings 3834 // by posting a message to persist it 3835 mAudioHandler.sendMessage( 3836 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 3837 mRCStack.peek().mReceiverComponent)); 3838 } 3839 } 3840 } 3841 } 3842 3843 /** 3844 * Helper function: 3845 * Restore remote control receiver from the system settings. 3846 */ 3847 private void restoreMediaButtonReceiver() { 3848 String receiverName = Settings.System.getString(mContentResolver, 3849 Settings.System.MEDIA_BUTTON_RECEIVER); 3850 if ((null != receiverName) && !receiverName.isEmpty()) { 3851 ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); 3852 // construct a PendingIntent targeted to the restored component name 3853 // for the media button and register it 3854 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 3855 // the associated intent will be handled by the component being registered 3856 mediaButtonIntent.setComponent(eventReceiver); 3857 PendingIntent pi = PendingIntent.getBroadcast(mContext, 3858 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 3859 registerMediaButtonIntent(pi, eventReceiver); 3860 } 3861 } 3862 3863 /** 3864 * Helper function: 3865 * Set the new remote control receiver at the top of the RC focus stack. 3866 * precondition: mediaIntent != null, target != null 3867 */ 3868 private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) { 3869 // already at top of stack? 3870 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { 3871 return; 3872 } 3873 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3874 RemoteControlStackEntry rcse = null; 3875 boolean wasInsideStack = false; 3876 while(stackIterator.hasNext()) { 3877 rcse = (RemoteControlStackEntry)stackIterator.next(); 3878 if(rcse.mMediaIntent.equals(mediaIntent)) { 3879 wasInsideStack = true; 3880 stackIterator.remove(); 3881 break; 3882 } 3883 } 3884 if (!wasInsideStack) { 3885 rcse = new RemoteControlStackEntry(mediaIntent, target); 3886 } 3887 mRCStack.push(rcse); 3888 3889 // post message to persist the default media button receiver 3890 mAudioHandler.sendMessage( mAudioHandler.obtainMessage( 3891 MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); 3892 } 3893 3894 /** 3895 * Helper function: 3896 * Remove the remote control receiver from the RC focus stack. 3897 * precondition: pi != null 3898 */ 3899 private void removeMediaButtonReceiver(PendingIntent pi) { 3900 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3901 while(stackIterator.hasNext()) { 3902 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 3903 if(rcse.mMediaIntent.equals(pi)) { 3904 stackIterator.remove(); 3905 rcse.unlinkToRcClientDeath(); 3906 break; 3907 } 3908 } 3909 } 3910 3911 /** 3912 * Helper function: 3913 * Called synchronized on mRCStack 3914 */ 3915 private boolean isCurrentRcController(PendingIntent pi) { 3916 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { 3917 return true; 3918 } 3919 return false; 3920 } 3921 3922 //========================================================================================== 3923 // Remote control display / client 3924 //========================================================================================== 3925 /** 3926 * Update the remote control displays with the new "focused" client generation 3927 */ 3928 private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, 3929 PendingIntent newMediaIntent, boolean clearing) { 3930 // NOTE: Only one IRemoteControlDisplay supported in this implementation 3931 if (mRcDisplay != null) { 3932 try { 3933 mRcDisplay.setCurrentClientId( 3934 newClientGeneration, newMediaIntent, clearing); 3935 } catch (RemoteException e) { 3936 Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e); 3937 // if we had a display before, stop monitoring its death 3938 rcDisplay_stopDeathMonitor_syncRcStack(); 3939 mRcDisplay = null; 3940 } 3941 } 3942 } 3943 3944 /** 3945 * Update the remote control clients with the new "focused" client generation 3946 */ 3947 private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { 3948 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 3949 while(stackIterator.hasNext()) { 3950 RemoteControlStackEntry se = stackIterator.next(); 3951 if ((se != null) && (se.mRcClient != null)) { 3952 try { 3953 se.mRcClient.setCurrentClientGenerationId(newClientGeneration); 3954 } catch (RemoteException e) { 3955 Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e); 3956 stackIterator.remove(); 3957 se.unlinkToRcClientDeath(); 3958 } 3959 } 3960 } 3961 } 3962 3963 /** 3964 * Update the displays and clients with the new "focused" client generation and name 3965 * @param newClientGeneration the new generation value matching a client update 3966 * @param newClientEventReceiver the media button event receiver associated with the client. 3967 * May be null, which implies there is no registered media button event receiver. 3968 * @param clearing true if the new client generation value maps to a remote control update 3969 * where the display should be cleared. 3970 */ 3971 private void setNewRcClient_syncRcsCurrc(int newClientGeneration, 3972 PendingIntent newMediaIntent, boolean clearing) { 3973 // send the new valid client generation ID to all displays 3974 setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); 3975 // send the new valid client generation ID to all clients 3976 setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); 3977 } 3978 3979 /** 3980 * Called when processing MSG_RCDISPLAY_CLEAR event 3981 */ 3982 private void onRcDisplayClear() { 3983 if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); 3984 3985 synchronized(mRCStack) { 3986 synchronized(mCurrentRcLock) { 3987 mCurrentRcClientGen++; 3988 // synchronously update the displays and clients with the new client generation 3989 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 3990 null /*newMediaIntent*/, true /*clearing*/); 3991 } 3992 } 3993 } 3994 3995 /** 3996 * Called when processing MSG_RCDISPLAY_UPDATE event 3997 */ 3998 private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { 3999 synchronized(mRCStack) { 4000 synchronized(mCurrentRcLock) { 4001 if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { 4002 if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); 4003 4004 mCurrentRcClientGen++; 4005 // synchronously update the displays and clients with 4006 // the new client generation 4007 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4008 rcse.mMediaIntent /*newMediaIntent*/, 4009 false /*clearing*/); 4010 4011 // tell the current client that it needs to send info 4012 try { 4013 mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, 4014 flags, mArtworkExpectedWidth, mArtworkExpectedHeight); 4015 } catch (RemoteException e) { 4016 Log.e(TAG, "Current valid remote client is dead: "+e); 4017 mCurrentRcClient = null; 4018 } 4019 } else { 4020 // the remote control display owner has changed between the 4021 // the message to update the display was sent, and the time it 4022 // gets to be processed (now) 4023 } 4024 } 4025 } 4026 } 4027 4028 4029 /** 4030 * Helper function: 4031 * Called synchronized on mRCStack 4032 */ 4033 private void clearRemoteControlDisplay_syncAfRcs() { 4034 synchronized(mCurrentRcLock) { 4035 mCurrentRcClient = null; 4036 } 4037 // will cause onRcDisplayClear() to be called in AudioService's handler thread 4038 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); 4039 } 4040 4041 /** 4042 * Helper function for code readability: only to be called from 4043 * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for 4044 * this method. 4045 * Preconditions: 4046 * - called synchronized mAudioFocusLock then on mRCStack 4047 * - mRCStack.isEmpty() is false 4048 */ 4049 private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 4050 RemoteControlStackEntry rcse = mRCStack.peek(); 4051 int infoFlagsAboutToBeUsed = infoChangedFlags; 4052 // this is where we enforce opt-in for information display on the remote controls 4053 // with the new AudioManager.registerRemoteControlClient() API 4054 if (rcse.mRcClient == null) { 4055 //Log.w(TAG, "Can't update remote control display with null remote control client"); 4056 clearRemoteControlDisplay_syncAfRcs(); 4057 return; 4058 } 4059 synchronized(mCurrentRcLock) { 4060 if (!rcse.mRcClient.equals(mCurrentRcClient)) { 4061 // new RC client, assume every type of information shall be queried 4062 infoFlagsAboutToBeUsed = RC_INFO_ALL; 4063 } 4064 mCurrentRcClient = rcse.mRcClient; 4065 } 4066 // will cause onRcDisplayUpdate() to be called in AudioService's handler thread 4067 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 4068 infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); 4069 } 4070 4071 /** 4072 * Helper function: 4073 * Called synchronized on mAudioFocusLock, then mRCStack 4074 * Check whether the remote control display should be updated, triggers the update if required 4075 * @param infoChangedFlags the flags corresponding to the remote control client information 4076 * that has changed, if applicable (checking for the update conditions might trigger a 4077 * clear, rather than an update event). 4078 */ 4079 private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 4080 // determine whether the remote control display should be refreshed 4081 // if either stack is empty, there is a mismatch, so clear the RC display 4082 if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { 4083 clearRemoteControlDisplay_syncAfRcs(); 4084 return; 4085 } 4086 // if the top of the two stacks belong to different packages, there is a mismatch, clear 4087 if ((mRCStack.peek().mCallingPackageName != null) 4088 && (mFocusStack.peek().mPackageName != null) 4089 && !(mRCStack.peek().mCallingPackageName.compareTo( 4090 mFocusStack.peek().mPackageName) == 0)) { 4091 clearRemoteControlDisplay_syncAfRcs(); 4092 return; 4093 } 4094 // if the audio focus didn't originate from the same Uid as the one in which the remote 4095 // control information will be retrieved, clear 4096 if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { 4097 clearRemoteControlDisplay_syncAfRcs(); 4098 return; 4099 } 4100 // refresh conditions were verified: update the remote controls 4101 // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty 4102 updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); 4103 } 4104 4105 /** 4106 * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) 4107 * precondition: mediaIntent != null, target != null 4108 */ 4109 public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { 4110 Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); 4111 4112 synchronized(mAudioFocusLock) { 4113 synchronized(mRCStack) { 4114 pushMediaButtonReceiver(mediaIntent, eventReceiver); 4115 // new RC client, assume every type of information shall be queried 4116 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4117 } 4118 } 4119 } 4120 4121 /** 4122 * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) 4123 * precondition: mediaIntent != null, eventReceiver != null 4124 */ 4125 public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) 4126 { 4127 Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); 4128 4129 synchronized(mAudioFocusLock) { 4130 synchronized(mRCStack) { 4131 boolean topOfStackWillChange = isCurrentRcController(mediaIntent); 4132 removeMediaButtonReceiver(mediaIntent); 4133 if (topOfStackWillChange) { 4134 // current RC client will change, assume every type of info needs to be queried 4135 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4136 } 4137 } 4138 } 4139 } 4140 4141 /** 4142 * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) 4143 * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient 4144 * without modifying the RC stack, but while still causing the display to refresh (will 4145 * become blank as a result of this) 4146 */ 4147 public void registerRemoteControlClient(PendingIntent mediaIntent, 4148 IRemoteControlClient rcClient, String callingPackageName) { 4149 if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); 4150 synchronized(mAudioFocusLock) { 4151 synchronized(mRCStack) { 4152 // store the new display information 4153 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4154 while(stackIterator.hasNext()) { 4155 RemoteControlStackEntry rcse = stackIterator.next(); 4156 if(rcse.mMediaIntent.equals(mediaIntent)) { 4157 // already had a remote control client? 4158 if (rcse.mRcClientDeathHandler != null) { 4159 // stop monitoring the old client's death 4160 rcse.unlinkToRcClientDeath(); 4161 } 4162 // save the new remote control client 4163 rcse.mRcClient = rcClient; 4164 rcse.mCallingPackageName = callingPackageName; 4165 rcse.mCallingUid = Binder.getCallingUid(); 4166 if (rcClient == null) { 4167 // here rcse.mRcClientDeathHandler is null; 4168 break; 4169 } 4170 4171 // there is a new (non-null) client: 4172 // 1/ give the new client the current display (if any) 4173 if (mRcDisplay != null) { 4174 try { 4175 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4176 } catch (RemoteException e) { 4177 Log.e(TAG, "Error connecting remote control display to client: "+e); 4178 e.printStackTrace(); 4179 } 4180 } 4181 // 2/ monitor the new client's death 4182 IBinder b = rcse.mRcClient.asBinder(); 4183 RcClientDeathHandler rcdh = 4184 new RcClientDeathHandler(b, rcse.mMediaIntent); 4185 try { 4186 b.linkToDeath(rcdh, 0); 4187 } catch (RemoteException e) { 4188 // remote control client is DOA, disqualify it 4189 Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); 4190 rcse.mRcClient = null; 4191 } 4192 rcse.mRcClientDeathHandler = rcdh; 4193 break; 4194 } 4195 } 4196 // if the eventReceiver is at the top of the stack 4197 // then check for potential refresh of the remote controls 4198 if (isCurrentRcController(mediaIntent)) { 4199 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4200 } 4201 } 4202 } 4203 } 4204 4205 /** 4206 * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) 4207 * rcClient is guaranteed non-null 4208 */ 4209 public void unregisterRemoteControlClient(PendingIntent mediaIntent, 4210 IRemoteControlClient rcClient) { 4211 synchronized(mAudioFocusLock) { 4212 synchronized(mRCStack) { 4213 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4214 while(stackIterator.hasNext()) { 4215 RemoteControlStackEntry rcse = stackIterator.next(); 4216 if ((rcse.mMediaIntent.equals(mediaIntent)) 4217 && rcClient.equals(rcse.mRcClient)) { 4218 // we found the IRemoteControlClient to unregister 4219 // stop monitoring its death 4220 rcse.unlinkToRcClientDeath(); 4221 // reset the client-related fields 4222 rcse.mRcClient = null; 4223 rcse.mCallingPackageName = null; 4224 } 4225 } 4226 } 4227 } 4228 } 4229 4230 /** 4231 * The remote control displays. 4232 * Access synchronized on mRCStack 4233 * NOTE: Only one IRemoteControlDisplay supported in this implementation 4234 */ 4235 private IRemoteControlDisplay mRcDisplay; 4236 private RcDisplayDeathHandler mRcDisplayDeathHandler; 4237 private int mArtworkExpectedWidth = -1; 4238 private int mArtworkExpectedHeight = -1; 4239 /** 4240 * Inner class to monitor remote control display deaths, and unregister them from the list 4241 * of displays if necessary. 4242 */ 4243 private class RcDisplayDeathHandler implements IBinder.DeathRecipient { 4244 private IBinder mCb; // To be notified of client's death 4245 4246 public RcDisplayDeathHandler(IBinder b) { 4247 if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b); 4248 mCb = b; 4249 } 4250 4251 public void binderDied() { 4252 synchronized(mRCStack) { 4253 Log.w(TAG, "RemoteControl: display died"); 4254 mRcDisplay = null; 4255 } 4256 } 4257 4258 public void unlinkToRcDisplayDeath() { 4259 if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb); 4260 try { 4261 mCb.unlinkToDeath(this, 0); 4262 } catch (java.util.NoSuchElementException e) { 4263 // not much we can do here, the display was being unregistered anyway 4264 Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()"); 4265 e.printStackTrace(); 4266 } 4267 } 4268 4269 } 4270 4271 private void rcDisplay_stopDeathMonitor_syncRcStack() { 4272 if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null) 4273 // we had a display before, stop monitoring its death 4274 mRcDisplayDeathHandler.unlinkToRcDisplayDeath(); 4275 } 4276 } 4277 4278 private void rcDisplay_startDeathMonitor_syncRcStack() { 4279 if (mRcDisplay != null) { 4280 // new non-null display, monitor its death 4281 IBinder b = mRcDisplay.asBinder(); 4282 mRcDisplayDeathHandler = new RcDisplayDeathHandler(b); 4283 try { 4284 b.linkToDeath(mRcDisplayDeathHandler, 0); 4285 } catch (RemoteException e) { 4286 // remote control display is DOA, disqualify it 4287 Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b); 4288 mRcDisplay = null; 4289 } 4290 } 4291 } 4292 4293 /** 4294 * Register an IRemoteControlDisplay. 4295 * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient 4296 * at the top of the stack to update the new display with its information. 4297 * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. 4298 * @param rcd the IRemoteControlDisplay to register. No effect if null. 4299 */ 4300 public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { 4301 if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); 4302 synchronized(mAudioFocusLock) { 4303 synchronized(mRCStack) { 4304 if ((mRcDisplay == rcd) || (rcd == null)) { 4305 return; 4306 } 4307 // if we had a display before, stop monitoring its death 4308 rcDisplay_stopDeathMonitor_syncRcStack(); 4309 mRcDisplay = rcd; 4310 // new display, start monitoring its death 4311 rcDisplay_startDeathMonitor_syncRcStack(); 4312 4313 // let all the remote control clients there is a new display 4314 // no need to unplug the previous because we only support one display 4315 // and the clients don't track the death of the display 4316 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4317 while(stackIterator.hasNext()) { 4318 RemoteControlStackEntry rcse = stackIterator.next(); 4319 if(rcse.mRcClient != null) { 4320 try { 4321 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4322 } catch (RemoteException e) { 4323 Log.e(TAG, "Error connecting remote control display to client: " + e); 4324 e.printStackTrace(); 4325 } 4326 } 4327 } 4328 4329 // we have a new display, of which all the clients are now aware: have it be updated 4330 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4331 } 4332 } 4333 } 4334 4335 /** 4336 * Unregister an IRemoteControlDisplay. 4337 * Since only one IRemoteControlDisplay is supported, this has no effect if the one to 4338 * unregister is not the current one. 4339 * @param rcd the IRemoteControlDisplay to unregister. No effect if null. 4340 */ 4341 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 4342 if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); 4343 synchronized(mRCStack) { 4344 // only one display here, so you can only unregister the current display 4345 if ((rcd == null) || (rcd != mRcDisplay)) { 4346 if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); 4347 return; 4348 } 4349 // if we had a display before, stop monitoring its death 4350 rcDisplay_stopDeathMonitor_syncRcStack(); 4351 mRcDisplay = null; 4352 4353 // disconnect this remote control display from all the clients 4354 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4355 while(stackIterator.hasNext()) { 4356 RemoteControlStackEntry rcse = stackIterator.next(); 4357 if(rcse.mRcClient != null) { 4358 try { 4359 rcse.mRcClient.unplugRemoteControlDisplay(rcd); 4360 } catch (RemoteException e) { 4361 Log.e(TAG, "Error disconnecting remote control display to client: " + e); 4362 e.printStackTrace(); 4363 } 4364 } 4365 } 4366 } 4367 } 4368 4369 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 4370 synchronized(mRCStack) { 4371 // NOTE: Only one IRemoteControlDisplay supported in this implementation 4372 mArtworkExpectedWidth = w; 4373 mArtworkExpectedHeight = h; 4374 } 4375 } 4376 4377 //========================================================================================== 4378 // Device orientation 4379 //========================================================================================== 4380 /** 4381 * Handles device configuration changes that may map to a change in the orientation. 4382 * This feature is optional, and is defined by the definition and value of the 4383 * "ro.audio.monitorOrientation" system property. 4384 */ 4385 private void handleConfigurationChanged(Context context) { 4386 try { 4387 // reading new orientation "safely" (i.e. under try catch) in case anything 4388 // goes wrong when obtaining resources and configuration 4389 int newOrientation = context.getResources().getConfiguration().orientation; 4390 if (newOrientation != mDeviceOrientation) { 4391 mDeviceOrientation = newOrientation; 4392 setOrientationForAudioSystem(); 4393 } 4394 } catch (Exception e) { 4395 Log.e(TAG, "Error retrieving device orientation: " + e); 4396 } 4397 } 4398 4399 private void setOrientationForAudioSystem() { 4400 switch (mDeviceOrientation) { 4401 case Configuration.ORIENTATION_LANDSCAPE: 4402 //Log.i(TAG, "orientation is landscape"); 4403 AudioSystem.setParameters("orientation=landscape"); 4404 break; 4405 case Configuration.ORIENTATION_PORTRAIT: 4406 //Log.i(TAG, "orientation is portrait"); 4407 AudioSystem.setParameters("orientation=portrait"); 4408 break; 4409 case Configuration.ORIENTATION_SQUARE: 4410 //Log.i(TAG, "orientation is square"); 4411 AudioSystem.setParameters("orientation=square"); 4412 break; 4413 case Configuration.ORIENTATION_UNDEFINED: 4414 //Log.i(TAG, "orientation is undefined"); 4415 AudioSystem.setParameters("orientation=undefined"); 4416 break; 4417 default: 4418 Log.e(TAG, "Unknown orientation"); 4419 } 4420 } 4421 4422 4423 @Override 4424 public void setRingtonePlayer(IRingtonePlayer player) { 4425 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 4426 mRingtonePlayer = player; 4427 } 4428 4429 @Override 4430 public IRingtonePlayer getRingtonePlayer() { 4431 return mRingtonePlayer; 4432 } 4433 4434 @Override 4435 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4436 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 4437 4438 // TODO probably a lot more to do here than just the audio focus and remote control stacks 4439 dumpFocusStack(pw); 4440 dumpRCStack(pw); 4441 dumpStreamStates(pw); 4442 } 4443} 4444