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