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