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