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