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