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