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