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