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