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