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