AudioService.java revision dd45d01128423a82652a3c9d77fa393631d95229
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK; 20import static android.media.AudioManager.RINGER_MODE_NORMAL; 21import static android.media.AudioManager.RINGER_MODE_SILENT; 22import static android.media.AudioManager.RINGER_MODE_VIBRATE; 23 24import android.app.Activity; 25import android.app.ActivityManagerNative; 26import android.app.KeyguardManager; 27import android.app.PendingIntent; 28import android.app.PendingIntent.CanceledException; 29import android.app.PendingIntent.OnFinished; 30import android.bluetooth.BluetoothA2dp; 31import android.bluetooth.BluetoothAdapter; 32import android.bluetooth.BluetoothClass; 33import android.bluetooth.BluetoothDevice; 34import android.bluetooth.BluetoothHeadset; 35import android.bluetooth.BluetoothProfile; 36import android.content.ActivityNotFoundException; 37import android.content.BroadcastReceiver; 38import android.content.ComponentName; 39import android.content.ContentResolver; 40import android.content.Context; 41import android.content.Intent; 42import android.content.IntentFilter; 43import android.content.pm.PackageManager; 44import android.content.res.Configuration; 45import android.database.ContentObserver; 46import android.media.MediaPlayer.OnCompletionListener; 47import android.media.MediaPlayer.OnErrorListener; 48import android.os.Binder; 49import android.os.Bundle; 50import android.os.Environment; 51import android.os.Handler; 52import android.os.IBinder; 53import android.os.Looper; 54import android.os.Message; 55import android.os.PowerManager; 56import android.os.RemoteCallbackList; 57import android.os.RemoteException; 58import android.os.ServiceManager; 59import android.os.SystemProperties; 60import android.os.UserHandle; 61import android.os.Vibrator; 62import android.provider.Settings; 63import android.provider.Settings.System; 64import android.speech.RecognizerIntent; 65import android.telephony.PhoneStateListener; 66import android.telephony.ServiceState; 67import android.telephony.TelephonyManager; 68import android.text.TextUtils; 69import android.util.Log; 70import android.view.KeyEvent; 71import android.view.VolumePanel; 72 73import com.android.internal.telephony.ITelephony; 74 75import java.io.FileDescriptor; 76import java.io.IOException; 77import java.io.PrintWriter; 78import java.util.ArrayList; 79import java.util.concurrent.ConcurrentHashMap; 80import java.util.HashMap; 81import java.util.Iterator; 82import java.util.List; 83import java.util.Map; 84import java.util.NoSuchElementException; 85import java.util.Set; 86import java.util.Stack; 87 88/** 89 * The implementation of the volume manager service. 90 * <p> 91 * This implementation focuses on delivering a responsive UI. Most methods are 92 * asynchronous to external calls. For example, the task of setting a volume 93 * will update our internal state, but in a separate thread will set the system 94 * volume and later persist to the database. Similarly, setting the ringer mode 95 * will update the state and broadcast a change and in a separate thread later 96 * persist the ringer mode. 97 * 98 * @hide 99 */ 100public class AudioService extends IAudioService.Stub implements OnFinished { 101 102 private static final String TAG = "AudioService"; 103 104 /** Debug remote control client/display feature */ 105 protected static final boolean DEBUG_RC = false; 106 /** Debug volumes */ 107 protected static final boolean DEBUG_VOL = false; 108 109 /** How long to delay before persisting a change in volume/ringer mode. */ 110 private static final int PERSIST_DELAY = 500; 111 112 private Context mContext; 113 private ContentResolver mContentResolver; 114 private boolean mVoiceCapable; 115 116 /** The UI */ 117 private VolumePanel mVolumePanel; 118 119 // sendMsg() flags 120 /** If the msg is already queued, replace it with this one. */ 121 private static final int SENDMSG_REPLACE = 0; 122 /** If the msg is already queued, ignore this one and leave the old. */ 123 private static final int SENDMSG_NOOP = 1; 124 /** If the msg is already queued, queue this one and leave the old. */ 125 private static final int SENDMSG_QUEUE = 2; 126 127 // AudioHandler messages 128 private static final int MSG_SET_DEVICE_VOLUME = 0; 129 private static final int MSG_PERSIST_VOLUME = 1; 130 private static final int MSG_PERSIST_MASTER_VOLUME = 2; 131 private static final int MSG_PERSIST_RINGER_MODE = 3; 132 private static final int MSG_MEDIA_SERVER_DIED = 4; 133 private static final int MSG_MEDIA_SERVER_STARTED = 5; 134 private static final int MSG_PLAY_SOUND_EFFECT = 6; 135 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7; 136 private static final int MSG_LOAD_SOUND_EFFECTS = 8; 137 private static final int MSG_SET_FORCE_USE = 9; 138 private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10; 139 private static final int MSG_BT_HEADSET_CNCT_FAILED = 11; 140 private static final int MSG_RCDISPLAY_CLEAR = 12; 141 private static final int MSG_RCDISPLAY_UPDATE = 13; 142 private static final int MSG_SET_ALL_VOLUMES = 14; 143 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15; 144 private static final int MSG_REPORT_NEW_ROUTES = 16; 145 private static final int MSG_REEVALUATE_REMOTE = 17; 146 private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18; 147 private static final int MSG_RCC_NEW_VOLUME_OBS = 19; 148 private static final int MSG_SET_FORCE_BT_A2DP_USE = 20; 149 // start of messages handled under wakelock 150 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), 151 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) 152 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21; 153 private static final int MSG_SET_A2DP_CONNECTION_STATE = 22; 154 // end of messages handled under wakelock 155 private static final int MSG_SET_RSX_CONNECTION_STATE = 23; // change remote submix connection 156 private static final int MSG_SET_FORCE_RSX_USE = 24; // force remote submix audio routing 157 private static final int MSG_CHECK_MUSIC_ACTIVE = 25; 158 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 26; 159 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 27; 160 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 28; 161 162 // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be 163 // persisted 164 private static final int PERSIST_CURRENT = 0x1; 165 private static final int PERSIST_LAST_AUDIBLE = 0x2; 166 167 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 168 // Timeout for connection to bluetooth headset service 169 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 170 171 /** @see AudioSystemThread */ 172 private AudioSystemThread mAudioSystemThread; 173 /** @see AudioHandler */ 174 private AudioHandler mAudioHandler; 175 /** @see VolumeStreamState */ 176 private VolumeStreamState[] mStreamStates; 177 private SettingsObserver mSettingsObserver; 178 179 private int mMode; 180 // protects mRingerMode 181 private final Object mSettingsLock = new Object(); 182 183 private boolean mMediaServerOk; 184 185 private SoundPool mSoundPool; 186 private final Object mSoundEffectsLock = new Object(); 187 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 188 189 // Internally master volume is a float in the 0.0 - 1.0 range, 190 // but to support integer based AudioManager API we translate it to 0 - 100 191 private static final int MAX_MASTER_VOLUME = 100; 192 193 // Maximum volume adjust steps allowed in a single batch call. 194 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 195 196 /* Sound effect file names */ 197 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 198 private static final String[] SOUND_EFFECT_FILES = new String[] { 199 "Effect_Tick.ogg", 200 "KeypressStandard.ogg", 201 "KeypressSpacebar.ogg", 202 "KeypressDelete.ogg", 203 "KeypressReturn.ogg" 204 }; 205 206 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 207 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 208 * uses soundpool (second column) */ 209 private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 210 {0, -1}, // FX_KEY_CLICK 211 {0, -1}, // FX_FOCUS_NAVIGATION_UP 212 {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 213 {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 214 {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 215 {1, -1}, // FX_KEYPRESS_STANDARD 216 {2, -1}, // FX_KEYPRESS_SPACEBAR 217 {3, -1}, // FX_FOCUS_DELETE 218 {4, -1} // FX_FOCUS_RETURN 219 }; 220 221 /** @hide Maximum volume index values for audio streams */ 222 private final int[] MAX_STREAM_VOLUME = new int[] { 223 5, // STREAM_VOICE_CALL 224 7, // STREAM_SYSTEM 225 7, // STREAM_RING 226 15, // STREAM_MUSIC 227 7, // STREAM_ALARM 228 7, // STREAM_NOTIFICATION 229 15, // STREAM_BLUETOOTH_SCO 230 7, // STREAM_SYSTEM_ENFORCED 231 15, // STREAM_DTMF 232 15 // STREAM_TTS 233 }; 234 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 235 * of another stream: This avoids multiplying the volume settings for hidden 236 * stream types that follow other stream behavior for volume settings 237 * NOTE: do not create loops in aliases! 238 * Some streams alias to different streams according to device category (phone or tablet) or 239 * use case (in call s off call...).See updateStreamVolumeAlias() for more details 240 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 241 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 242 private final int[] STREAM_VOLUME_ALIAS = new int[] { 243 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 244 AudioSystem.STREAM_RING, // STREAM_SYSTEM 245 AudioSystem.STREAM_RING, // STREAM_RING 246 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 247 AudioSystem.STREAM_ALARM, // STREAM_ALARM 248 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 249 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 250 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 251 AudioSystem.STREAM_RING, // STREAM_DTMF 252 AudioSystem.STREAM_MUSIC // STREAM_TTS 253 }; 254 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 255 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 256 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 257 AudioSystem.STREAM_RING, // STREAM_RING 258 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 259 AudioSystem.STREAM_ALARM, // STREAM_ALARM 260 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 261 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 262 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 263 AudioSystem.STREAM_MUSIC, // STREAM_DTMF 264 AudioSystem.STREAM_MUSIC // STREAM_TTS 265 }; 266 private int[] mStreamVolumeAlias; 267 268 // stream names used by dumpStreamStates() 269 private final String[] STREAM_NAMES = new String[] { 270 "STREAM_VOICE_CALL", 271 "STREAM_SYSTEM", 272 "STREAM_RING", 273 "STREAM_MUSIC", 274 "STREAM_ALARM", 275 "STREAM_NOTIFICATION", 276 "STREAM_BLUETOOTH_SCO", 277 "STREAM_SYSTEM_ENFORCED", 278 "STREAM_DTMF", 279 "STREAM_TTS" 280 }; 281 282 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 283 public void onError(int error) { 284 switch (error) { 285 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 286 if (mMediaServerOk) { 287 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 288 null, 1500); 289 mMediaServerOk = false; 290 } 291 break; 292 case AudioSystem.AUDIO_STATUS_OK: 293 if (!mMediaServerOk) { 294 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 295 null, 0); 296 mMediaServerOk = true; 297 } 298 break; 299 default: 300 break; 301 } 302 } 303 }; 304 305 /** 306 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 307 * {@link AudioManager#RINGER_MODE_SILENT}, or 308 * {@link AudioManager#RINGER_MODE_VIBRATE}. 309 */ 310 // protected by mSettingsLock 311 private int mRingerMode; 312 313 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 314 private int mRingerModeAffectedStreams; 315 316 // Streams currently muted by ringer mode 317 private int mRingerModeMutedStreams; 318 319 /** @see System#MUTE_STREAMS_AFFECTED */ 320 private int mMuteAffectedStreams; 321 322 /** 323 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. 324 * mVibrateSetting is just maintained during deprecation period but vibration policy is 325 * now only controlled by mHasVibrator and mRingerMode 326 */ 327 private int mVibrateSetting; 328 329 // Is there a vibrator 330 private final boolean mHasVibrator; 331 332 // Broadcast receiver for device connections intent broadcasts 333 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 334 335 // Used to alter media button redirection when the phone is ringing. 336 private boolean mIsRinging = false; 337 338 // Devices currently connected 339 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 340 341 // Forced device usage for communications 342 private int mForcedUseForComm; 343 344 // True if we have master volume support 345 private final boolean mUseMasterVolume; 346 347 private final int[] mMasterVolumeRamp; 348 349 // List of binder death handlers for setMode() client processes. 350 // The last process to have called setMode() is at the top of the list. 351 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 352 353 // List of clients having issued a SCO start request 354 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 355 356 // BluetoothHeadset API to control SCO connection 357 private BluetoothHeadset mBluetoothHeadset; 358 359 // Bluetooth headset device 360 private BluetoothDevice mBluetoothHeadsetDevice; 361 362 // Indicate if SCO audio connection is currently active and if the initiator is 363 // audio service (internal) or bluetooth headset (external) 364 private int mScoAudioState; 365 // SCO audio state is not active 366 private static final int SCO_STATE_INACTIVE = 0; 367 // SCO audio activation request waiting for headset service to connect 368 private static final int SCO_STATE_ACTIVATE_REQ = 1; 369 // SCO audio state is active or starting due to a local request to start a virtual call 370 private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 371 // SCO audio deactivation request waiting for headset service to connect 372 private static final int SCO_STATE_DEACTIVATE_REQ = 5; 373 374 // SCO audio state is active due to an action in BT handsfree (either voice recognition or 375 // in call audio) 376 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 377 // Deactivation request for all SCO connections (initiated by audio mode change) 378 // waiting for headset service to connect 379 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 380 381 // Current connection state indicated by bluetooth headset 382 private int mScoConnectionState; 383 384 // true if boot sequence has been completed 385 private boolean mBootCompleted; 386 // listener for SoundPool sample load completion indication 387 private SoundPoolCallback mSoundPoolCallBack; 388 // thread for SoundPool listener 389 private SoundPoolListenerThread mSoundPoolListenerThread; 390 // message looper for SoundPool listener 391 private Looper mSoundPoolLooper = null; 392 // volume applied to sound played with playSoundEffect() 393 private static int sSoundEffectVolumeDb; 394 // getActiveStreamType() will return: 395 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped 396 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt 397 // stopped 398 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000; 399 // previous volume adjustment direction received by checkForRingerModeChange() 400 private int mPrevVolDirection = AudioManager.ADJUST_SAME; 401 // Keyguard manager proxy 402 private KeyguardManager mKeyguardManager; 403 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 404 // is controlled by Vol keys. 405 private int mVolumeControlStream = -1; 406 private final Object mForceControlStreamLock = new Object(); 407 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 408 // server process so in theory it is not necessary to monitor the client death. 409 // However it is good to be ready for future evolutions. 410 private ForceControlStreamClient mForceControlStreamClient = null; 411 // Used to play ringtones outside system_server 412 private volatile IRingtonePlayer mRingtonePlayer; 413 414 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 415 416 // Request to override default use of A2DP for media. 417 private boolean mBluetoothA2dpEnabled; 418 private final Object mBluetoothA2dpEnabledLock = new Object(); 419 420 // Monitoring of audio routes. Protected by mCurAudioRoutes. 421 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); 422 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers 423 = new RemoteCallbackList<IAudioRoutesObserver>(); 424 425 /** 426 * A fake stream type to match the notion of remote media playback 427 */ 428 public final static int STREAM_REMOTE_MUSIC = -200; 429 430 // Devices for which the volume is fixed and VolumePanel slider should be disabled 431 final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL | 432 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | 433 AudioSystem.DEVICE_OUT_ALL_USB; 434 435 private final boolean mMonitorOrientation; 436 437 /////////////////////////////////////////////////////////////////////////// 438 // Construction 439 /////////////////////////////////////////////////////////////////////////// 440 441 /** @hide */ 442 public AudioService(Context context) { 443 mContext = context; 444 mContentResolver = context.getContentResolver(); 445 mVoiceCapable = mContext.getResources().getBoolean( 446 com.android.internal.R.bool.config_voice_capable); 447 448 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 449 mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); 450 451 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 452 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); 453 454 // Intialized volume 455 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 456 "ro.config.vc_call_vol_steps", 457 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 458 459 sSoundEffectVolumeDb = context.getResources().getInteger( 460 com.android.internal.R.integer.config_soundEffectVolumeDb); 461 462 mVolumePanel = new VolumePanel(context, this); 463 mMode = AudioSystem.MODE_NORMAL; 464 mForcedUseForComm = AudioSystem.FORCE_NONE; 465 466 createAudioSystemThread(); 467 468 boolean cameraSoundForced = mContext.getResources().getBoolean( 469 com.android.internal.R.bool.config_camera_sound_forced); 470 mCameraSoundForced = new Boolean(cameraSoundForced); 471 sendMsg(mAudioHandler, 472 MSG_SET_FORCE_USE, 473 SENDMSG_QUEUE, 474 AudioSystem.FOR_SYSTEM, 475 cameraSoundForced ? 476 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, 477 null, 478 0); 479 480 readPersistedSettings(); 481 mSettingsObserver = new SettingsObserver(); 482 updateStreamVolumeAlias(false /*updateVolumes*/); 483 createStreamStates(); 484 485 mMediaServerOk = true; 486 487 mSafeMediaVolumeState = new Integer(SAFE_MEDIA_VOLUME_NOT_CONFIGURED); 488 489 // Call setRingerModeInt() to apply correct mute 490 // state on streams affected by ringer mode. 491 mRingerModeMutedStreams = 0; 492 setRingerModeInt(getRingerMode(), false); 493 494 AudioSystem.setErrorCallback(mAudioSystemCallback); 495 496 // Register for device connection intent broadcasts. 497 IntentFilter intentFilter = 498 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 499 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 500 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 501 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 502 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 503 intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 504 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 505 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 506 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 507 508 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 509 // Register a configuration change listener only if requested by system properties 510 // to monitor orientation changes (off by default) 511 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false); 512 if (mMonitorOrientation) { 513 Log.v(TAG, "monitoring device orientation"); 514 // initialize orientation in AudioSystem 515 setOrientationForAudioSystem(); 516 } 517 518 context.registerReceiver(mReceiver, intentFilter); 519 520 // Register for package removal intent broadcasts for media button receiver persistence 521 IntentFilter pkgFilter = new IntentFilter(); 522 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 523 pkgFilter.addDataScheme("package"); 524 context.registerReceiver(mReceiver, pkgFilter); 525 526 // Register for phone state monitoring 527 TelephonyManager tmgr = (TelephonyManager) 528 context.getSystemService(Context.TELEPHONY_SERVICE); 529 tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 530 531 mUseMasterVolume = context.getResources().getBoolean( 532 com.android.internal.R.bool.config_useMasterVolume); 533 restoreMasterVolume(); 534 535 mMasterVolumeRamp = context.getResources().getIntArray( 536 com.android.internal.R.array.config_masterVolumeRamp); 537 538 mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC], 539 MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); 540 mHasRemotePlayback = false; 541 mMainRemoteIsActive = false; 542 postReevaluateRemote(); 543 } 544 545 private void createAudioSystemThread() { 546 mAudioSystemThread = new AudioSystemThread(); 547 mAudioSystemThread.start(); 548 waitForAudioHandlerCreation(); 549 } 550 551 /** Waits for the volume handler to be created by the other thread. */ 552 private void waitForAudioHandlerCreation() { 553 synchronized(this) { 554 while (mAudioHandler == null) { 555 try { 556 // Wait for mAudioHandler to be set by the other thread 557 wait(); 558 } catch (InterruptedException e) { 559 Log.e(TAG, "Interrupted while waiting on volume handler."); 560 } 561 } 562 } 563 } 564 565 private void checkAllAliasStreamVolumes() { 566 int numStreamTypes = AudioSystem.getNumStreamTypes(); 567 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 568 if (streamType != mStreamVolumeAlias[streamType]) { 569 mStreamStates[streamType]. 570 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 571 false /*lastAudible*/); 572 mStreamStates[streamType]. 573 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 574 true /*lastAudible*/); 575 } 576 // apply stream volume 577 if (mStreamStates[streamType].muteCount() == 0) { 578 mStreamStates[streamType].applyAllVolumes(); 579 } 580 } 581 } 582 583 private void createStreamStates() { 584 int numStreamTypes = AudioSystem.getNumStreamTypes(); 585 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 586 587 for (int i = 0; i < numStreamTypes; i++) { 588 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 589 } 590 591 checkAllAliasStreamVolumes(); 592 } 593 594 private void dumpStreamStates(PrintWriter pw) { 595 pw.println("\nStream volumes (device: index)"); 596 int numStreamTypes = AudioSystem.getNumStreamTypes(); 597 for (int i = 0; i < numStreamTypes; i++) { 598 pw.println("- "+STREAM_NAMES[i]+":"); 599 mStreamStates[i].dump(pw); 600 pw.println(""); 601 } 602 pw.print("\n- mute affected streams = 0x"); 603 pw.println(Integer.toHexString(mMuteAffectedStreams)); 604 } 605 606 607 private void updateStreamVolumeAlias(boolean updateVolumes) { 608 int dtmfStreamAlias; 609 if (mVoiceCapable) { 610 mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 611 dtmfStreamAlias = AudioSystem.STREAM_RING; 612 } else { 613 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 614 dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 615 } 616 if (isInCommunication()) { 617 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 618 } 619 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 620 if (updateVolumes) { 621 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 622 false /*lastAudible*/); 623 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 624 true /*lastAudible*/); 625 sendMsg(mAudioHandler, 626 MSG_SET_ALL_VOLUMES, 627 SENDMSG_QUEUE, 628 0, 629 0, 630 mStreamStates[AudioSystem.STREAM_DTMF], 0); 631 } 632 } 633 634 private void readPersistedSettings() { 635 final ContentResolver cr = mContentResolver; 636 637 int ringerModeFromSettings = 638 Settings.Global.getInt(cr, System.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, System.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 // Note that we are currently forcing use of remote submix as soon as corresponding device 2226 // is made available 2227 sendMsg(mAudioHandler, MSG_SET_FORCE_RSX_USE, SENDMSG_REPLACE, 2228 AudioSystem.FOR_MEDIA, 2229 on ? AudioSystem.FORCE_REMOTE_SUBMIX : AudioSystem.FORCE_NONE, 2230 null/*obj*/, 0/*delay*/); 2231 } 2232 2233 private void onSetRsxConnectionState(int available, int address) { 2234 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, 2235 available == 1 ? 2236 AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE, 2237 String.valueOf(address) /*device_address*/); 2238 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, 2239 available == 1 ? 2240 AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE, 2241 String.valueOf(address) /*device_address*/); 2242 } 2243 2244 private void onCheckMusicActive() { 2245 synchronized (mSafeMediaVolumeState) { 2246 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) { 2247 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC); 2248 2249 if ((device & mSafeMediaVolumeDevices) != 0) { 2250 sendMsg(mAudioHandler, 2251 MSG_CHECK_MUSIC_ACTIVE, 2252 SENDMSG_REPLACE, 2253 0, 2254 0, 2255 null, 2256 MUSIC_ACTIVE_POLL_PERIOD_MS); 2257 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device, 2258 false /*lastAudible*/); 2259 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) && 2260 (index > mSafeMediaVolumeIndex)) { 2261 // Approximate cumulative active music time 2262 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS; 2263 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) { 2264 setSafeMediaVolumeEnabled(true); 2265 mMusicActiveMs = 0; 2266 mVolumePanel.postDisplaySafeVolumeWarning(); 2267 } 2268 } 2269 } 2270 } 2271 } 2272 } 2273 2274 private void onConfigureSafeVolume(boolean force) { 2275 synchronized (mSafeMediaVolumeState) { 2276 int mcc = mContext.getResources().getConfiguration().mcc; 2277 if ((mMcc != mcc) || ((mMcc == 0) && force)) { 2278 mSafeMediaVolumeIndex = mContext.getResources().getInteger( 2279 com.android.internal.R.integer.config_safe_media_volume_index) * 10; 2280 boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean( 2281 com.android.internal.R.bool.config_safe_media_volume_enabled); 2282 if (safeMediaVolumeEnabled) { 2283 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; 2284 enforceSafeMediaVolume(); 2285 } else { 2286 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; 2287 } 2288 mMcc = mcc; 2289 } 2290 } 2291 } 2292 2293 /////////////////////////////////////////////////////////////////////////// 2294 // Internal methods 2295 /////////////////////////////////////////////////////////////////////////// 2296 2297 /** 2298 * Checks if the adjustment should change ringer mode instead of just 2299 * adjusting volume. If so, this will set the proper ringer mode and volume 2300 * indices on the stream states. 2301 */ 2302 private boolean checkForRingerModeChange(int oldIndex, int direction, int step) { 2303 boolean adjustVolumeIndex = true; 2304 int ringerMode = getRingerMode(); 2305 2306 switch (ringerMode) { 2307 case RINGER_MODE_NORMAL: 2308 if (direction == AudioManager.ADJUST_LOWER) { 2309 if (mHasVibrator) { 2310 // "step" is the delta in internal index units corresponding to a 2311 // change of 1 in UI index units. 2312 // Because of rounding when rescaling from one stream index range to its alias 2313 // index range, we cannot simply test oldIndex == step: 2314 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1) 2315 if (step <= oldIndex && oldIndex < 2 * step) { 2316 ringerMode = RINGER_MODE_VIBRATE; 2317 } 2318 } else { 2319 // (oldIndex < step) is equivalent to (old UI index == 0) 2320 if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2321 ringerMode = RINGER_MODE_SILENT; 2322 } 2323 } 2324 } 2325 break; 2326 case RINGER_MODE_VIBRATE: 2327 if (!mHasVibrator) { 2328 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" + 2329 "but no vibrator is present"); 2330 break; 2331 } 2332 if ((direction == AudioManager.ADJUST_LOWER)) { 2333 if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2334 ringerMode = RINGER_MODE_SILENT; 2335 } 2336 } else if (direction == AudioManager.ADJUST_RAISE) { 2337 ringerMode = RINGER_MODE_NORMAL; 2338 } 2339 adjustVolumeIndex = false; 2340 break; 2341 case RINGER_MODE_SILENT: 2342 if (direction == AudioManager.ADJUST_RAISE) { 2343 if (mHasVibrator) { 2344 ringerMode = RINGER_MODE_VIBRATE; 2345 } else { 2346 ringerMode = RINGER_MODE_NORMAL; 2347 } 2348 } 2349 adjustVolumeIndex = false; 2350 break; 2351 default: 2352 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode); 2353 break; 2354 } 2355 2356 setRingerMode(ringerMode); 2357 2358 mPrevVolDirection = direction; 2359 2360 return adjustVolumeIndex; 2361 } 2362 2363 public boolean isStreamAffectedByRingerMode(int streamType) { 2364 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 2365 } 2366 2367 private boolean isStreamMutedByRingerMode(int streamType) { 2368 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 2369 } 2370 2371 public boolean isStreamAffectedByMute(int streamType) { 2372 return (mMuteAffectedStreams & (1 << streamType)) != 0; 2373 } 2374 2375 private void ensureValidDirection(int direction) { 2376 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 2377 throw new IllegalArgumentException("Bad direction " + direction); 2378 } 2379 } 2380 2381 private void ensureValidSteps(int steps) { 2382 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 2383 throw new IllegalArgumentException("Bad volume adjust steps " + steps); 2384 } 2385 } 2386 2387 private void ensureValidStreamType(int streamType) { 2388 if (streamType < 0 || streamType >= mStreamStates.length) { 2389 throw new IllegalArgumentException("Bad stream type " + streamType); 2390 } 2391 } 2392 2393 private boolean isInCommunication() { 2394 boolean isOffhook = false; 2395 2396 if (mVoiceCapable) { 2397 try { 2398 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 2399 if (phone != null) isOffhook = phone.isOffhook(); 2400 } catch (RemoteException e) { 2401 Log.w(TAG, "Couldn't connect to phone service", e); 2402 } 2403 } 2404 return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 2405 } 2406 2407 private int getActiveStreamType(int suggestedStreamType) { 2408 if (mVoiceCapable) { 2409 if (isInCommunication()) { 2410 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2411 == AudioSystem.FORCE_BT_SCO) { 2412 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2413 return AudioSystem.STREAM_BLUETOOTH_SCO; 2414 } else { 2415 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2416 return AudioSystem.STREAM_VOICE_CALL; 2417 } 2418 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2419 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 2420 // volume can have priority over STREAM_MUSIC 2421 if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 2422 if (DEBUG_VOL) 2423 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 2424 return STREAM_REMOTE_MUSIC; 2425 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 2426 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { 2427 if (DEBUG_VOL) 2428 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 2429 return AudioSystem.STREAM_MUSIC; 2430 } else { 2431 if (DEBUG_VOL) 2432 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); 2433 return AudioSystem.STREAM_RING; 2434 } 2435 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 2436 if (DEBUG_VOL) 2437 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 2438 return AudioSystem.STREAM_MUSIC; 2439 } else { 2440 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 2441 + suggestedStreamType); 2442 return suggestedStreamType; 2443 } 2444 } else { 2445 if (isInCommunication()) { 2446 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2447 == AudioSystem.FORCE_BT_SCO) { 2448 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); 2449 return AudioSystem.STREAM_BLUETOOTH_SCO; 2450 } else { 2451 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); 2452 return AudioSystem.STREAM_VOICE_CALL; 2453 } 2454 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 2455 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) || 2456 AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 2457 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { 2458 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); 2459 return AudioSystem.STREAM_NOTIFICATION; 2460 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2461 if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 2462 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 2463 // volume can have priority over STREAM_MUSIC 2464 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 2465 return STREAM_REMOTE_MUSIC; 2466 } else { 2467 if (DEBUG_VOL) 2468 Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); 2469 return AudioSystem.STREAM_MUSIC; 2470 } 2471 } else { 2472 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 2473 + suggestedStreamType); 2474 return suggestedStreamType; 2475 } 2476 } 2477 } 2478 2479 private void broadcastRingerMode(int ringerMode) { 2480 // Send sticky broadcast 2481 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2482 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 2483 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2484 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2485 sendStickyBroadcastToAll(broadcast); 2486 } 2487 2488 private void broadcastVibrateSetting(int vibrateType) { 2489 // Send broadcast 2490 if (ActivityManagerNative.isSystemReady()) { 2491 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 2492 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 2493 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 2494 sendBroadcastToAll(broadcast); 2495 } 2496 } 2497 2498 // Message helper methods 2499 /** 2500 * Queue a message on the given handler's message queue, after acquiring the service wake lock. 2501 * Note that the wake lock needs to be released after the message has been handled. 2502 */ 2503 private void queueMsgUnderWakeLock(Handler handler, int msg, 2504 int arg1, int arg2, Object obj, int delay) { 2505 mMediaEventWakeLock.acquire(); 2506 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); 2507 } 2508 2509 private static void sendMsg(Handler handler, int msg, 2510 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 2511 2512 if (existingMsgPolicy == SENDMSG_REPLACE) { 2513 handler.removeMessages(msg); 2514 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 2515 return; 2516 } 2517 2518 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 2519 } 2520 2521 boolean checkAudioSettingsPermission(String method) { 2522 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 2523 == PackageManager.PERMISSION_GRANTED) { 2524 return true; 2525 } 2526 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 2527 + Binder.getCallingPid() 2528 + ", uid=" + Binder.getCallingUid(); 2529 Log.w(TAG, msg); 2530 return false; 2531 } 2532 2533 private int getDeviceForStream(int stream) { 2534 int device = AudioSystem.getDevicesForStream(stream); 2535 if ((device & (device - 1)) != 0) { 2536 // Multiple device selection is either: 2537 // - speaker + one other device: give priority to speaker in this case. 2538 // - one A2DP device + another device: happens with duplicated output. In this case 2539 // retain the device on the A2DP output as the other must not correspond to an active 2540 // selection if not the speaker. 2541 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 2542 device = AudioSystem.DEVICE_OUT_SPEAKER; 2543 } else { 2544 device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 2545 } 2546 } 2547 return device; 2548 } 2549 2550 public void setWiredDeviceConnectionState(int device, int state, String name) { 2551 synchronized (mConnectedDevices) { 2552 int delay = checkSendBecomingNoisyIntent(device, state); 2553 queueMsgUnderWakeLock(mAudioHandler, 2554 MSG_SET_WIRED_DEVICE_CONNECTION_STATE, 2555 device, 2556 state, 2557 name, 2558 delay); 2559 } 2560 } 2561 2562 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state) 2563 { 2564 int delay; 2565 synchronized (mConnectedDevices) { 2566 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2567 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 2568 queueMsgUnderWakeLock(mAudioHandler, 2569 MSG_SET_A2DP_CONNECTION_STATE, 2570 state, 2571 0, 2572 device, 2573 delay); 2574 } 2575 return delay; 2576 } 2577 2578 /////////////////////////////////////////////////////////////////////////// 2579 // Inner classes 2580 /////////////////////////////////////////////////////////////////////////// 2581 2582 public class VolumeStreamState { 2583 private final int mStreamType; 2584 2585 private String mVolumeIndexSettingName; 2586 private String mLastAudibleVolumeIndexSettingName; 2587 private int mIndexMax; 2588 private final ConcurrentHashMap<Integer, Integer> mIndex = 2589 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 2590 private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex = 2591 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 2592 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 2593 2594 private VolumeStreamState(String settingName, int streamType) { 2595 2596 mVolumeIndexSettingName = settingName; 2597 mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 2598 2599 mStreamType = streamType; 2600 mIndexMax = MAX_STREAM_VOLUME[streamType]; 2601 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2602 mIndexMax *= 10; 2603 2604 // mDeathHandlers must be created before calling readSettings() 2605 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 2606 2607 readSettings(); 2608 } 2609 2610 public String getSettingNameForDevice(boolean lastAudible, int device) { 2611 String name = lastAudible ? 2612 mLastAudibleVolumeIndexSettingName : 2613 mVolumeIndexSettingName; 2614 String suffix = AudioSystem.getDeviceName(device); 2615 if (suffix.isEmpty()) { 2616 return name; 2617 } 2618 return name + "_" + suffix; 2619 } 2620 2621 public synchronized void readSettings() { 2622 int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 2623 2624 // do not read system stream volume from settings: this stream is always aliased 2625 // to another stream type and its volume is never persisted. Values in settings can 2626 // only be stale values 2627 // on first call to readSettings() at init time, muteCount() is always 0 so we will 2628 // always create entries for default device 2629 if ((mStreamType == AudioSystem.STREAM_SYSTEM) || 2630 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) { 2631 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2632 synchronized (mCameraSoundForced) { 2633 if (mCameraSoundForced) { 2634 index = mIndexMax; 2635 } 2636 } 2637 if (muteCount() == 0) { 2638 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); 2639 } 2640 mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); 2641 return; 2642 } 2643 2644 for (int i = 0; remainingDevices != 0; i++) { 2645 int device = (1 << i); 2646 if ((device & remainingDevices) == 0) { 2647 continue; 2648 } 2649 remainingDevices &= ~device; 2650 2651 // ignore settings for fixed volume devices: volume should always be at max 2652 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && 2653 ((device & mFixedVolumeDevices) != 0)) { 2654 if (muteCount() == 0) { 2655 mIndex.put(device, mIndexMax); 2656 } 2657 mLastAudibleIndex.put(device, mIndexMax); 2658 continue; 2659 } 2660 // retrieve current volume for device 2661 String name = getSettingNameForDevice(false /* lastAudible */, device); 2662 // if no volume stored for current stream and device, use default volume if default 2663 // device, continue otherwise 2664 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 2665 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 2666 int index = Settings.System.getIntForUser( 2667 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT); 2668 if (index == -1) { 2669 continue; 2670 } 2671 2672 // retrieve last audible volume for device 2673 name = getSettingNameForDevice(true /* lastAudible */, device); 2674 // use stored last audible index if present, otherwise use current index if not 0 2675 // or default index 2676 defaultIndex = (index > 0) ? 2677 index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2678 int lastAudibleIndex = Settings.System.getIntForUser( 2679 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT); 2680 2681 // a last audible index of 0 should never be stored for ring and notification 2682 // streams on phones (voice capable devices). 2683 if ((lastAudibleIndex == 0) && mVoiceCapable && 2684 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) { 2685 lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2686 // Correct the data base 2687 sendMsg(mAudioHandler, 2688 MSG_PERSIST_VOLUME, 2689 SENDMSG_QUEUE, 2690 PERSIST_LAST_AUDIBLE, 2691 device, 2692 this, 2693 PERSIST_DELAY); 2694 } 2695 mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex)); 2696 // the initial index should never be 0 for ring and notification streams on phones 2697 // (voice capable devices) if not in silent or vibrate mode. 2698 if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) && 2699 mVoiceCapable && 2700 (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) { 2701 index = lastAudibleIndex; 2702 // Correct the data base 2703 sendMsg(mAudioHandler, 2704 MSG_PERSIST_VOLUME, 2705 SENDMSG_QUEUE, 2706 PERSIST_CURRENT, 2707 device, 2708 this, 2709 PERSIST_DELAY); 2710 } 2711 if (muteCount() == 0) { 2712 mIndex.put(device, getValidIndex(10 * index)); 2713 } 2714 } 2715 } 2716 2717 public void applyDeviceVolume(int device) { 2718 AudioSystem.setStreamVolumeIndex(mStreamType, 2719 (getIndex(device, false /* lastAudible */) + 5)/10, 2720 device); 2721 } 2722 2723 public synchronized void applyAllVolumes() { 2724 // apply default volume first: by convention this will reset all 2725 // devices volumes in audio policy manager to the supplied value 2726 AudioSystem.setStreamVolumeIndex(mStreamType, 2727 (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, 2728 AudioSystem.DEVICE_OUT_DEFAULT); 2729 // then apply device specific volumes 2730 Set set = mIndex.entrySet(); 2731 Iterator i = set.iterator(); 2732 while (i.hasNext()) { 2733 Map.Entry entry = (Map.Entry)i.next(); 2734 int device = ((Integer)entry.getKey()).intValue(); 2735 if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 2736 AudioSystem.setStreamVolumeIndex(mStreamType, 2737 ((Integer)entry.getValue() + 5)/10, 2738 device); 2739 } 2740 } 2741 } 2742 2743 public boolean adjustIndex(int deltaIndex, int device) { 2744 return setIndex(getIndex(device, 2745 false /* lastAudible */) + deltaIndex, 2746 device, 2747 true /* lastAudible */); 2748 } 2749 2750 public synchronized boolean setIndex(int index, int device, boolean lastAudible) { 2751 int oldIndex = getIndex(device, false /* lastAudible */); 2752 index = getValidIndex(index); 2753 synchronized (mCameraSoundForced) { 2754 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) { 2755 index = mIndexMax; 2756 } 2757 } 2758 mIndex.put(device, getValidIndex(index)); 2759 2760 if (oldIndex != index) { 2761 if (lastAudible) { 2762 mLastAudibleIndex.put(device, index); 2763 } 2764 // Apply change to all streams using this one as alias 2765 // if changing volume of current device, also change volume of current 2766 // device on aliased stream 2767 boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2768 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2769 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2770 if (streamType != mStreamType && 2771 mStreamVolumeAlias[streamType] == mStreamType) { 2772 int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2773 mStreamStates[streamType].setIndex(scaledIndex, 2774 device, 2775 lastAudible); 2776 if (currentDevice) { 2777 mStreamStates[streamType].setIndex(scaledIndex, 2778 getDeviceForStream(streamType), 2779 lastAudible); 2780 } 2781 } 2782 } 2783 return true; 2784 } else { 2785 return false; 2786 } 2787 } 2788 2789 public synchronized int getIndex(int device, boolean lastAudible) { 2790 ConcurrentHashMap <Integer, Integer> indexes; 2791 if (lastAudible) { 2792 indexes = mLastAudibleIndex; 2793 } else { 2794 indexes = mIndex; 2795 } 2796 Integer index = indexes.get(device); 2797 if (index == null) { 2798 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 2799 index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); 2800 } 2801 return index.intValue(); 2802 } 2803 2804 public synchronized void setLastAudibleIndex(int index, int device) { 2805 // Apply change to all streams using this one as alias 2806 // if changing volume of current device, also change volume of current 2807 // device on aliased stream 2808 boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2809 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2810 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2811 if (streamType != mStreamType && 2812 mStreamVolumeAlias[streamType] == mStreamType) { 2813 int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2814 mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device); 2815 if (currentDevice) { 2816 mStreamStates[streamType].setLastAudibleIndex(scaledIndex, 2817 getDeviceForStream(streamType)); 2818 } 2819 } 2820 } 2821 mLastAudibleIndex.put(device, getValidIndex(index)); 2822 } 2823 2824 public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) { 2825 setLastAudibleIndex(getIndex(device, 2826 true /* lastAudible */) + deltaIndex, 2827 device); 2828 } 2829 2830 public int getMaxIndex() { 2831 return mIndexMax; 2832 } 2833 2834 // only called by setAllIndexes() which is already synchronized 2835 public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { 2836 if (lastAudible) { 2837 return mLastAudibleIndex; 2838 } else { 2839 return mIndex; 2840 } 2841 } 2842 2843 public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { 2844 ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); 2845 Set set = indexes.entrySet(); 2846 Iterator i = set.iterator(); 2847 while (i.hasNext()) { 2848 Map.Entry entry = (Map.Entry)i.next(); 2849 int device = ((Integer)entry.getKey()).intValue(); 2850 int index = ((Integer)entry.getValue()).intValue(); 2851 index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 2852 2853 if (lastAudible) { 2854 setLastAudibleIndex(index, device); 2855 } else { 2856 setIndex(index, device, false /* lastAudible */); 2857 } 2858 } 2859 } 2860 2861 public synchronized void setAllIndexesToMax() { 2862 Set set = mIndex.entrySet(); 2863 Iterator i = set.iterator(); 2864 while (i.hasNext()) { 2865 Map.Entry entry = (Map.Entry)i.next(); 2866 entry.setValue(mIndexMax); 2867 } 2868 set = mLastAudibleIndex.entrySet(); 2869 i = set.iterator(); 2870 while (i.hasNext()) { 2871 Map.Entry entry = (Map.Entry)i.next(); 2872 entry.setValue(mIndexMax); 2873 } 2874 } 2875 2876 public synchronized void mute(IBinder cb, boolean state) { 2877 VolumeDeathHandler handler = getDeathHandler(cb, state); 2878 if (handler == null) { 2879 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 2880 return; 2881 } 2882 handler.mute(state); 2883 } 2884 2885 public int getStreamType() { 2886 return mStreamType; 2887 } 2888 2889 private int getValidIndex(int index) { 2890 if (index < 0) { 2891 return 0; 2892 } else if (index > mIndexMax) { 2893 return mIndexMax; 2894 } 2895 2896 return index; 2897 } 2898 2899 private class VolumeDeathHandler implements IBinder.DeathRecipient { 2900 private IBinder mICallback; // To be notified of client's death 2901 private int mMuteCount; // Number of active mutes for this client 2902 2903 VolumeDeathHandler(IBinder cb) { 2904 mICallback = cb; 2905 } 2906 2907 // must be called while synchronized on parent VolumeStreamState 2908 public void mute(boolean state) { 2909 if (state) { 2910 if (mMuteCount == 0) { 2911 // Register for client death notification 2912 try { 2913 // mICallback can be 0 if muted by AudioService 2914 if (mICallback != null) { 2915 mICallback.linkToDeath(this, 0); 2916 } 2917 mDeathHandlers.add(this); 2918 // If the stream is not yet muted by any client, set level to 0 2919 if (muteCount() == 0) { 2920 Set set = mIndex.entrySet(); 2921 Iterator i = set.iterator(); 2922 while (i.hasNext()) { 2923 Map.Entry entry = (Map.Entry)i.next(); 2924 int device = ((Integer)entry.getKey()).intValue(); 2925 setIndex(0, device, false /* lastAudible */); 2926 } 2927 sendMsg(mAudioHandler, 2928 MSG_SET_ALL_VOLUMES, 2929 SENDMSG_QUEUE, 2930 0, 2931 0, 2932 VolumeStreamState.this, 0); 2933 } 2934 } catch (RemoteException e) { 2935 // Client has died! 2936 binderDied(); 2937 return; 2938 } 2939 } else { 2940 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 2941 } 2942 mMuteCount++; 2943 } else { 2944 if (mMuteCount == 0) { 2945 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 2946 } else { 2947 mMuteCount--; 2948 if (mMuteCount == 0) { 2949 // Unregister from client death notification 2950 mDeathHandlers.remove(this); 2951 // mICallback can be 0 if muted by AudioService 2952 if (mICallback != null) { 2953 mICallback.unlinkToDeath(this, 0); 2954 } 2955 if (muteCount() == 0) { 2956 // If the stream is not muted any more, restore its volume if 2957 // ringer mode allows it 2958 if (!isStreamAffectedByRingerMode(mStreamType) || 2959 mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 2960 Set set = mIndex.entrySet(); 2961 Iterator i = set.iterator(); 2962 while (i.hasNext()) { 2963 Map.Entry entry = (Map.Entry)i.next(); 2964 int device = ((Integer)entry.getKey()).intValue(); 2965 setIndex(getIndex(device, 2966 true /* lastAudible */), 2967 device, 2968 false /* lastAudible */); 2969 } 2970 sendMsg(mAudioHandler, 2971 MSG_SET_ALL_VOLUMES, 2972 SENDMSG_QUEUE, 2973 0, 2974 0, 2975 VolumeStreamState.this, 0); 2976 } 2977 } 2978 } 2979 } 2980 } 2981 } 2982 2983 public void binderDied() { 2984 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 2985 if (mMuteCount != 0) { 2986 // Reset all active mute requests from this client. 2987 mMuteCount = 1; 2988 mute(false); 2989 } 2990 } 2991 } 2992 2993 private synchronized int muteCount() { 2994 int count = 0; 2995 int size = mDeathHandlers.size(); 2996 for (int i = 0; i < size; i++) { 2997 count += mDeathHandlers.get(i).mMuteCount; 2998 } 2999 return count; 3000 } 3001 3002 // only called by mute() which is already synchronized 3003 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 3004 VolumeDeathHandler handler; 3005 int size = mDeathHandlers.size(); 3006 for (int i = 0; i < size; i++) { 3007 handler = mDeathHandlers.get(i); 3008 if (cb == handler.mICallback) { 3009 return handler; 3010 } 3011 } 3012 // If this is the first mute request for this client, create a new 3013 // client death handler. Otherwise, it is an out of sequence unmute request. 3014 if (state) { 3015 handler = new VolumeDeathHandler(cb); 3016 } else { 3017 Log.w(TAG, "stream was not muted by this client"); 3018 handler = null; 3019 } 3020 return handler; 3021 } 3022 3023 private void dump(PrintWriter pw) { 3024 pw.print(" Mute count: "); 3025 pw.println(muteCount()); 3026 pw.print(" Current: "); 3027 Set set = mIndex.entrySet(); 3028 Iterator i = set.iterator(); 3029 while (i.hasNext()) { 3030 Map.Entry entry = (Map.Entry)i.next(); 3031 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 3032 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 3033 } 3034 pw.print("\n Last audible: "); 3035 set = mLastAudibleIndex.entrySet(); 3036 i = set.iterator(); 3037 while (i.hasNext()) { 3038 Map.Entry entry = (Map.Entry)i.next(); 3039 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 3040 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 3041 } 3042 } 3043 } 3044 3045 /** Thread that handles native AudioSystem control. */ 3046 private class AudioSystemThread extends Thread { 3047 AudioSystemThread() { 3048 super("AudioService"); 3049 } 3050 3051 @Override 3052 public void run() { 3053 // Set this thread up so the handler will work on it 3054 Looper.prepare(); 3055 3056 synchronized(AudioService.this) { 3057 mAudioHandler = new AudioHandler(); 3058 3059 // Notify that the handler has been created 3060 AudioService.this.notify(); 3061 } 3062 3063 // Listen for volume change requests that are set by VolumePanel 3064 Looper.loop(); 3065 } 3066 } 3067 3068 /** Handles internal volume messages in separate volume thread. */ 3069 private class AudioHandler extends Handler { 3070 3071 private void setDeviceVolume(VolumeStreamState streamState, int device) { 3072 3073 // Apply volume 3074 streamState.applyDeviceVolume(device); 3075 3076 // Apply change to all streams using this one as alias 3077 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3078 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3079 if (streamType != streamState.mStreamType && 3080 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 3081 mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 3082 } 3083 } 3084 3085 // Post a persist volume msg 3086 sendMsg(mAudioHandler, 3087 MSG_PERSIST_VOLUME, 3088 SENDMSG_QUEUE, 3089 PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, 3090 device, 3091 streamState, 3092 PERSIST_DELAY); 3093 3094 } 3095 3096 private void setAllVolumes(VolumeStreamState streamState) { 3097 3098 // Apply volume 3099 streamState.applyAllVolumes(); 3100 3101 // Apply change to all streams using this one as alias 3102 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3103 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3104 if (streamType != streamState.mStreamType && 3105 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 3106 mStreamStates[streamType].applyAllVolumes(); 3107 } 3108 } 3109 } 3110 3111 private void persistVolume(VolumeStreamState streamState, 3112 int persistType, 3113 int device) { 3114 if ((persistType & PERSIST_CURRENT) != 0) { 3115 System.putIntForUser(mContentResolver, 3116 streamState.getSettingNameForDevice(false /* lastAudible */, device), 3117 (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10, 3118 UserHandle.USER_CURRENT); 3119 } 3120 if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { 3121 System.putIntForUser(mContentResolver, 3122 streamState.getSettingNameForDevice(true /* lastAudible */, device), 3123 (streamState.getIndex(device, true /* lastAudible */) + 5) / 10, 3124 UserHandle.USER_CURRENT); 3125 } 3126 } 3127 3128 private void persistRingerMode(int ringerMode) { 3129 Settings.Global.putInt(mContentResolver, System.MODE_RINGER, ringerMode); 3130 } 3131 3132 private void playSoundEffect(int effectType, int volume) { 3133 synchronized (mSoundEffectsLock) { 3134 if (mSoundPool == null) { 3135 return; 3136 } 3137 float volFloat; 3138 // use default if volume is not specified by caller 3139 if (volume < 0) { 3140 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20); 3141 } else { 3142 volFloat = (float) volume / 1000.0f; 3143 } 3144 3145 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 3146 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 3147 } else { 3148 MediaPlayer mediaPlayer = new MediaPlayer(); 3149 try { 3150 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 3151 mediaPlayer.setDataSource(filePath); 3152 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 3153 mediaPlayer.prepare(); 3154 mediaPlayer.setVolume(volFloat, volFloat); 3155 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 3156 public void onCompletion(MediaPlayer mp) { 3157 cleanupPlayer(mp); 3158 } 3159 }); 3160 mediaPlayer.setOnErrorListener(new OnErrorListener() { 3161 public boolean onError(MediaPlayer mp, int what, int extra) { 3162 cleanupPlayer(mp); 3163 return true; 3164 } 3165 }); 3166 mediaPlayer.start(); 3167 } catch (IOException ex) { 3168 Log.w(TAG, "MediaPlayer IOException: "+ex); 3169 } catch (IllegalArgumentException ex) { 3170 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 3171 } catch (IllegalStateException ex) { 3172 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 3173 } 3174 } 3175 } 3176 } 3177 3178 private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { 3179 Settings.System.putStringForUser(mContentResolver, 3180 Settings.System.MEDIA_BUTTON_RECEIVER, 3181 receiver == null ? "" : receiver.flattenToString(), 3182 UserHandle.USER_CURRENT); 3183 } 3184 3185 private void cleanupPlayer(MediaPlayer mp) { 3186 if (mp != null) { 3187 try { 3188 mp.stop(); 3189 mp.release(); 3190 } catch (IllegalStateException ex) { 3191 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 3192 } 3193 } 3194 } 3195 3196 private void setForceUse(int usage, int config) { 3197 AudioSystem.setForceUse(usage, config); 3198 } 3199 3200 @Override 3201 public void handleMessage(Message msg) { 3202 3203 switch (msg.what) { 3204 3205 case MSG_SET_DEVICE_VOLUME: 3206 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 3207 break; 3208 3209 case MSG_SET_ALL_VOLUMES: 3210 setAllVolumes((VolumeStreamState) msg.obj); 3211 break; 3212 3213 case MSG_PERSIST_VOLUME: 3214 persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); 3215 break; 3216 3217 case MSG_PERSIST_MASTER_VOLUME: 3218 Settings.System.putFloatForUser(mContentResolver, 3219 Settings.System.VOLUME_MASTER, 3220 (float)msg.arg1 / (float)1000.0, 3221 UserHandle.USER_CURRENT); 3222 break; 3223 3224 case MSG_PERSIST_MASTER_VOLUME_MUTE: 3225 Settings.System.putIntForUser(mContentResolver, 3226 Settings.System.VOLUME_MASTER_MUTE, 3227 msg.arg1, 3228 UserHandle.USER_CURRENT); 3229 break; 3230 3231 case MSG_PERSIST_RINGER_MODE: 3232 // note that the value persisted is the current ringer mode, not the 3233 // value of ringer mode as of the time the request was made to persist 3234 persistRingerMode(getRingerMode()); 3235 break; 3236 3237 case MSG_MEDIA_SERVER_DIED: 3238 if (!mMediaServerOk) { 3239 Log.e(TAG, "Media server died."); 3240 // Force creation of new IAudioFlinger interface so that we are notified 3241 // when new media_server process is back to life. 3242 AudioSystem.setErrorCallback(mAudioSystemCallback); 3243 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 3244 null, 500); 3245 } 3246 break; 3247 3248 case MSG_MEDIA_SERVER_STARTED: 3249 Log.e(TAG, "Media server started."); 3250 // indicate to audio HAL that we start the reconfiguration phase after a media 3251 // server crash 3252 // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 3253 // process restarts after a crash, not the first time it is started. 3254 AudioSystem.setParameters("restarting=true"); 3255 3256 // Restore device connection states 3257 synchronized (mConnectedDevices) { 3258 Set set = mConnectedDevices.entrySet(); 3259 Iterator i = set.iterator(); 3260 while (i.hasNext()) { 3261 Map.Entry device = (Map.Entry)i.next(); 3262 AudioSystem.setDeviceConnectionState( 3263 ((Integer)device.getKey()).intValue(), 3264 AudioSystem.DEVICE_STATE_AVAILABLE, 3265 (String)device.getValue()); 3266 } 3267 } 3268 // Restore call state 3269 AudioSystem.setPhoneState(mMode); 3270 3271 // Restore forced usage for communcations and record 3272 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 3273 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 3274 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ? 3275 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE); 3276 3277 // Restore stream volumes 3278 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3279 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3280 VolumeStreamState streamState = mStreamStates[streamType]; 3281 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 3282 3283 streamState.applyAllVolumes(); 3284 } 3285 3286 // Restore ringer mode 3287 setRingerModeInt(getRingerMode(), false); 3288 3289 // Restore master volume 3290 restoreMasterVolume(); 3291 3292 // Reset device orientation (if monitored for this device) 3293 if (mMonitorOrientation) { 3294 setOrientationForAudioSystem(); 3295 } 3296 3297 synchronized (mBluetoothA2dpEnabledLock) { 3298 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 3299 mBluetoothA2dpEnabled ? 3300 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 3301 } 3302 // indicate the end of reconfiguration phase to audio HAL 3303 AudioSystem.setParameters("restarting=false"); 3304 break; 3305 3306 case MSG_LOAD_SOUND_EFFECTS: 3307 loadSoundEffects(); 3308 break; 3309 3310 case MSG_PLAY_SOUND_EFFECT: 3311 playSoundEffect(msg.arg1, msg.arg2); 3312 break; 3313 3314 case MSG_BTA2DP_DOCK_TIMEOUT: 3315 // msg.obj == address of BTA2DP device 3316 synchronized (mConnectedDevices) { 3317 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 3318 } 3319 break; 3320 3321 case MSG_SET_FORCE_USE: 3322 case MSG_SET_FORCE_BT_A2DP_USE: 3323 case MSG_SET_FORCE_RSX_USE: 3324 setForceUse(msg.arg1, msg.arg2); 3325 break; 3326 3327 case MSG_PERSIST_MEDIABUTTONRECEIVER: 3328 onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); 3329 break; 3330 3331 case MSG_RCDISPLAY_CLEAR: 3332 onRcDisplayClear(); 3333 break; 3334 3335 case MSG_RCDISPLAY_UPDATE: 3336 // msg.obj is guaranteed to be non null 3337 onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); 3338 break; 3339 3340 case MSG_BT_HEADSET_CNCT_FAILED: 3341 resetBluetoothSco(); 3342 break; 3343 3344 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: 3345 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj); 3346 mMediaEventWakeLock.release(); 3347 break; 3348 3349 case MSG_SET_A2DP_CONNECTION_STATE: 3350 onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1); 3351 mMediaEventWakeLock.release(); 3352 break; 3353 3354 case MSG_REPORT_NEW_ROUTES: { 3355 int N = mRoutesObservers.beginBroadcast(); 3356 if (N > 0) { 3357 AudioRoutesInfo routes; 3358 synchronized (mCurAudioRoutes) { 3359 routes = new AudioRoutesInfo(mCurAudioRoutes); 3360 } 3361 while (N > 0) { 3362 N--; 3363 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N); 3364 try { 3365 obs.dispatchAudioRoutesChanged(routes); 3366 } catch (RemoteException e) { 3367 } 3368 } 3369 } 3370 mRoutesObservers.finishBroadcast(); 3371 break; 3372 } 3373 3374 case MSG_REEVALUATE_REMOTE: 3375 onReevaluateRemote(); 3376 break; 3377 3378 case MSG_RCC_NEW_PLAYBACK_INFO: 3379 onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, 3380 ((Integer)msg.obj).intValue() /* value */); 3381 break; 3382 case MSG_RCC_NEW_VOLUME_OBS: 3383 onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, 3384 (IRemoteVolumeObserver)msg.obj /* rvo */); 3385 break; 3386 3387 case MSG_SET_RSX_CONNECTION_STATE: 3388 onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/); 3389 break; 3390 3391 case MSG_CHECK_MUSIC_ACTIVE: 3392 onCheckMusicActive(); 3393 break; 3394 3395 case MSG_BROADCAST_AUDIO_BECOMING_NOISY: 3396 onSendBecomingNoisyIntent(); 3397 break; 3398 3399 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED: 3400 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME: 3401 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED)); 3402 break; 3403 } 3404 } 3405 } 3406 3407 private class SettingsObserver extends ContentObserver { 3408 3409 SettingsObserver() { 3410 super(new Handler()); 3411 mContentResolver.registerContentObserver(Settings.System.getUriFor( 3412 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 3413 } 3414 3415 @Override 3416 public void onChange(boolean selfChange) { 3417 super.onChange(selfChange); 3418 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 3419 // However there appear to be some missing locks around mRingerModeMutedStreams 3420 // and mRingerModeAffectedStreams, so will leave this synchronized for now. 3421 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 3422 synchronized (mSettingsLock) { 3423 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver, 3424 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 3425 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 3426 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)), 3427 UserHandle.USER_CURRENT); 3428 if (mVoiceCapable) { 3429 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 3430 } else { 3431 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 3432 } 3433 synchronized (mCameraSoundForced) { 3434 if (mCameraSoundForced) { 3435 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 3436 } else { 3437 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 3438 } 3439 } 3440 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 3441 /* 3442 * Ensure all stream types that should be affected by ringer mode 3443 * are in the proper state. 3444 */ 3445 mRingerModeAffectedStreams = ringerModeAffectedStreams; 3446 setRingerModeInt(getRingerMode(), false); 3447 } 3448 } 3449 } 3450 } 3451 3452 // must be called synchronized on mConnectedDevices 3453 private void makeA2dpDeviceAvailable(String address) { 3454 // enable A2DP before notifying A2DP connection to avoid unecessary processing in 3455 // audio policy manager 3456 setBluetoothA2dpOnInt(true); 3457 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 3458 AudioSystem.DEVICE_STATE_AVAILABLE, 3459 address); 3460 // Reset A2DP suspend state each time a new sink is connected 3461 AudioSystem.setParameters("A2dpSuspended=false"); 3462 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 3463 address); 3464 } 3465 3466 private void onSendBecomingNoisyIntent() { 3467 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); 3468 } 3469 3470 // must be called synchronized on mConnectedDevices 3471 private void makeA2dpDeviceUnavailableNow(String address) { 3472 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 3473 AudioSystem.DEVICE_STATE_UNAVAILABLE, 3474 address); 3475 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 3476 } 3477 3478 // must be called synchronized on mConnectedDevices 3479 private void makeA2dpDeviceUnavailableLater(String address) { 3480 // prevent any activity on the A2DP audio output to avoid unwanted 3481 // reconnection of the sink. 3482 AudioSystem.setParameters("A2dpSuspended=true"); 3483 // the device will be made unavailable later, so consider it disconnected right away 3484 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 3485 // send the delayed message to make the device unavailable later 3486 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 3487 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 3488 3489 } 3490 3491 // must be called synchronized on mConnectedDevices 3492 private void cancelA2dpDeviceTimeout() { 3493 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3494 } 3495 3496 // must be called synchronized on mConnectedDevices 3497 private boolean hasScheduledA2dpDockTimeout() { 3498 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3499 } 3500 3501 private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) 3502 { 3503 if (btDevice == null) { 3504 return; 3505 } 3506 String address = btDevice.getAddress(); 3507 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3508 address = ""; 3509 } 3510 synchronized (mConnectedDevices) { 3511 boolean isConnected = 3512 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 3513 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 3514 3515 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 3516 if (btDevice.isBluetoothDock()) { 3517 if (state == BluetoothProfile.STATE_DISCONNECTED) { 3518 // introduction of a delay for transient disconnections of docks when 3519 // power is rapidly turned off/on, this message will be canceled if 3520 // we reconnect the dock under a preset delay 3521 makeA2dpDeviceUnavailableLater(address); 3522 // the next time isConnected is evaluated, it will be false for the dock 3523 } 3524 } else { 3525 makeA2dpDeviceUnavailableNow(address); 3526 } 3527 synchronized (mCurAudioRoutes) { 3528 if (mCurAudioRoutes.mBluetoothName != null) { 3529 mCurAudioRoutes.mBluetoothName = null; 3530 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3531 SENDMSG_NOOP, 0, 0, null, 0); 3532 } 3533 } 3534 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 3535 if (btDevice.isBluetoothDock()) { 3536 // this could be a reconnection after a transient disconnection 3537 cancelA2dpDeviceTimeout(); 3538 mDockAddress = address; 3539 } else { 3540 // this could be a connection of another A2DP device before the timeout of 3541 // a dock: cancel the dock timeout, and make the dock unavailable now 3542 if(hasScheduledA2dpDockTimeout()) { 3543 cancelA2dpDeviceTimeout(); 3544 makeA2dpDeviceUnavailableNow(mDockAddress); 3545 } 3546 } 3547 makeA2dpDeviceAvailable(address); 3548 synchronized (mCurAudioRoutes) { 3549 String name = btDevice.getAliasName(); 3550 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) { 3551 mCurAudioRoutes.mBluetoothName = name; 3552 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3553 SENDMSG_NOOP, 0, 0, null, 0); 3554 } 3555 } 3556 } 3557 } 3558 } 3559 3560 private boolean handleDeviceConnection(boolean connected, int device, String params) { 3561 synchronized (mConnectedDevices) { 3562 boolean isConnected = (mConnectedDevices.containsKey(device) && 3563 (params.isEmpty() || mConnectedDevices.get(device).equals(params))); 3564 3565 if (isConnected && !connected) { 3566 AudioSystem.setDeviceConnectionState(device, 3567 AudioSystem.DEVICE_STATE_UNAVAILABLE, 3568 mConnectedDevices.get(device)); 3569 mConnectedDevices.remove(device); 3570 return true; 3571 } else if (!isConnected && connected) { 3572 AudioSystem.setDeviceConnectionState(device, 3573 AudioSystem.DEVICE_STATE_AVAILABLE, 3574 params); 3575 mConnectedDevices.put(new Integer(device), params); 3576 return true; 3577 } 3578 } 3579 return false; 3580 } 3581 3582 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only 3583 // sent if none of these devices is connected. 3584 int mBecomingNoisyIntentDevices = 3585 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | 3586 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL | 3587 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | 3588 AudioSystem.DEVICE_OUT_ALL_USB; 3589 3590 // must be called before removing the device from mConnectedDevices 3591 private int checkSendBecomingNoisyIntent(int device, int state) { 3592 int delay = 0; 3593 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) { 3594 int devices = 0; 3595 for (int dev : mConnectedDevices.keySet()) { 3596 if ((dev & mBecomingNoisyIntentDevices) != 0) { 3597 devices |= dev; 3598 } 3599 } 3600 if (devices == device) { 3601 sendMsg(mAudioHandler, 3602 MSG_BROADCAST_AUDIO_BECOMING_NOISY, 3603 SENDMSG_REPLACE, 3604 0, 3605 0, 3606 null, 3607 0); 3608 delay = 1000; 3609 } 3610 } 3611 3612 if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) || 3613 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { 3614 delay = 1000; 3615 } 3616 return delay; 3617 } 3618 3619 private void sendDeviceConnectionIntent(int device, int state, String name) 3620 { 3621 Intent intent = new Intent(); 3622 3623 intent.putExtra("state", state); 3624 intent.putExtra("name", name); 3625 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3626 3627 int connType = 0; 3628 3629 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) { 3630 connType = AudioRoutesInfo.MAIN_HEADSET; 3631 intent.setAction(Intent.ACTION_HEADSET_PLUG); 3632 intent.putExtra("microphone", 1); 3633 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) { 3634 connType = AudioRoutesInfo.MAIN_HEADPHONES; 3635 intent.setAction(Intent.ACTION_HEADSET_PLUG); 3636 intent.putExtra("microphone", 0); 3637 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) { 3638 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3639 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 3640 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { 3641 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3642 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 3643 } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { 3644 connType = AudioRoutesInfo.MAIN_HDMI; 3645 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); 3646 } 3647 3648 synchronized (mCurAudioRoutes) { 3649 if (connType != 0) { 3650 int newConn = mCurAudioRoutes.mMainType; 3651 if (state != 0) { 3652 newConn |= connType; 3653 } else { 3654 newConn &= ~connType; 3655 } 3656 if (newConn != mCurAudioRoutes.mMainType) { 3657 mCurAudioRoutes.mMainType = newConn; 3658 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3659 SENDMSG_NOOP, 0, 0, null, 0); 3660 } 3661 } 3662 } 3663 3664 final long ident = Binder.clearCallingIdentity(); 3665 try { 3666 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); 3667 } finally { 3668 Binder.restoreCallingIdentity(ident); 3669 } 3670 } 3671 3672 private void onSetWiredDeviceConnectionState(int device, int state, String name) 3673 { 3674 synchronized (mConnectedDevices) { 3675 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3676 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3677 setBluetoothA2dpOnInt(true); 3678 } 3679 boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0); 3680 handleDeviceConnection((state == 1), device, (isUsb ? name : "")); 3681 if (state != 0) { 3682 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3683 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) { 3684 setBluetoothA2dpOnInt(false); 3685 } 3686 if ((device & mSafeMediaVolumeDevices) != 0) { 3687 sendMsg(mAudioHandler, 3688 MSG_CHECK_MUSIC_ACTIVE, 3689 SENDMSG_REPLACE, 3690 0, 3691 0, 3692 null, 3693 MUSIC_ACTIVE_POLL_PERIOD_MS); 3694 } 3695 } 3696 if (!isUsb) { 3697 sendDeviceConnectionIntent(device, state, name); 3698 } 3699 } 3700 } 3701 3702 /* cache of the address of the last dock the device was connected to */ 3703 private String mDockAddress; 3704 3705 /** 3706 * Receiver for misc intent broadcasts the Phone app cares about. 3707 */ 3708 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 3709 @Override 3710 public void onReceive(Context context, Intent intent) { 3711 String action = intent.getAction(); 3712 int device; 3713 int state; 3714 3715 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3716 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3717 Intent.EXTRA_DOCK_STATE_UNDOCKED); 3718 int config; 3719 switch (dockState) { 3720 case Intent.EXTRA_DOCK_STATE_DESK: 3721 config = AudioSystem.FORCE_BT_DESK_DOCK; 3722 break; 3723 case Intent.EXTRA_DOCK_STATE_CAR: 3724 config = AudioSystem.FORCE_BT_CAR_DOCK; 3725 break; 3726 case Intent.EXTRA_DOCK_STATE_LE_DESK: 3727 config = AudioSystem.FORCE_ANALOG_DOCK; 3728 break; 3729 case Intent.EXTRA_DOCK_STATE_HE_DESK: 3730 config = AudioSystem.FORCE_DIGITAL_DOCK; 3731 break; 3732 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3733 default: 3734 config = AudioSystem.FORCE_NONE; 3735 } 3736 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 3737 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 3738 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3739 BluetoothProfile.STATE_DISCONNECTED); 3740 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3741 String address = null; 3742 3743 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3744 if (btDevice == null) { 3745 return; 3746 } 3747 3748 address = btDevice.getAddress(); 3749 BluetoothClass btClass = btDevice.getBluetoothClass(); 3750 if (btClass != null) { 3751 switch (btClass.getDeviceClass()) { 3752 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3753 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3754 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3755 break; 3756 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3757 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3758 break; 3759 } 3760 } 3761 3762 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3763 address = ""; 3764 } 3765 3766 boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 3767 if (handleDeviceConnection(connected, device, address)) { 3768 synchronized (mScoClients) { 3769 if (connected) { 3770 mBluetoothHeadsetDevice = btDevice; 3771 } else { 3772 mBluetoothHeadsetDevice = null; 3773 resetBluetoothSco(); 3774 } 3775 } 3776 } 3777 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 3778 action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 3779 state = intent.getIntExtra("state", 0); 3780 int alsaCard = intent.getIntExtra("card", -1); 3781 int alsaDevice = intent.getIntExtra("device", -1); 3782 String params = (alsaCard == -1 && alsaDevice == -1 ? "" 3783 : "card=" + alsaCard + ";device=" + alsaDevice); 3784 device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3785 AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 3786 Log.v(TAG, "Broadcast Receiver: Got " 3787 + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3788 "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 3789 + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 3790 setWiredDeviceConnectionState(device, state, params); 3791 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 3792 boolean broadcast = false; 3793 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 3794 synchronized (mScoClients) { 3795 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 3796 // broadcast intent if the connection was initated by AudioService 3797 if (!mScoClients.isEmpty() && 3798 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 3799 mScoAudioState == SCO_STATE_ACTIVATE_REQ || 3800 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 3801 broadcast = true; 3802 } 3803 switch (btState) { 3804 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 3805 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 3806 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3807 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3808 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3809 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3810 } 3811 break; 3812 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 3813 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 3814 mScoAudioState = SCO_STATE_INACTIVE; 3815 clearAllScoClients(0, false); 3816 break; 3817 case BluetoothHeadset.STATE_AUDIO_CONNECTING: 3818 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3819 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3820 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 3821 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 3822 } 3823 default: 3824 // do not broadcast CONNECTING or invalid state 3825 broadcast = false; 3826 break; 3827 } 3828 } 3829 if (broadcast) { 3830 broadcastScoConnectionState(scoAudioState); 3831 //FIXME: this is to maintain compatibility with deprecated intent 3832 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3833 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3834 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 3835 sendStickyBroadcastToAll(newIntent); 3836 } 3837 } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 3838 mBootCompleted = true; 3839 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 3840 0, 0, null, 0); 3841 3842 mKeyguardManager = 3843 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 3844 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 3845 resetBluetoothSco(); 3846 getBluetoothHeadset(); 3847 //FIXME: this is to maintain compatibility with deprecated intent 3848 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 3849 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 3850 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 3851 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 3852 sendStickyBroadcastToAll(newIntent); 3853 3854 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 3855 if (adapter != null) { 3856 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 3857 BluetoothProfile.A2DP); 3858 } 3859 3860 sendMsg(mAudioHandler, 3861 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, 3862 SENDMSG_REPLACE, 3863 0, 3864 0, 3865 null, 3866 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); 3867 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { 3868 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 3869 // a package is being removed, not replaced 3870 String packageName = intent.getData().getSchemeSpecificPart(); 3871 if (packageName != null) { 3872 removeMediaButtonReceiverForPackage(packageName); 3873 } 3874 } 3875 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 3876 AudioSystem.setParameters("screen_state=on"); 3877 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 3878 AudioSystem.setParameters("screen_state=off"); 3879 } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) { 3880 handleConfigurationChanged(context); 3881 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 3882 // attempt to stop music playabck for background user 3883 sendMsg(mAudioHandler, 3884 MSG_BROADCAST_AUDIO_BECOMING_NOISY, 3885 SENDMSG_REPLACE, 3886 0, 3887 0, 3888 null, 3889 0); 3890 // load volume settings for new user 3891 readAudioSettings(true /*userSwitch*/); 3892 // preserve STREAM_MUSIC volume from one user to the next. 3893 sendMsg(mAudioHandler, 3894 MSG_SET_ALL_VOLUMES, 3895 SENDMSG_QUEUE, 3896 0, 3897 0, 3898 mStreamStates[AudioSystem.STREAM_MUSIC], 0); 3899 } 3900 } 3901 } 3902 3903 //========================================================================================== 3904 // AudioFocus 3905 //========================================================================================== 3906 3907 /* constant to identify focus stack entry that is used to hold the focus while the phone 3908 * is ringing or during a call. Used by com.android.internal.telephony.CallManager when 3909 * entering and exiting calls. 3910 */ 3911 public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; 3912 3913 private final static Object mAudioFocusLock = new Object(); 3914 3915 private final static Object mRingingLock = new Object(); 3916 3917 private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 3918 @Override 3919 public void onCallStateChanged(int state, String incomingNumber) { 3920 if (state == TelephonyManager.CALL_STATE_RINGING) { 3921 //Log.v(TAG, " CALL_STATE_RINGING"); 3922 synchronized(mRingingLock) { 3923 mIsRinging = true; 3924 } 3925 } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) 3926 || (state == TelephonyManager.CALL_STATE_IDLE)) { 3927 synchronized(mRingingLock) { 3928 mIsRinging = false; 3929 } 3930 } 3931 } 3932 }; 3933 3934 private void notifyTopOfAudioFocusStack() { 3935 // notify the top of the stack it gained focus 3936 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3937 if (canReassignAudioFocus()) { 3938 try { 3939 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3940 AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 3941 } catch (RemoteException e) { 3942 Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 3943 e.printStackTrace(); 3944 } 3945 } 3946 } 3947 } 3948 3949 private static class FocusStackEntry { 3950 public int mStreamType = -1;// no stream type 3951 public IAudioFocusDispatcher mFocusDispatcher = null; 3952 public IBinder mSourceRef = null; 3953 public String mClientId; 3954 public int mFocusChangeType; 3955 public AudioFocusDeathHandler mHandler; 3956 public String mPackageName; 3957 public int mCallingUid; 3958 3959 public FocusStackEntry() { 3960 } 3961 3962 public FocusStackEntry(int streamType, int duration, 3963 IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 3964 String pn, int uid) { 3965 mStreamType = streamType; 3966 mFocusDispatcher = afl; 3967 mSourceRef = source; 3968 mClientId = id; 3969 mFocusChangeType = duration; 3970 mHandler = hdlr; 3971 mPackageName = pn; 3972 mCallingUid = uid; 3973 } 3974 3975 public void unlinkToDeath() { 3976 try { 3977 if (mSourceRef != null && mHandler != null) { 3978 mSourceRef.unlinkToDeath(mHandler, 0); 3979 mHandler = null; 3980 } 3981 } catch (java.util.NoSuchElementException e) { 3982 Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); 3983 } 3984 } 3985 3986 @Override 3987 protected void finalize() throws Throwable { 3988 unlinkToDeath(); // unlink exception handled inside method 3989 super.finalize(); 3990 } 3991 } 3992 3993 private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 3994 3995 /** 3996 * Helper function: 3997 * Display in the log the current entries in the audio focus stack 3998 */ 3999 private void dumpFocusStack(PrintWriter pw) { 4000 pw.println("\nAudio Focus stack entries:"); 4001 synchronized(mAudioFocusLock) { 4002 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 4003 while(stackIterator.hasNext()) { 4004 FocusStackEntry fse = stackIterator.next(); 4005 pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 4006 + " -- duration: " + fse.mFocusChangeType 4007 + " -- uid: " + fse.mCallingUid 4008 + " -- stream: " + fse.mStreamType); 4009 } 4010 } 4011 } 4012 4013 /** 4014 * Helper function: 4015 * Called synchronized on mAudioFocusLock 4016 * Remove a focus listener from the focus stack. 4017 * @param focusListenerToRemove the focus listener 4018 * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 4019 * focus, notify the next item in the stack it gained focus. 4020 */ 4021 private void removeFocusStackEntry(String clientToRemove, boolean signal) { 4022 // is the current top of the focus stack abandoning focus? (because of request, not death) 4023 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 4024 { 4025 //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 4026 FocusStackEntry fse = mFocusStack.pop(); 4027 fse.unlinkToDeath(); 4028 if (signal) { 4029 // notify the new top of the stack it gained focus 4030 notifyTopOfAudioFocusStack(); 4031 // there's a new top of the stack, let the remote control know 4032 synchronized(mRCStack) { 4033 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4034 } 4035 } 4036 } else { 4037 // focus is abandoned by a client that's not at the top of the stack, 4038 // no need to update focus. 4039 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 4040 while(stackIterator.hasNext()) { 4041 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 4042 if(fse.mClientId.equals(clientToRemove)) { 4043 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 4044 + fse.mClientId); 4045 stackIterator.remove(); 4046 fse.unlinkToDeath(); 4047 } 4048 } 4049 } 4050 } 4051 4052 /** 4053 * Helper function: 4054 * Called synchronized on mAudioFocusLock 4055 * Remove focus listeners from the focus stack for a particular client when it has died. 4056 */ 4057 private void removeFocusStackEntryForClient(IBinder cb) { 4058 // is the owner of the audio focus part of the client to remove? 4059 boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 4060 mFocusStack.peek().mSourceRef.equals(cb); 4061 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 4062 while(stackIterator.hasNext()) { 4063 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 4064 if(fse.mSourceRef.equals(cb)) { 4065 Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 4066 + fse.mClientId); 4067 stackIterator.remove(); 4068 // the client just died, no need to unlink to its death 4069 } 4070 } 4071 if (isTopOfStackForClientToRemove) { 4072 // we removed an entry at the top of the stack: 4073 // notify the new top of the stack it gained focus. 4074 notifyTopOfAudioFocusStack(); 4075 // there's a new top of the stack, let the remote control know 4076 synchronized(mRCStack) { 4077 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4078 } 4079 } 4080 } 4081 4082 /** 4083 * Helper function: 4084 * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 4085 */ 4086 private boolean canReassignAudioFocus() { 4087 // focus requests are rejected during a phone call or when the phone is ringing 4088 // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 4089 if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { 4090 return false; 4091 } 4092 return true; 4093 } 4094 4095 /** 4096 * Inner class to monitor audio focus client deaths, and remove them from the audio focus 4097 * stack if necessary. 4098 */ 4099 private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 4100 private IBinder mCb; // To be notified of client's death 4101 4102 AudioFocusDeathHandler(IBinder cb) { 4103 mCb = cb; 4104 } 4105 4106 public void binderDied() { 4107 synchronized(mAudioFocusLock) { 4108 Log.w(TAG, " AudioFocus audio focus client died"); 4109 removeFocusStackEntryForClient(mCb); 4110 } 4111 } 4112 4113 public IBinder getBinder() { 4114 return mCb; 4115 } 4116 } 4117 4118 4119 /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 4120 public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 4121 IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 4122 Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 4123 // the main stream type for the audio focus request is currently not used. It may 4124 // potentially be used to handle multiple stream type-dependent audio focuses. 4125 4126 // we need a valid binder callback for clients 4127 if (!cb.pingBinder()) { 4128 Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 4129 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4130 } 4131 4132 synchronized(mAudioFocusLock) { 4133 if (!canReassignAudioFocus()) { 4134 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4135 } 4136 4137 // handle the potential premature death of the new holder of the focus 4138 // (premature death == death before abandoning focus) 4139 // Register for client death notification 4140 AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 4141 try { 4142 cb.linkToDeath(afdh, 0); 4143 } catch (RemoteException e) { 4144 // client has already died! 4145 Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 4146 return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 4147 } 4148 4149 if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 4150 // if focus is already owned by this client and the reason for acquiring the focus 4151 // hasn't changed, don't do anything 4152 if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 4153 // unlink death handler so it can be gc'ed. 4154 // linkToDeath() creates a JNI global reference preventing collection. 4155 cb.unlinkToDeath(afdh, 0); 4156 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 4157 } 4158 // the reason for the audio focus request has changed: remove the current top of 4159 // stack and respond as if we had a new focus owner 4160 FocusStackEntry fse = mFocusStack.pop(); 4161 fse.unlinkToDeath(); 4162 } 4163 4164 // notify current top of stack it is losing focus 4165 if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 4166 try { 4167 mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 4168 -1 * focusChangeHint, // loss and gain codes are inverse of each other 4169 mFocusStack.peek().mClientId); 4170 } catch (RemoteException e) { 4171 Log.e(TAG, " Failure to signal loss of focus due to "+ e); 4172 e.printStackTrace(); 4173 } 4174 } 4175 4176 // focus requester might already be somewhere below in the stack, remove it 4177 removeFocusStackEntry(clientId, false /* signal */); 4178 4179 // push focus requester at the top of the audio focus stack 4180 mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, 4181 clientId, afdh, callingPackageName, Binder.getCallingUid())); 4182 4183 // there's a new top of the stack, let the remote control know 4184 synchronized(mRCStack) { 4185 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4186 } 4187 }//synchronized(mAudioFocusLock) 4188 4189 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 4190 } 4191 4192 /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 4193 public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 4194 Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 4195 try { 4196 // this will take care of notifying the new focus owner if needed 4197 synchronized(mAudioFocusLock) { 4198 removeFocusStackEntry(clientId, true); 4199 } 4200 } catch (java.util.ConcurrentModificationException cme) { 4201 // Catching this exception here is temporary. It is here just to prevent 4202 // a crash seen when the "Silent" notification is played. This is believed to be fixed 4203 // but this try catch block is left just to be safe. 4204 Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 4205 cme.printStackTrace(); 4206 } 4207 4208 return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 4209 } 4210 4211 4212 public void unregisterAudioFocusClient(String clientId) { 4213 synchronized(mAudioFocusLock) { 4214 removeFocusStackEntry(clientId, false); 4215 } 4216 } 4217 4218 4219 //========================================================================================== 4220 // RemoteControl 4221 //========================================================================================== 4222 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 4223 filterMediaKeyEvent(keyEvent, false /*needWakeLock*/); 4224 } 4225 4226 public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 4227 filterMediaKeyEvent(keyEvent, true /*needWakeLock*/); 4228 } 4229 4230 private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 4231 // sanity check on the incoming key event 4232 if (!isValidMediaKeyEvent(keyEvent)) { 4233 Log.e(TAG, "not dispatching invalid media key event " + keyEvent); 4234 return; 4235 } 4236 // event filtering for telephony 4237 synchronized(mRingingLock) { 4238 synchronized(mRCStack) { 4239 if ((mMediaReceiverForCalls != null) && 4240 (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) { 4241 dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); 4242 return; 4243 } 4244 } 4245 } 4246 // event filtering based on voice-based interactions 4247 if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) { 4248 filterVoiceInputKeyEvent(keyEvent, needWakeLock); 4249 } else { 4250 dispatchMediaKeyEvent(keyEvent, needWakeLock); 4251 } 4252 } 4253 4254 /** 4255 * Handles the dispatching of the media button events to the telephony package. 4256 * Precondition: mMediaReceiverForCalls != null 4257 * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 4258 * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 4259 * is dispatched. 4260 */ 4261 private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { 4262 Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 4263 keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 4264 keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); 4265 if (needWakeLock) { 4266 mMediaEventWakeLock.acquire(); 4267 keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 4268 } 4269 final long ident = Binder.clearCallingIdentity(); 4270 try { 4271 mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, 4272 null, mKeyEventDone, mAudioHandler, Activity.RESULT_OK, null, null); 4273 } finally { 4274 Binder.restoreCallingIdentity(ident); 4275 } 4276 } 4277 4278 /** 4279 * Handles the dispatching of the media button events to one of the registered listeners, 4280 * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. 4281 * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 4282 * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 4283 * is dispatched. 4284 */ 4285 private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 4286 if (needWakeLock) { 4287 mMediaEventWakeLock.acquire(); 4288 } 4289 Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 4290 keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 4291 synchronized(mRCStack) { 4292 if (!mRCStack.empty()) { 4293 // send the intent that was registered by the client 4294 try { 4295 mRCStack.peek().mMediaIntent.send(mContext, 4296 needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, 4297 keyIntent, AudioService.this, mAudioHandler); 4298 } catch (CanceledException e) { 4299 Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); 4300 e.printStackTrace(); 4301 } 4302 } else { 4303 // legacy behavior when nobody registered their media button event receiver 4304 // through AudioManager 4305 if (needWakeLock) { 4306 keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 4307 } 4308 final long ident = Binder.clearCallingIdentity(); 4309 try { 4310 mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL, 4311 null, mKeyEventDone, 4312 mAudioHandler, Activity.RESULT_OK, null, null); 4313 } finally { 4314 Binder.restoreCallingIdentity(ident); 4315 } 4316 } 4317 } 4318 } 4319 4320 /** 4321 * The different actions performed in response to a voice button key event. 4322 */ 4323 private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1; 4324 private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2; 4325 private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3; 4326 4327 private final Object mVoiceEventLock = new Object(); 4328 private boolean mVoiceButtonDown; 4329 private boolean mVoiceButtonHandled; 4330 4331 /** 4332 * Filter key events that may be used for voice-based interactions 4333 * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported 4334 * media buttons that can be used to trigger voice-based interactions. 4335 * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 4336 * is dispatched. 4337 */ 4338 private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 4339 if (DEBUG_RC) { 4340 Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock); 4341 } 4342 4343 int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS; 4344 int keyAction = keyEvent.getAction(); 4345 synchronized (mVoiceEventLock) { 4346 if (keyAction == KeyEvent.ACTION_DOWN) { 4347 if (keyEvent.getRepeatCount() == 0) { 4348 // initial down 4349 mVoiceButtonDown = true; 4350 mVoiceButtonHandled = false; 4351 } else if (mVoiceButtonDown && !mVoiceButtonHandled 4352 && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { 4353 // long-press, start voice-based interactions 4354 mVoiceButtonHandled = true; 4355 voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT; 4356 } 4357 } else if (keyAction == KeyEvent.ACTION_UP) { 4358 if (mVoiceButtonDown) { 4359 // voice button up 4360 mVoiceButtonDown = false; 4361 if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { 4362 voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS; 4363 } 4364 } 4365 } 4366 }//synchronized (mVoiceEventLock) 4367 4368 // take action after media button event filtering for voice-based interactions 4369 switch (voiceButtonAction) { 4370 case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS: 4371 if (DEBUG_RC) Log.v(TAG, " ignore key event"); 4372 break; 4373 case VOICEBUTTON_ACTION_START_VOICE_INPUT: 4374 if (DEBUG_RC) Log.v(TAG, " start voice-based interactions"); 4375 // then start the voice-based interactions 4376 startVoiceBasedInteractions(needWakeLock); 4377 break; 4378 case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS: 4379 if (DEBUG_RC) Log.v(TAG, " send simulated key event, wakelock=" + needWakeLock); 4380 sendSimulatedMediaButtonEvent(keyEvent, needWakeLock); 4381 break; 4382 } 4383 } 4384 4385 private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) { 4386 // send DOWN event 4387 KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN); 4388 dispatchMediaKeyEvent(keyEvent, needWakeLock); 4389 // send UP event 4390 keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP); 4391 dispatchMediaKeyEvent(keyEvent, needWakeLock); 4392 4393 } 4394 4395 4396 private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { 4397 if (keyEvent == null) { 4398 return false; 4399 } 4400 final int keyCode = keyEvent.getKeyCode(); 4401 switch (keyCode) { 4402 case KeyEvent.KEYCODE_MUTE: 4403 case KeyEvent.KEYCODE_HEADSETHOOK: 4404 case KeyEvent.KEYCODE_MEDIA_PLAY: 4405 case KeyEvent.KEYCODE_MEDIA_PAUSE: 4406 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 4407 case KeyEvent.KEYCODE_MEDIA_STOP: 4408 case KeyEvent.KEYCODE_MEDIA_NEXT: 4409 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 4410 case KeyEvent.KEYCODE_MEDIA_REWIND: 4411 case KeyEvent.KEYCODE_MEDIA_RECORD: 4412 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 4413 case KeyEvent.KEYCODE_MEDIA_CLOSE: 4414 case KeyEvent.KEYCODE_MEDIA_EJECT: 4415 break; 4416 default: 4417 return false; 4418 } 4419 return true; 4420 } 4421 4422 /** 4423 * Checks whether the given key code is one that can trigger the launch of voice-based 4424 * interactions. 4425 * @param keyCode the key code associated with the key event 4426 * @return true if the key is one of the supported voice-based interaction triggers 4427 */ 4428 private static boolean isValidVoiceInputKeyCode(int keyCode) { 4429 if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { 4430 return true; 4431 } else { 4432 return false; 4433 } 4434 } 4435 4436 /** 4437 * Tell the system to start voice-based interactions / voice commands 4438 */ 4439 private void startVoiceBasedInteractions(boolean needWakeLock) { 4440 Intent voiceIntent = null; 4441 // select which type of search to launch: 4442 // - screen on and device unlocked: action is ACTION_WEB_SEARCH 4443 // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE 4444 // with EXTRA_SECURE set to true if the device is securely locked 4445 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 4446 boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); 4447 if (!isLocked && pm.isScreenOn()) { 4448 voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); 4449 } else { 4450 voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); 4451 voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, 4452 isLocked && mKeyguardManager.isKeyguardSecure()); 4453 } 4454 // start the search activity 4455 if (needWakeLock) { 4456 mMediaEventWakeLock.acquire(); 4457 } 4458 try { 4459 if (voiceIntent != null) { 4460 voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 4461 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 4462 mContext.startActivity(voiceIntent); 4463 } 4464 } catch (ActivityNotFoundException e) { 4465 Log.w(TAG, "No activity for search: " + e); 4466 } finally { 4467 if (needWakeLock) { 4468 mMediaEventWakeLock.release(); 4469 } 4470 } 4471 } 4472 4473 private PowerManager.WakeLock mMediaEventWakeLock; 4474 4475 private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number 4476 4477 // only set when wakelock was acquired, no need to check value when received 4478 private static final String EXTRA_WAKELOCK_ACQUIRED = 4479 "android.media.AudioService.WAKELOCK_ACQUIRED"; 4480 4481 public void onSendFinished(PendingIntent pendingIntent, Intent intent, 4482 int resultCode, String resultData, Bundle resultExtras) { 4483 if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { 4484 mMediaEventWakeLock.release(); 4485 } 4486 } 4487 4488 BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { 4489 public void onReceive(Context context, Intent intent) { 4490 if (intent == null) { 4491 return; 4492 } 4493 Bundle extras = intent.getExtras(); 4494 if (extras == null) { 4495 return; 4496 } 4497 if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) { 4498 mMediaEventWakeLock.release(); 4499 } 4500 } 4501 }; 4502 4503 private final Object mCurrentRcLock = new Object(); 4504 /** 4505 * The one remote control client which will receive a request for display information. 4506 * This object may be null. 4507 * Access protected by mCurrentRcLock. 4508 */ 4509 private IRemoteControlClient mCurrentRcClient = null; 4510 4511 private final static int RC_INFO_NONE = 0; 4512 private final static int RC_INFO_ALL = 4513 RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | 4514 RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | 4515 RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | 4516 RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; 4517 4518 /** 4519 * A monotonically increasing generation counter for mCurrentRcClient. 4520 * Only accessed with a lock on mCurrentRcLock. 4521 * No value wrap-around issues as we only act on equal values. 4522 */ 4523 private int mCurrentRcClientGen = 0; 4524 4525 /** 4526 * Inner class to monitor remote control client deaths, and remove the client for the 4527 * remote control stack if necessary. 4528 */ 4529 private class RcClientDeathHandler implements IBinder.DeathRecipient { 4530 private IBinder mCb; // To be notified of client's death 4531 private PendingIntent mMediaIntent; 4532 4533 RcClientDeathHandler(IBinder cb, PendingIntent pi) { 4534 mCb = cb; 4535 mMediaIntent = pi; 4536 } 4537 4538 public void binderDied() { 4539 Log.w(TAG, " RemoteControlClient died"); 4540 // remote control client died, make sure the displays don't use it anymore 4541 // by setting its remote control client to null 4542 registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); 4543 // the dead client was maybe handling remote playback, reevaluate 4544 postReevaluateRemote(); 4545 } 4546 4547 public IBinder getBinder() { 4548 return mCb; 4549 } 4550 } 4551 4552 /** 4553 * A global counter for RemoteControlClient identifiers 4554 */ 4555 private static int sLastRccId = 0; 4556 4557 private class RemotePlaybackState { 4558 int mRccId; 4559 int mVolume; 4560 int mVolumeMax; 4561 int mVolumeHandling; 4562 4563 private RemotePlaybackState(int id, int vol, int volMax) { 4564 mRccId = id; 4565 mVolume = vol; 4566 mVolumeMax = volMax; 4567 mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 4568 } 4569 } 4570 4571 /** 4572 * Internal cache for the playback information of the RemoteControlClient whose volume gets to 4573 * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack 4574 * every time we need this info. 4575 */ 4576 private RemotePlaybackState mMainRemote; 4577 /** 4578 * Indicates whether the "main" RemoteControlClient is considered active. 4579 * Use synchronized on mMainRemote. 4580 */ 4581 private boolean mMainRemoteIsActive; 4582 /** 4583 * Indicates whether there is remote playback going on. True even if there is no "active" 4584 * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it 4585 * handles remote playback. 4586 * Use synchronized on mMainRemote. 4587 */ 4588 private boolean mHasRemotePlayback; 4589 4590 private static class RemoteControlStackEntry { 4591 public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 4592 /** 4593 * The target for the ACTION_MEDIA_BUTTON events. 4594 * Always non null. 4595 */ 4596 public PendingIntent mMediaIntent; 4597 /** 4598 * The registered media button event receiver. 4599 * Always non null. 4600 */ 4601 public ComponentName mReceiverComponent; 4602 public String mCallingPackageName; 4603 public int mCallingUid; 4604 /** 4605 * Provides access to the information to display on the remote control. 4606 * May be null (when a media button event receiver is registered, 4607 * but no remote control client has been registered) */ 4608 public IRemoteControlClient mRcClient; 4609 public RcClientDeathHandler mRcClientDeathHandler; 4610 /** 4611 * Information only used for non-local playback 4612 */ 4613 public int mPlaybackType; 4614 public int mPlaybackVolume; 4615 public int mPlaybackVolumeMax; 4616 public int mPlaybackVolumeHandling; 4617 public int mPlaybackStream; 4618 public int mPlaybackState; 4619 public IRemoteVolumeObserver mRemoteVolumeObs; 4620 4621 public void resetPlaybackInfo() { 4622 mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; 4623 mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 4624 mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 4625 mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 4626 mPlaybackStream = AudioManager.STREAM_MUSIC; 4627 mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED; 4628 mRemoteVolumeObs = null; 4629 } 4630 4631 /** precondition: mediaIntent != null, eventReceiver != null */ 4632 public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { 4633 mMediaIntent = mediaIntent; 4634 mReceiverComponent = eventReceiver; 4635 mCallingUid = -1; 4636 mRcClient = null; 4637 mRccId = ++sLastRccId; 4638 4639 resetPlaybackInfo(); 4640 } 4641 4642 public void unlinkToRcClientDeath() { 4643 if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { 4644 try { 4645 mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); 4646 mRcClientDeathHandler = null; 4647 } catch (java.util.NoSuchElementException e) { 4648 // not much we can do here 4649 Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); 4650 e.printStackTrace(); 4651 } 4652 } 4653 } 4654 4655 @Override 4656 protected void finalize() throws Throwable { 4657 unlinkToRcClientDeath();// unlink exception handled inside method 4658 super.finalize(); 4659 } 4660 } 4661 4662 /** 4663 * The stack of remote control event receivers. 4664 * Code sections and methods that modify the remote control event receiver stack are 4665 * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either 4666 * stack, audio focus or RC, can lead to a change in the remote control display 4667 */ 4668 private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 4669 4670 /** 4671 * The component the telephony package can register so telephony calls have priority to 4672 * handle media button events 4673 */ 4674 private ComponentName mMediaReceiverForCalls = null; 4675 4676 /** 4677 * Helper function: 4678 * Display in the log the current entries in the remote control focus stack 4679 */ 4680 private void dumpRCStack(PrintWriter pw) { 4681 pw.println("\nRemote Control stack entries:"); 4682 synchronized(mRCStack) { 4683 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4684 while(stackIterator.hasNext()) { 4685 RemoteControlStackEntry rcse = stackIterator.next(); 4686 pw.println(" pi: " + rcse.mMediaIntent + 4687 " -- ercvr: " + rcse.mReceiverComponent + 4688 " -- client: " + rcse.mRcClient + 4689 " -- uid: " + rcse.mCallingUid + 4690 " -- type: " + rcse.mPlaybackType + 4691 " state: " + rcse.mPlaybackState); 4692 } 4693 } 4694 } 4695 4696 /** 4697 * Helper function: 4698 * Display in the log the current entries in the remote control stack, focusing 4699 * on RemoteControlClient data 4700 */ 4701 private void dumpRCCStack(PrintWriter pw) { 4702 pw.println("\nRemote Control Client stack entries:"); 4703 synchronized(mRCStack) { 4704 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4705 while(stackIterator.hasNext()) { 4706 RemoteControlStackEntry rcse = stackIterator.next(); 4707 pw.println(" uid: " + rcse.mCallingUid + 4708 " -- id: " + rcse.mRccId + 4709 " -- type: " + rcse.mPlaybackType + 4710 " -- state: " + rcse.mPlaybackState + 4711 " -- vol handling: " + rcse.mPlaybackVolumeHandling + 4712 " -- vol: " + rcse.mPlaybackVolume + 4713 " -- volMax: " + rcse.mPlaybackVolumeMax + 4714 " -- volObs: " + rcse.mRemoteVolumeObs); 4715 4716 } 4717 } 4718 synchronized (mMainRemote) { 4719 pw.println("\nRemote Volume State:"); 4720 pw.println(" has remote: " + mHasRemotePlayback); 4721 pw.println(" is remote active: " + mMainRemoteIsActive); 4722 pw.println(" rccId: " + mMainRemote.mRccId); 4723 pw.println(" volume handling: " 4724 + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? 4725 "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); 4726 pw.println(" volume: " + mMainRemote.mVolume); 4727 pw.println(" volume steps: " + mMainRemote.mVolumeMax); 4728 } 4729 } 4730 4731 /** 4732 * Helper function: 4733 * Remove any entry in the remote control stack that has the same package name as packageName 4734 * Pre-condition: packageName != null 4735 */ 4736 private void removeMediaButtonReceiverForPackage(String packageName) { 4737 synchronized(mRCStack) { 4738 if (mRCStack.empty()) { 4739 return; 4740 } else { 4741 RemoteControlStackEntry oldTop = mRCStack.peek(); 4742 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4743 // iterate over the stack entries 4744 while(stackIterator.hasNext()) { 4745 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4746 if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) { 4747 // a stack entry is from the package being removed, remove it from the stack 4748 stackIterator.remove(); 4749 rcse.unlinkToRcClientDeath(); 4750 } 4751 } 4752 if (mRCStack.empty()) { 4753 // no saved media button receiver 4754 mAudioHandler.sendMessage( 4755 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4756 null)); 4757 } else if (oldTop != mRCStack.peek()) { 4758 // the top of the stack has changed, save it in the system settings 4759 // by posting a message to persist it 4760 mAudioHandler.sendMessage( 4761 mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4762 mRCStack.peek().mReceiverComponent)); 4763 } 4764 } 4765 } 4766 } 4767 4768 /** 4769 * Helper function: 4770 * Restore remote control receiver from the system settings. 4771 */ 4772 private void restoreMediaButtonReceiver() { 4773 String receiverName = Settings.System.getStringForUser(mContentResolver, 4774 Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT); 4775 if ((null != receiverName) && !receiverName.isEmpty()) { 4776 ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); 4777 // construct a PendingIntent targeted to the restored component name 4778 // for the media button and register it 4779 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4780 // the associated intent will be handled by the component being registered 4781 mediaButtonIntent.setComponent(eventReceiver); 4782 PendingIntent pi = PendingIntent.getBroadcast(mContext, 4783 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 4784 registerMediaButtonIntent(pi, eventReceiver); 4785 } 4786 } 4787 4788 /** 4789 * Helper function: 4790 * Set the new remote control receiver at the top of the RC focus stack. 4791 * precondition: mediaIntent != null, target != null 4792 */ 4793 private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) { 4794 // already at top of stack? 4795 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { 4796 return; 4797 } 4798 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4799 RemoteControlStackEntry rcse = null; 4800 boolean wasInsideStack = false; 4801 while(stackIterator.hasNext()) { 4802 rcse = (RemoteControlStackEntry)stackIterator.next(); 4803 if(rcse.mMediaIntent.equals(mediaIntent)) { 4804 wasInsideStack = true; 4805 stackIterator.remove(); 4806 break; 4807 } 4808 } 4809 if (!wasInsideStack) { 4810 rcse = new RemoteControlStackEntry(mediaIntent, target); 4811 } 4812 mRCStack.push(rcse); 4813 4814 // post message to persist the default media button receiver 4815 mAudioHandler.sendMessage( mAudioHandler.obtainMessage( 4816 MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); 4817 } 4818 4819 /** 4820 * Helper function: 4821 * Remove the remote control receiver from the RC focus stack. 4822 * precondition: pi != null 4823 */ 4824 private void removeMediaButtonReceiver(PendingIntent pi) { 4825 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4826 while(stackIterator.hasNext()) { 4827 RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4828 if(rcse.mMediaIntent.equals(pi)) { 4829 stackIterator.remove(); 4830 rcse.unlinkToRcClientDeath(); 4831 break; 4832 } 4833 } 4834 } 4835 4836 /** 4837 * Helper function: 4838 * Called synchronized on mRCStack 4839 */ 4840 private boolean isCurrentRcController(PendingIntent pi) { 4841 if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { 4842 return true; 4843 } 4844 return false; 4845 } 4846 4847 //========================================================================================== 4848 // Remote control display / client 4849 //========================================================================================== 4850 /** 4851 * Update the remote control displays with the new "focused" client generation 4852 */ 4853 private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, 4854 PendingIntent newMediaIntent, boolean clearing) { 4855 // NOTE: Only one IRemoteControlDisplay supported in this implementation 4856 if (mRcDisplay != null) { 4857 try { 4858 mRcDisplay.setCurrentClientId( 4859 newClientGeneration, newMediaIntent, clearing); 4860 } catch (RemoteException e) { 4861 Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e); 4862 // if we had a display before, stop monitoring its death 4863 rcDisplay_stopDeathMonitor_syncRcStack(); 4864 mRcDisplay = null; 4865 } 4866 } 4867 } 4868 4869 /** 4870 * Update the remote control clients with the new "focused" client generation 4871 */ 4872 private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { 4873 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4874 while(stackIterator.hasNext()) { 4875 RemoteControlStackEntry se = stackIterator.next(); 4876 if ((se != null) && (se.mRcClient != null)) { 4877 try { 4878 se.mRcClient.setCurrentClientGenerationId(newClientGeneration); 4879 } catch (RemoteException e) { 4880 Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e); 4881 stackIterator.remove(); 4882 se.unlinkToRcClientDeath(); 4883 } 4884 } 4885 } 4886 } 4887 4888 /** 4889 * Update the displays and clients with the new "focused" client generation and name 4890 * @param newClientGeneration the new generation value matching a client update 4891 * @param newClientEventReceiver the media button event receiver associated with the client. 4892 * May be null, which implies there is no registered media button event receiver. 4893 * @param clearing true if the new client generation value maps to a remote control update 4894 * where the display should be cleared. 4895 */ 4896 private void setNewRcClient_syncRcsCurrc(int newClientGeneration, 4897 PendingIntent newMediaIntent, boolean clearing) { 4898 // send the new valid client generation ID to all displays 4899 setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); 4900 // send the new valid client generation ID to all clients 4901 setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); 4902 } 4903 4904 /** 4905 * Called when processing MSG_RCDISPLAY_CLEAR event 4906 */ 4907 private void onRcDisplayClear() { 4908 if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); 4909 4910 synchronized(mRCStack) { 4911 synchronized(mCurrentRcLock) { 4912 mCurrentRcClientGen++; 4913 // synchronously update the displays and clients with the new client generation 4914 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4915 null /*newMediaIntent*/, true /*clearing*/); 4916 } 4917 } 4918 } 4919 4920 /** 4921 * Called when processing MSG_RCDISPLAY_UPDATE event 4922 */ 4923 private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { 4924 synchronized(mRCStack) { 4925 synchronized(mCurrentRcLock) { 4926 if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { 4927 if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); 4928 4929 mCurrentRcClientGen++; 4930 // synchronously update the displays and clients with 4931 // the new client generation 4932 setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4933 rcse.mMediaIntent /*newMediaIntent*/, 4934 false /*clearing*/); 4935 4936 // tell the current client that it needs to send info 4937 try { 4938 mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, 4939 flags, mArtworkExpectedWidth, mArtworkExpectedHeight); 4940 } catch (RemoteException e) { 4941 Log.e(TAG, "Current valid remote client is dead: "+e); 4942 mCurrentRcClient = null; 4943 } 4944 } else { 4945 // the remote control display owner has changed between the 4946 // the message to update the display was sent, and the time it 4947 // gets to be processed (now) 4948 } 4949 } 4950 } 4951 } 4952 4953 4954 /** 4955 * Helper function: 4956 * Called synchronized on mRCStack 4957 */ 4958 private void clearRemoteControlDisplay_syncAfRcs() { 4959 synchronized(mCurrentRcLock) { 4960 mCurrentRcClient = null; 4961 } 4962 // will cause onRcDisplayClear() to be called in AudioService's handler thread 4963 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); 4964 } 4965 4966 /** 4967 * Helper function for code readability: only to be called from 4968 * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for 4969 * this method. 4970 * Preconditions: 4971 * - called synchronized mAudioFocusLock then on mRCStack 4972 * - mRCStack.isEmpty() is false 4973 */ 4974 private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 4975 RemoteControlStackEntry rcse = mRCStack.peek(); 4976 int infoFlagsAboutToBeUsed = infoChangedFlags; 4977 // this is where we enforce opt-in for information display on the remote controls 4978 // with the new AudioManager.registerRemoteControlClient() API 4979 if (rcse.mRcClient == null) { 4980 //Log.w(TAG, "Can't update remote control display with null remote control client"); 4981 clearRemoteControlDisplay_syncAfRcs(); 4982 return; 4983 } 4984 synchronized(mCurrentRcLock) { 4985 if (!rcse.mRcClient.equals(mCurrentRcClient)) { 4986 // new RC client, assume every type of information shall be queried 4987 infoFlagsAboutToBeUsed = RC_INFO_ALL; 4988 } 4989 mCurrentRcClient = rcse.mRcClient; 4990 } 4991 // will cause onRcDisplayUpdate() to be called in AudioService's handler thread 4992 mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 4993 infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); 4994 } 4995 4996 /** 4997 * Helper function: 4998 * Called synchronized on mAudioFocusLock, then mRCStack 4999 * Check whether the remote control display should be updated, triggers the update if required 5000 * @param infoChangedFlags the flags corresponding to the remote control client information 5001 * that has changed, if applicable (checking for the update conditions might trigger a 5002 * clear, rather than an update event). 5003 */ 5004 private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 5005 // determine whether the remote control display should be refreshed 5006 // if either stack is empty, there is a mismatch, so clear the RC display 5007 if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { 5008 clearRemoteControlDisplay_syncAfRcs(); 5009 return; 5010 } 5011 5012 // determine which entry in the AudioFocus stack to consider, and compare against the 5013 // top of the stack for the media button event receivers : simply using the top of the 5014 // stack would make the entry disappear from the RemoteControlDisplay in conditions such as 5015 // notifications playing during music playback. 5016 // crawl the AudioFocus stack until an entry is found with the following characteristics: 5017 // - focus gain on STREAM_MUSIC stream 5018 // - non-transient focus gain on a stream other than music 5019 FocusStackEntry af = null; 5020 Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 5021 while(stackIterator.hasNext()) { 5022 FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 5023 if ((fse.mStreamType == AudioManager.STREAM_MUSIC) 5024 || (fse.mFocusChangeType == AudioManager.AUDIOFOCUS_GAIN)) { 5025 af = fse; 5026 break; 5027 } 5028 } 5029 if (af == null) { 5030 clearRemoteControlDisplay_syncAfRcs(); 5031 return; 5032 } 5033 5034 // if the audio focus and RC owners belong to different packages, there is a mismatch, clear 5035 if ((mRCStack.peek().mCallingPackageName != null) 5036 && (af.mPackageName != null) 5037 && !(mRCStack.peek().mCallingPackageName.compareTo( 5038 af.mPackageName) == 0)) { 5039 clearRemoteControlDisplay_syncAfRcs(); 5040 return; 5041 } 5042 // if the audio focus didn't originate from the same Uid as the one in which the remote 5043 // control information will be retrieved, clear 5044 if (mRCStack.peek().mCallingUid != af.mCallingUid) { 5045 clearRemoteControlDisplay_syncAfRcs(); 5046 return; 5047 } 5048 // refresh conditions were verified: update the remote controls 5049 // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty 5050 updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); 5051 } 5052 5053 /** 5054 * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) 5055 * precondition: mediaIntent != null, target != null 5056 */ 5057 public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { 5058 Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); 5059 5060 synchronized(mAudioFocusLock) { 5061 synchronized(mRCStack) { 5062 pushMediaButtonReceiver(mediaIntent, eventReceiver); 5063 // new RC client, assume every type of information shall be queried 5064 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 5065 } 5066 } 5067 } 5068 5069 /** 5070 * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) 5071 * precondition: mediaIntent != null, eventReceiver != null 5072 */ 5073 public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) 5074 { 5075 Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); 5076 5077 synchronized(mAudioFocusLock) { 5078 synchronized(mRCStack) { 5079 boolean topOfStackWillChange = isCurrentRcController(mediaIntent); 5080 removeMediaButtonReceiver(mediaIntent); 5081 if (topOfStackWillChange) { 5082 // current RC client will change, assume every type of info needs to be queried 5083 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 5084 } 5085 } 5086 } 5087 } 5088 5089 /** 5090 * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) 5091 * precondition: c != null 5092 */ 5093 public void registerMediaButtonEventReceiverForCalls(ComponentName c) { 5094 if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 5095 != PackageManager.PERMISSION_GRANTED) { 5096 Log.e(TAG, "Invalid permissions to register media button receiver for calls"); 5097 return; 5098 } 5099 synchronized(mRCStack) { 5100 mMediaReceiverForCalls = c; 5101 } 5102 } 5103 5104 /** 5105 * see AudioManager.unregisterMediaButtonEventReceiverForCalls() 5106 */ 5107 public void unregisterMediaButtonEventReceiverForCalls() { 5108 if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 5109 != PackageManager.PERMISSION_GRANTED) { 5110 Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); 5111 return; 5112 } 5113 synchronized(mRCStack) { 5114 mMediaReceiverForCalls = null; 5115 } 5116 } 5117 5118 /** 5119 * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) 5120 * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient 5121 * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient 5122 * without modifying the RC stack, but while still causing the display to refresh (will 5123 * become blank as a result of this) 5124 */ 5125 public int registerRemoteControlClient(PendingIntent mediaIntent, 5126 IRemoteControlClient rcClient, String callingPackageName) { 5127 if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); 5128 int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 5129 synchronized(mAudioFocusLock) { 5130 synchronized(mRCStack) { 5131 // store the new display information 5132 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5133 while(stackIterator.hasNext()) { 5134 RemoteControlStackEntry rcse = stackIterator.next(); 5135 if(rcse.mMediaIntent.equals(mediaIntent)) { 5136 // already had a remote control client? 5137 if (rcse.mRcClientDeathHandler != null) { 5138 // stop monitoring the old client's death 5139 rcse.unlinkToRcClientDeath(); 5140 } 5141 // save the new remote control client 5142 rcse.mRcClient = rcClient; 5143 rcse.mCallingPackageName = callingPackageName; 5144 rcse.mCallingUid = Binder.getCallingUid(); 5145 if (rcClient == null) { 5146 // here rcse.mRcClientDeathHandler is null; 5147 rcse.resetPlaybackInfo(); 5148 break; 5149 } 5150 rccId = rcse.mRccId; 5151 5152 // there is a new (non-null) client: 5153 // 1/ give the new client the current display (if any) 5154 if (mRcDisplay != null) { 5155 try { 5156 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 5157 } catch (RemoteException e) { 5158 Log.e(TAG, "Error connecting remote control display to client: "+e); 5159 e.printStackTrace(); 5160 } 5161 } 5162 // 2/ monitor the new client's death 5163 IBinder b = rcse.mRcClient.asBinder(); 5164 RcClientDeathHandler rcdh = 5165 new RcClientDeathHandler(b, rcse.mMediaIntent); 5166 try { 5167 b.linkToDeath(rcdh, 0); 5168 } catch (RemoteException e) { 5169 // remote control client is DOA, disqualify it 5170 Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); 5171 rcse.mRcClient = null; 5172 } 5173 rcse.mRcClientDeathHandler = rcdh; 5174 break; 5175 } 5176 } 5177 // if the eventReceiver is at the top of the stack 5178 // then check for potential refresh of the remote controls 5179 if (isCurrentRcController(mediaIntent)) { 5180 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 5181 } 5182 } 5183 } 5184 return rccId; 5185 } 5186 5187 /** 5188 * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) 5189 * rcClient is guaranteed non-null 5190 */ 5191 public void unregisterRemoteControlClient(PendingIntent mediaIntent, 5192 IRemoteControlClient rcClient) { 5193 synchronized(mAudioFocusLock) { 5194 synchronized(mRCStack) { 5195 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5196 while(stackIterator.hasNext()) { 5197 RemoteControlStackEntry rcse = stackIterator.next(); 5198 if ((rcse.mMediaIntent.equals(mediaIntent)) 5199 && rcClient.equals(rcse.mRcClient)) { 5200 // we found the IRemoteControlClient to unregister 5201 // stop monitoring its death 5202 rcse.unlinkToRcClientDeath(); 5203 // reset the client-related fields 5204 rcse.mRcClient = null; 5205 rcse.mCallingPackageName = null; 5206 } 5207 } 5208 } 5209 } 5210 } 5211 5212 /** 5213 * The remote control displays. 5214 * Access synchronized on mRCStack 5215 * NOTE: Only one IRemoteControlDisplay supported in this implementation 5216 */ 5217 private IRemoteControlDisplay mRcDisplay; 5218 private RcDisplayDeathHandler mRcDisplayDeathHandler; 5219 private int mArtworkExpectedWidth = -1; 5220 private int mArtworkExpectedHeight = -1; 5221 /** 5222 * Inner class to monitor remote control display deaths, and unregister them from the list 5223 * of displays if necessary. 5224 */ 5225 private class RcDisplayDeathHandler implements IBinder.DeathRecipient { 5226 private IBinder mCb; // To be notified of client's death 5227 5228 public RcDisplayDeathHandler(IBinder b) { 5229 if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b); 5230 mCb = b; 5231 } 5232 5233 public void binderDied() { 5234 synchronized(mRCStack) { 5235 Log.w(TAG, "RemoteControl: display died"); 5236 mRcDisplay = null; 5237 } 5238 } 5239 5240 public void unlinkToRcDisplayDeath() { 5241 if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb); 5242 try { 5243 mCb.unlinkToDeath(this, 0); 5244 } catch (java.util.NoSuchElementException e) { 5245 // not much we can do here, the display was being unregistered anyway 5246 Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()"); 5247 e.printStackTrace(); 5248 } 5249 } 5250 5251 } 5252 5253 private void rcDisplay_stopDeathMonitor_syncRcStack() { 5254 if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null) 5255 // we had a display before, stop monitoring its death 5256 mRcDisplayDeathHandler.unlinkToRcDisplayDeath(); 5257 } 5258 } 5259 5260 private void rcDisplay_startDeathMonitor_syncRcStack() { 5261 if (mRcDisplay != null) { 5262 // new non-null display, monitor its death 5263 IBinder b = mRcDisplay.asBinder(); 5264 mRcDisplayDeathHandler = new RcDisplayDeathHandler(b); 5265 try { 5266 b.linkToDeath(mRcDisplayDeathHandler, 0); 5267 } catch (RemoteException e) { 5268 // remote control display is DOA, disqualify it 5269 Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b); 5270 mRcDisplay = null; 5271 } 5272 } 5273 } 5274 5275 /** 5276 * Register an IRemoteControlDisplay. 5277 * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient 5278 * at the top of the stack to update the new display with its information. 5279 * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. 5280 * @param rcd the IRemoteControlDisplay to register. No effect if null. 5281 */ 5282 public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { 5283 if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); 5284 synchronized(mAudioFocusLock) { 5285 synchronized(mRCStack) { 5286 if ((mRcDisplay == rcd) || (rcd == null)) { 5287 return; 5288 } 5289 // if we had a display before, stop monitoring its death 5290 rcDisplay_stopDeathMonitor_syncRcStack(); 5291 mRcDisplay = rcd; 5292 // new display, start monitoring its death 5293 rcDisplay_startDeathMonitor_syncRcStack(); 5294 5295 // let all the remote control clients there is a new display 5296 // no need to unplug the previous because we only support one display 5297 // and the clients don't track the death of the display 5298 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5299 while(stackIterator.hasNext()) { 5300 RemoteControlStackEntry rcse = stackIterator.next(); 5301 if(rcse.mRcClient != null) { 5302 try { 5303 rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 5304 } catch (RemoteException e) { 5305 Log.e(TAG, "Error connecting remote control display to client: " + e); 5306 e.printStackTrace(); 5307 } 5308 } 5309 } 5310 5311 // we have a new display, of which all the clients are now aware: have it be updated 5312 checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 5313 } 5314 } 5315 } 5316 5317 /** 5318 * Unregister an IRemoteControlDisplay. 5319 * Since only one IRemoteControlDisplay is supported, this has no effect if the one to 5320 * unregister is not the current one. 5321 * @param rcd the IRemoteControlDisplay to unregister. No effect if null. 5322 */ 5323 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 5324 if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); 5325 synchronized(mRCStack) { 5326 // only one display here, so you can only unregister the current display 5327 if ((rcd == null) || (rcd != mRcDisplay)) { 5328 if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); 5329 return; 5330 } 5331 // if we had a display before, stop monitoring its death 5332 rcDisplay_stopDeathMonitor_syncRcStack(); 5333 mRcDisplay = null; 5334 5335 // disconnect this remote control display from all the clients 5336 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5337 while(stackIterator.hasNext()) { 5338 RemoteControlStackEntry rcse = stackIterator.next(); 5339 if(rcse.mRcClient != null) { 5340 try { 5341 rcse.mRcClient.unplugRemoteControlDisplay(rcd); 5342 } catch (RemoteException e) { 5343 Log.e(TAG, "Error disconnecting remote control display to client: " + e); 5344 e.printStackTrace(); 5345 } 5346 } 5347 } 5348 } 5349 } 5350 5351 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 5352 synchronized(mRCStack) { 5353 // NOTE: Only one IRemoteControlDisplay supported in this implementation 5354 mArtworkExpectedWidth = w; 5355 mArtworkExpectedHeight = h; 5356 } 5357 } 5358 5359 public void setPlaybackInfoForRcc(int rccId, int what, int value) { 5360 sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, 5361 rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); 5362 } 5363 5364 // handler for MSG_RCC_NEW_PLAYBACK_INFO 5365 private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { 5366 if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + 5367 ", what=" + key + ",val=" + value + ")"); 5368 synchronized(mRCStack) { 5369 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5370 while(stackIterator.hasNext()) { 5371 RemoteControlStackEntry rcse = stackIterator.next(); 5372 if (rcse.mRccId == rccId) { 5373 switch (key) { 5374 case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: 5375 rcse.mPlaybackType = value; 5376 postReevaluateRemote(); 5377 break; 5378 case RemoteControlClient.PLAYBACKINFO_VOLUME: 5379 rcse.mPlaybackVolume = value; 5380 synchronized (mMainRemote) { 5381 if (rccId == mMainRemote.mRccId) { 5382 mMainRemote.mVolume = value; 5383 mVolumePanel.postHasNewRemotePlaybackInfo(); 5384 } 5385 } 5386 break; 5387 case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: 5388 rcse.mPlaybackVolumeMax = value; 5389 synchronized (mMainRemote) { 5390 if (rccId == mMainRemote.mRccId) { 5391 mMainRemote.mVolumeMax = value; 5392 mVolumePanel.postHasNewRemotePlaybackInfo(); 5393 } 5394 } 5395 break; 5396 case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: 5397 rcse.mPlaybackVolumeHandling = value; 5398 synchronized (mMainRemote) { 5399 if (rccId == mMainRemote.mRccId) { 5400 mMainRemote.mVolumeHandling = value; 5401 mVolumePanel.postHasNewRemotePlaybackInfo(); 5402 } 5403 } 5404 break; 5405 case RemoteControlClient.PLAYBACKINFO_USES_STREAM: 5406 rcse.mPlaybackStream = value; 5407 break; 5408 case RemoteControlClient.PLAYBACKINFO_PLAYSTATE: 5409 rcse.mPlaybackState = value; 5410 synchronized (mMainRemote) { 5411 if (rccId == mMainRemote.mRccId) { 5412 mMainRemoteIsActive = isPlaystateActive(value); 5413 postReevaluateRemote(); 5414 } 5415 } 5416 break; 5417 default: 5418 Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); 5419 break; 5420 } 5421 return; 5422 } 5423 } 5424 } 5425 } 5426 5427 public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 5428 sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, 5429 rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); 5430 } 5431 5432 // handler for MSG_RCC_NEW_VOLUME_OBS 5433 private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 5434 synchronized(mRCStack) { 5435 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5436 while(stackIterator.hasNext()) { 5437 RemoteControlStackEntry rcse = stackIterator.next(); 5438 if (rcse.mRccId == rccId) { 5439 rcse.mRemoteVolumeObs = rvo; 5440 break; 5441 } 5442 } 5443 } 5444 } 5445 5446 /** 5447 * Checks if a remote client is active on the supplied stream type. Update the remote stream 5448 * volume state if found and playing 5449 * @param streamType 5450 * @return false if no remote playing is currently playing 5451 */ 5452 private boolean checkUpdateRemoteStateIfActive(int streamType) { 5453 synchronized(mRCStack) { 5454 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5455 while(stackIterator.hasNext()) { 5456 RemoteControlStackEntry rcse = stackIterator.next(); 5457 if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) 5458 && isPlaystateActive(rcse.mPlaybackState) 5459 && (rcse.mPlaybackStream == streamType)) { 5460 if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType 5461 + ", vol =" + rcse.mPlaybackVolume); 5462 synchronized (mMainRemote) { 5463 mMainRemote.mRccId = rcse.mRccId; 5464 mMainRemote.mVolume = rcse.mPlaybackVolume; 5465 mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; 5466 mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; 5467 mMainRemoteIsActive = true; 5468 } 5469 return true; 5470 } 5471 } 5472 } 5473 synchronized (mMainRemote) { 5474 mMainRemoteIsActive = false; 5475 } 5476 return false; 5477 } 5478 5479 /** 5480 * Returns true if the given playback state is considered "active", i.e. it describes a state 5481 * where playback is happening, or about to 5482 * @param playState the playback state to evaluate 5483 * @return true if active, false otherwise (inactive or unknown) 5484 */ 5485 private static boolean isPlaystateActive(int playState) { 5486 switch (playState) { 5487 case RemoteControlClient.PLAYSTATE_PLAYING: 5488 case RemoteControlClient.PLAYSTATE_BUFFERING: 5489 case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: 5490 case RemoteControlClient.PLAYSTATE_REWINDING: 5491 case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: 5492 case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: 5493 return true; 5494 default: 5495 return false; 5496 } 5497 } 5498 5499 private void adjustRemoteVolume(int streamType, int direction, int flags) { 5500 int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 5501 boolean volFixed = false; 5502 synchronized (mMainRemote) { 5503 if (!mMainRemoteIsActive) { 5504 if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); 5505 return; 5506 } 5507 rccId = mMainRemote.mRccId; 5508 volFixed = (mMainRemote.mVolumeHandling == 5509 RemoteControlClient.PLAYBACK_VOLUME_FIXED); 5510 } 5511 // unlike "local" stream volumes, we can't compute the new volume based on the direction, 5512 // we can only notify the remote that volume needs to be updated, and we'll get an async' 5513 // update through setPlaybackInfoForRcc() 5514 if (!volFixed) { 5515 sendVolumeUpdateToRemote(rccId, direction); 5516 } 5517 5518 // fire up the UI 5519 mVolumePanel.postRemoteVolumeChanged(streamType, flags); 5520 } 5521 5522 private void sendVolumeUpdateToRemote(int rccId, int direction) { 5523 if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } 5524 if (direction == 0) { 5525 // only handling discrete events 5526 return; 5527 } 5528 IRemoteVolumeObserver rvo = null; 5529 synchronized (mRCStack) { 5530 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5531 while(stackIterator.hasNext()) { 5532 RemoteControlStackEntry rcse = stackIterator.next(); 5533 //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 5534 if (rcse.mRccId == rccId) { 5535 rvo = rcse.mRemoteVolumeObs; 5536 break; 5537 } 5538 } 5539 } 5540 if (rvo != null) { 5541 try { 5542 rvo.dispatchRemoteVolumeUpdate(direction, -1); 5543 } catch (RemoteException e) { 5544 Log.e(TAG, "Error dispatching relative volume update", e); 5545 } 5546 } 5547 } 5548 5549 public int getRemoteStreamMaxVolume() { 5550 synchronized (mMainRemote) { 5551 if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 5552 return 0; 5553 } 5554 return mMainRemote.mVolumeMax; 5555 } 5556 } 5557 5558 public int getRemoteStreamVolume() { 5559 synchronized (mMainRemote) { 5560 if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 5561 return 0; 5562 } 5563 return mMainRemote.mVolume; 5564 } 5565 } 5566 5567 public void setRemoteStreamVolume(int vol) { 5568 if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } 5569 int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 5570 synchronized (mMainRemote) { 5571 if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 5572 return; 5573 } 5574 rccId = mMainRemote.mRccId; 5575 } 5576 IRemoteVolumeObserver rvo = null; 5577 synchronized (mRCStack) { 5578 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5579 while(stackIterator.hasNext()) { 5580 RemoteControlStackEntry rcse = stackIterator.next(); 5581 if (rcse.mRccId == rccId) { 5582 //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 5583 rvo = rcse.mRemoteVolumeObs; 5584 break; 5585 } 5586 } 5587 } 5588 if (rvo != null) { 5589 try { 5590 rvo.dispatchRemoteVolumeUpdate(0, vol); 5591 } catch (RemoteException e) { 5592 Log.e(TAG, "Error dispatching absolute volume update", e); 5593 } 5594 } 5595 } 5596 5597 /** 5598 * Call to make AudioService reevaluate whether it's in a mode where remote players should 5599 * have their volume controlled. In this implementation this is only to reset whether 5600 * VolumePanel should display remote volumes 5601 */ 5602 private void postReevaluateRemote() { 5603 sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); 5604 } 5605 5606 private void onReevaluateRemote() { 5607 if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } 5608 // is there a registered RemoteControlClient that is handling remote playback 5609 boolean hasRemotePlayback = false; 5610 synchronized (mRCStack) { 5611 Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 5612 while(stackIterator.hasNext()) { 5613 RemoteControlStackEntry rcse = stackIterator.next(); 5614 if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 5615 hasRemotePlayback = true; 5616 break; 5617 } 5618 } 5619 } 5620 synchronized (mMainRemote) { 5621 if (mHasRemotePlayback != hasRemotePlayback) { 5622 mHasRemotePlayback = hasRemotePlayback; 5623 mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback); 5624 } 5625 } 5626 } 5627 5628 //========================================================================================== 5629 // Device orientation 5630 //========================================================================================== 5631 /** 5632 * Handles device configuration changes that may map to a change in the orientation. 5633 * This feature is optional, and is defined by the definition and value of the 5634 * "ro.audio.monitorOrientation" system property. 5635 */ 5636 private void handleConfigurationChanged(Context context) { 5637 try { 5638 // reading new orientation "safely" (i.e. under try catch) in case anything 5639 // goes wrong when obtaining resources and configuration 5640 Configuration config = context.getResources().getConfiguration(); 5641 if (mMonitorOrientation) { 5642 int newOrientation = config.orientation; 5643 if (newOrientation != mDeviceOrientation) { 5644 mDeviceOrientation = newOrientation; 5645 setOrientationForAudioSystem(); 5646 } 5647 } 5648 sendMsg(mAudioHandler, 5649 MSG_CONFIGURE_SAFE_MEDIA_VOLUME, 5650 SENDMSG_REPLACE, 5651 0, 5652 0, 5653 null, 5654 0); 5655 5656 boolean cameraSoundForced = mContext.getResources().getBoolean( 5657 com.android.internal.R.bool.config_camera_sound_forced); 5658 synchronized (mSettingsLock) { 5659 synchronized (mCameraSoundForced) { 5660 if (cameraSoundForced != mCameraSoundForced) { 5661 mCameraSoundForced = cameraSoundForced; 5662 5663 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; 5664 if (cameraSoundForced) { 5665 s.setAllIndexesToMax(); 5666 mRingerModeAffectedStreams &= 5667 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 5668 } else { 5669 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], 5670 false /*lastAudible*/); 5671 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], 5672 true /*lastAudible*/); 5673 mRingerModeAffectedStreams |= 5674 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 5675 } 5676 // take new state into account for streams muted by ringer mode 5677 setRingerModeInt(getRingerMode(), false); 5678 5679 sendMsg(mAudioHandler, 5680 MSG_SET_FORCE_USE, 5681 SENDMSG_QUEUE, 5682 AudioSystem.FOR_SYSTEM, 5683 cameraSoundForced ? 5684 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, 5685 null, 5686 0); 5687 5688 sendMsg(mAudioHandler, 5689 MSG_SET_ALL_VOLUMES, 5690 SENDMSG_QUEUE, 5691 0, 5692 0, 5693 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0); 5694 } 5695 } 5696 } 5697 } catch (Exception e) { 5698 Log.e(TAG, "Error retrieving device orientation: " + e); 5699 } 5700 } 5701 5702 private void setOrientationForAudioSystem() { 5703 switch (mDeviceOrientation) { 5704 case Configuration.ORIENTATION_LANDSCAPE: 5705 //Log.i(TAG, "orientation is landscape"); 5706 AudioSystem.setParameters("orientation=landscape"); 5707 break; 5708 case Configuration.ORIENTATION_PORTRAIT: 5709 //Log.i(TAG, "orientation is portrait"); 5710 AudioSystem.setParameters("orientation=portrait"); 5711 break; 5712 case Configuration.ORIENTATION_SQUARE: 5713 //Log.i(TAG, "orientation is square"); 5714 AudioSystem.setParameters("orientation=square"); 5715 break; 5716 case Configuration.ORIENTATION_UNDEFINED: 5717 //Log.i(TAG, "orientation is undefined"); 5718 AudioSystem.setParameters("orientation=undefined"); 5719 break; 5720 default: 5721 Log.e(TAG, "Unknown orientation"); 5722 } 5723 } 5724 5725 5726 // Handles request to override default use of A2DP for media. 5727 public void setBluetoothA2dpOnInt(boolean on) { 5728 synchronized (mBluetoothA2dpEnabledLock) { 5729 mBluetoothA2dpEnabled = on; 5730 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); 5731 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 5732 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 5733 } 5734 } 5735 5736 @Override 5737 public void setRingtonePlayer(IRingtonePlayer player) { 5738 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 5739 mRingtonePlayer = player; 5740 } 5741 5742 @Override 5743 public IRingtonePlayer getRingtonePlayer() { 5744 return mRingtonePlayer; 5745 } 5746 5747 @Override 5748 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 5749 synchronized (mCurAudioRoutes) { 5750 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes); 5751 mRoutesObservers.register(observer); 5752 return routes; 5753 } 5754 } 5755 5756 5757 //========================================================================================== 5758 // Safe media volume management. 5759 // MUSIC stream volume level is limited when headphones are connected according to safety 5760 // regulation. When the user attempts to raise the volume above the limit, a warning is 5761 // displayed and the user has to acknowlegde before the volume is actually changed. 5762 // The volume index corresponding to the limit is stored in config_safe_media_volume_index 5763 // property. Platforms with a different limit must set this property accordingly in their 5764 // overlay. 5765 //========================================================================================== 5766 5767 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones. 5768 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected 5769 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or 5770 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it 5771 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume() 5772 // (when user opts out). 5773 private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0; 5774 private final int SAFE_MEDIA_VOLUME_DISABLED = 1; 5775 private final int SAFE_MEDIA_VOLUME_INACTIVE = 2; 5776 private final int SAFE_MEDIA_VOLUME_ACTIVE = 3; 5777 private Integer mSafeMediaVolumeState; 5778 5779 private int mMcc = 0; 5780 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property 5781 private int mSafeMediaVolumeIndex; 5782 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced, 5783 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET | 5784 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 5785 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. 5786 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled 5787 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS. 5788 private int mMusicActiveMs; 5789 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours 5790 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval 5791 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed 5792 5793 private void setSafeMediaVolumeEnabled(boolean on) { 5794 synchronized (mSafeMediaVolumeState) { 5795 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) && 5796 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) { 5797 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) { 5798 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; 5799 enforceSafeMediaVolume(); 5800 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) { 5801 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE; 5802 mMusicActiveMs = 0; 5803 sendMsg(mAudioHandler, 5804 MSG_CHECK_MUSIC_ACTIVE, 5805 SENDMSG_REPLACE, 5806 0, 5807 0, 5808 null, 5809 MUSIC_ACTIVE_POLL_PERIOD_MS); 5810 } 5811 } 5812 } 5813 } 5814 5815 private void enforceSafeMediaVolume() { 5816 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; 5817 boolean lastAudible = (streamState.muteCount() != 0); 5818 int devices = mSafeMediaVolumeDevices; 5819 int i = 0; 5820 5821 while (devices != 0) { 5822 int device = 1 << i++; 5823 if ((device & devices) == 0) { 5824 continue; 5825 } 5826 int index = streamState.getIndex(device, lastAudible); 5827 if (index > mSafeMediaVolumeIndex) { 5828 if (lastAudible) { 5829 streamState.setLastAudibleIndex(mSafeMediaVolumeIndex, device); 5830 sendMsg(mAudioHandler, 5831 MSG_PERSIST_VOLUME, 5832 SENDMSG_QUEUE, 5833 PERSIST_LAST_AUDIBLE, 5834 device, 5835 streamState, 5836 PERSIST_DELAY); 5837 } else { 5838 streamState.setIndex(mSafeMediaVolumeIndex, device, true); 5839 sendMsg(mAudioHandler, 5840 MSG_SET_DEVICE_VOLUME, 5841 SENDMSG_QUEUE, 5842 device, 5843 0, 5844 streamState, 5845 0); 5846 } 5847 } 5848 devices &= ~device; 5849 } 5850 } 5851 5852 private boolean checkSafeMediaVolume(int streamType, int index, int device) { 5853 synchronized (mSafeMediaVolumeState) { 5854 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) && 5855 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && 5856 ((device & mSafeMediaVolumeDevices) != 0) && 5857 (index > mSafeMediaVolumeIndex)) { 5858 mVolumePanel.postDisplaySafeVolumeWarning(); 5859 return false; 5860 } 5861 return true; 5862 } 5863 } 5864 5865 public void disableSafeMediaVolume() { 5866 synchronized (mSafeMediaVolumeState) { 5867 setSafeMediaVolumeEnabled(false); 5868 } 5869 } 5870 5871 5872 //========================================================================================== 5873 // Camera shutter sound policy. 5874 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter 5875 // sound is forced (sound even if the device is in silent mode) or not. This option is false by 5876 // default and can be overridden by country specific overlay in values-mccXXX/config.xml. 5877 //========================================================================================== 5878 5879 // cached value of com.android.internal.R.bool.config_camera_sound_forced 5880 private Boolean mCameraSoundForced; 5881 5882 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound 5883 public boolean isCameraSoundForced() { 5884 synchronized (mCameraSoundForced) { 5885 return mCameraSoundForced; 5886 } 5887 } 5888 5889 private static final String[] RINGER_MODE_NAMES = new String[] { 5890 "SILENT", 5891 "VIBRATE", 5892 "NORMAL" 5893 }; 5894 5895 private void dumpRingerMode(PrintWriter pw) { 5896 pw.println("\nRinger mode: "); 5897 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]); 5898 pw.print("- ringer mode affected streams = 0x"); 5899 pw.println(Integer.toHexString(mRingerModeAffectedStreams)); 5900 pw.print("- ringer mode muted streams = 0x"); 5901 pw.println(Integer.toHexString(mRingerModeMutedStreams)); 5902 } 5903 5904 @Override 5905 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5906 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 5907 5908 dumpFocusStack(pw); 5909 dumpRCStack(pw); 5910 dumpRCCStack(pw); 5911 dumpStreamStates(pw); 5912 dumpRingerMode(pw); 5913 pw.println("\nAudio routes:"); 5914 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); 5915 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); 5916 } 5917} 5918