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