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