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