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