AudioService.java revision 2380566debfc57eb1cc07db1306ccee23b84ddd4
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.ActivityManager; 26import android.app.ActivityManagerNative; 27import android.app.AppOpsManager; 28import android.app.KeyguardManager; 29import android.app.PendingIntent; 30import android.app.PendingIntent.CanceledException; 31import android.bluetooth.BluetoothA2dp; 32import android.bluetooth.BluetoothAdapter; 33import android.bluetooth.BluetoothClass; 34import android.bluetooth.BluetoothDevice; 35import android.bluetooth.BluetoothHeadset; 36import android.bluetooth.BluetoothProfile; 37import android.content.ActivityNotFoundException; 38import android.content.BroadcastReceiver; 39import android.content.ComponentName; 40import android.content.ContentResolver; 41import android.content.Context; 42import android.content.Intent; 43import android.content.IntentFilter; 44import android.content.pm.PackageManager; 45import android.content.res.Configuration; 46import android.content.res.Resources; 47import android.content.res.XmlResourceParser; 48import android.database.ContentObserver; 49import android.media.MediaPlayer.OnCompletionListener; 50import android.media.MediaPlayer.OnErrorListener; 51import android.os.Binder; 52import android.os.Build; 53import android.os.Bundle; 54import android.os.Environment; 55import android.os.Handler; 56import android.os.IBinder; 57import android.os.Looper; 58import android.os.Message; 59import android.os.PowerManager; 60import android.os.RemoteCallbackList; 61import android.os.RemoteException; 62import android.os.ServiceManager; 63import android.os.SystemProperties; 64import android.os.UserHandle; 65import android.os.Vibrator; 66import android.provider.Settings; 67import android.provider.Settings.System; 68import android.speech.RecognizerIntent; 69import android.telephony.PhoneStateListener; 70import android.telephony.TelephonyManager; 71import android.text.TextUtils; 72import android.util.Log; 73import android.view.KeyEvent; 74import android.view.Surface; 75import android.view.VolumePanel; 76import android.view.WindowManager; 77 78import com.android.internal.telephony.ITelephony; 79import com.android.internal.util.XmlUtils; 80 81import org.xmlpull.v1.XmlPullParserException; 82 83import java.io.FileDescriptor; 84import java.io.IOException; 85import java.io.PrintWriter; 86import java.lang.reflect.Field; 87import java.util.ArrayList; 88import java.util.concurrent.ConcurrentHashMap; 89import java.util.HashMap; 90import java.util.Iterator; 91import java.util.List; 92import java.util.Map; 93import java.util.NoSuchElementException; 94import java.util.Set; 95import java.util.Stack; 96 97/** 98 * The implementation of the volume manager service. 99 * <p> 100 * This implementation focuses on delivering a responsive UI. Most methods are 101 * asynchronous to external calls. For example, the task of setting a volume 102 * will update our internal state, but in a separate thread will set the system 103 * volume and later persist to the database. Similarly, setting the ringer mode 104 * will update the state and broadcast a change and in a separate thread later 105 * persist the ringer mode. 106 * 107 * @hide 108 */ 109public class AudioService extends IAudioService.Stub { 110 111 private static final String TAG = "AudioService"; 112 113 /** Debug remote control client/display feature */ 114 protected static final boolean DEBUG_RC = false; 115 /** Debug volumes */ 116 protected static final boolean DEBUG_VOL = false; 117 118 /** How long to delay before persisting a change in volume/ringer mode. */ 119 private static final int PERSIST_DELAY = 500; 120 121 private final Context mContext; 122 private final ContentResolver mContentResolver; 123 private final AppOpsManager mAppOps; 124 private final boolean mVoiceCapable; 125 126 /** The UI */ 127 private VolumePanel mVolumePanel; 128 129 // sendMsg() flags 130 /** If the msg is already queued, replace it with this one. */ 131 private static final int SENDMSG_REPLACE = 0; 132 /** If the msg is already queued, ignore this one and leave the old. */ 133 private static final int SENDMSG_NOOP = 1; 134 /** If the msg is already queued, queue this one and leave the old. */ 135 private static final int SENDMSG_QUEUE = 2; 136 137 // AudioHandler messages 138 private static final int MSG_SET_DEVICE_VOLUME = 0; 139 private static final int MSG_PERSIST_VOLUME = 1; 140 private static final int MSG_PERSIST_MASTER_VOLUME = 2; 141 private static final int MSG_PERSIST_RINGER_MODE = 3; 142 private static final int MSG_MEDIA_SERVER_DIED = 4; 143 private static final int MSG_MEDIA_SERVER_STARTED = 5; 144 private static final int MSG_PLAY_SOUND_EFFECT = 6; 145 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7; 146 private static final int MSG_LOAD_SOUND_EFFECTS = 8; 147 private static final int MSG_SET_FORCE_USE = 9; 148 private static final int MSG_BT_HEADSET_CNCT_FAILED = 10; 149 private static final int MSG_SET_ALL_VOLUMES = 11; 150 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 12; 151 private static final int MSG_REPORT_NEW_ROUTES = 13; 152 private static final int MSG_SET_FORCE_BT_A2DP_USE = 14; 153 private static final int MSG_SET_RSX_CONNECTION_STATE = 15; // change remote submix connection 154 private static final int MSG_CHECK_MUSIC_ACTIVE = 16; 155 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 17; 156 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 18; 157 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 19; 158 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 20; 159 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 21; 160 private static final int MSG_UNLOAD_SOUND_EFFECTS = 22; 161 // start of messages handled under wakelock 162 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), 163 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) 164 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100; 165 private static final int MSG_SET_A2DP_CONNECTION_STATE = 101; 166 // end of messages handled under wakelock 167 168 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 169 // Timeout for connection to bluetooth headset service 170 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 171 172 /** @see AudioSystemThread */ 173 private AudioSystemThread mAudioSystemThread; 174 /** @see AudioHandler */ 175 private AudioHandler mAudioHandler; 176 /** @see VolumeStreamState */ 177 private VolumeStreamState[] mStreamStates; 178 private SettingsObserver mSettingsObserver; 179 180 private int mMode = AudioSystem.MODE_NORMAL; 181 // protects mRingerMode 182 private final Object mSettingsLock = new Object(); 183 184 private boolean mMediaServerOk; 185 186 private SoundPool mSoundPool; 187 private final Object mSoundEffectsLock = new Object(); 188 private static final int NUM_SOUNDPOOL_CHANNELS = 4; 189 190 // Internally master volume is a float in the 0.0 - 1.0 range, 191 // but to support integer based AudioManager API we translate it to 0 - 100 192 private static final int MAX_MASTER_VOLUME = 100; 193 194 // Maximum volume adjust steps allowed in a single batch call. 195 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 196 197 /* Sound effect file names */ 198 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 199 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>(); 200 201 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 202 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 203 * uses soundpool (second column) */ 204 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2]; 205 206 /** @hide Maximum volume index values for audio streams */ 207 private static final int[] MAX_STREAM_VOLUME = new int[] { 208 5, // STREAM_VOICE_CALL 209 7, // STREAM_SYSTEM 210 7, // STREAM_RING 211 15, // STREAM_MUSIC 212 7, // STREAM_ALARM 213 7, // STREAM_NOTIFICATION 214 15, // STREAM_BLUETOOTH_SCO 215 7, // STREAM_SYSTEM_ENFORCED 216 15, // STREAM_DTMF 217 15 // STREAM_TTS 218 }; 219 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 220 * of another stream: This avoids multiplying the volume settings for hidden 221 * stream types that follow other stream behavior for volume settings 222 * NOTE: do not create loops in aliases! 223 * Some streams alias to different streams according to device category (phone or tablet) or 224 * use case (in call s off call...).See updateStreamVolumeAlias() for more details 225 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 226 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 227 private final int[] STREAM_VOLUME_ALIAS = new int[] { 228 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 229 AudioSystem.STREAM_RING, // STREAM_SYSTEM 230 AudioSystem.STREAM_RING, // STREAM_RING 231 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 232 AudioSystem.STREAM_ALARM, // STREAM_ALARM 233 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 234 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 235 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 236 AudioSystem.STREAM_RING, // STREAM_DTMF 237 AudioSystem.STREAM_MUSIC // STREAM_TTS 238 }; 239 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 240 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 241 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 242 AudioSystem.STREAM_RING, // STREAM_RING 243 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 244 AudioSystem.STREAM_ALARM, // STREAM_ALARM 245 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 246 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 247 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 248 AudioSystem.STREAM_MUSIC, // STREAM_DTMF 249 AudioSystem.STREAM_MUSIC // STREAM_TTS 250 }; 251 private int[] mStreamVolumeAlias; 252 253 /** 254 * Map AudioSystem.STREAM_* constants to app ops. This should be used 255 * after mapping through mStreamVolumeAlias. 256 */ 257 private static final int[] STEAM_VOLUME_OPS = new int[] { 258 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL 259 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM 260 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING 261 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC 262 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM 263 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION 264 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO 265 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED 266 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF 267 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS 268 }; 269 270 private final boolean mUseFixedVolume; 271 272 // stream names used by dumpStreamStates() 273 private final String[] STREAM_NAMES = new String[] { 274 "STREAM_VOICE_CALL", 275 "STREAM_SYSTEM", 276 "STREAM_RING", 277 "STREAM_MUSIC", 278 "STREAM_ALARM", 279 "STREAM_NOTIFICATION", 280 "STREAM_BLUETOOTH_SCO", 281 "STREAM_SYSTEM_ENFORCED", 282 "STREAM_DTMF", 283 "STREAM_TTS" 284 }; 285 286 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 287 public void onError(int error) { 288 switch (error) { 289 case AudioSystem.AUDIO_STATUS_SERVER_DIED: 290 if (mMediaServerOk) { 291 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 292 null, 1500); 293 mMediaServerOk = false; 294 } 295 break; 296 case AudioSystem.AUDIO_STATUS_OK: 297 if (!mMediaServerOk) { 298 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 299 null, 0); 300 mMediaServerOk = true; 301 } 302 break; 303 default: 304 break; 305 } 306 } 307 }; 308 309 /** 310 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 311 * {@link AudioManager#RINGER_MODE_SILENT}, or 312 * {@link AudioManager#RINGER_MODE_VIBRATE}. 313 */ 314 // protected by mSettingsLock 315 private int mRingerMode; 316 317 /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 318 private int mRingerModeAffectedStreams; 319 320 // Streams currently muted by ringer mode 321 private int mRingerModeMutedStreams; 322 323 /** @see System#MUTE_STREAMS_AFFECTED */ 324 private int mMuteAffectedStreams; 325 326 /** 327 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. 328 * mVibrateSetting is just maintained during deprecation period but vibration policy is 329 * now only controlled by mHasVibrator and mRingerMode 330 */ 331 private int mVibrateSetting; 332 333 // Is there a vibrator 334 private final boolean mHasVibrator; 335 336 // Broadcast receiver for device connections intent broadcasts 337 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 338 339 // Devices currently connected 340 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 341 342 // Forced device usage for communications 343 private int mForcedUseForComm; 344 345 // True if we have master volume support 346 private final boolean mUseMasterVolume; 347 348 private final int[] mMasterVolumeRamp; 349 350 // List of binder death handlers for setMode() client processes. 351 // The last process to have called setMode() is at the top of the list. 352 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 353 354 // List of clients having issued a SCO start request 355 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 356 357 // BluetoothHeadset API to control SCO connection 358 private BluetoothHeadset mBluetoothHeadset; 359 360 // Bluetooth headset device 361 private BluetoothDevice mBluetoothHeadsetDevice; 362 363 // Indicate if SCO audio connection is currently active and if the initiator is 364 // audio service (internal) or bluetooth headset (external) 365 private int mScoAudioState; 366 // SCO audio state is not active 367 private static final int SCO_STATE_INACTIVE = 0; 368 // SCO audio activation request waiting for headset service to connect 369 private static final int SCO_STATE_ACTIVATE_REQ = 1; 370 // SCO audio state is active or starting due to a request from AudioManager API 371 private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 372 // SCO audio deactivation request waiting for headset service to connect 373 private static final int SCO_STATE_DEACTIVATE_REQ = 5; 374 375 // SCO audio state is active due to an action in BT handsfree (either voice recognition or 376 // in call audio) 377 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 378 // Deactivation request for all SCO connections (initiated by audio mode change) 379 // waiting for headset service to connect 380 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 381 382 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request 383 // originated from an app targeting an API version before JB MR2 and raw audio after that. 384 private int mScoAudioMode; 385 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall()) 386 private static final int SCO_MODE_VIRTUAL_CALL = 0; 387 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio()) 388 private static final int SCO_MODE_RAW = 1; 389 390 // Current connection state indicated by bluetooth headset 391 private int mScoConnectionState; 392 393 // true if boot sequence has been completed 394 private boolean mBootCompleted; 395 // listener for SoundPool sample load completion indication 396 private SoundPoolCallback mSoundPoolCallBack; 397 // thread for SoundPool listener 398 private SoundPoolListenerThread mSoundPoolListenerThread; 399 // message looper for SoundPool listener 400 private Looper mSoundPoolLooper = null; 401 // volume applied to sound played with playSoundEffect() 402 private static int sSoundEffectVolumeDb; 403 // getActiveStreamType() will return: 404 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped 405 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt 406 // stopped 407 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000; 408 // previous volume adjustment direction received by checkForRingerModeChange() 409 private int mPrevVolDirection = AudioManager.ADJUST_SAME; 410 // Keyguard manager proxy 411 private KeyguardManager mKeyguardManager; 412 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 413 // is controlled by Vol keys. 414 private int mVolumeControlStream = -1; 415 private final Object mForceControlStreamLock = new Object(); 416 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 417 // server process so in theory it is not necessary to monitor the client death. 418 // However it is good to be ready for future evolutions. 419 private ForceControlStreamClient mForceControlStreamClient = null; 420 // Used to play ringtones outside system_server 421 private volatile IRingtonePlayer mRingtonePlayer; 422 423 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 424 private int mDeviceRotation = Surface.ROTATION_0; 425 426 // Request to override default use of A2DP for media. 427 private boolean mBluetoothA2dpEnabled; 428 private final Object mBluetoothA2dpEnabledLock = new Object(); 429 430 // Monitoring of audio routes. Protected by mCurAudioRoutes. 431 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); 432 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers 433 = new RemoteCallbackList<IAudioRoutesObserver>(); 434 435 /** 436 * A fake stream type to match the notion of remote media playback 437 */ 438 public final static int STREAM_REMOTE_MUSIC = -200; 439 440 // Devices for which the volume is fixed and VolumePanel slider should be disabled 441 final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL | 442 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | 443 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | 444 AudioSystem.DEVICE_OUT_ALL_USB; 445 446 // TODO merge orientation and rotation 447 private final boolean mMonitorOrientation; 448 private final boolean mMonitorRotation; 449 450 private boolean mDockAudioMediaEnabled = true; 451 452 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 453 454 // Used when safe volume warning message display is requested by setStreamVolume(). In this 455 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand 456 // and used later when/if disableSafeMediaVolume() is called. 457 private StreamVolumeCommand mPendingVolumeCommand; 458 459 private PowerManager.WakeLock mAudioEventWakeLock; 460 461 private final MediaFocusControl mMediaFocusControl; 462 463 /////////////////////////////////////////////////////////////////////////// 464 // Construction 465 /////////////////////////////////////////////////////////////////////////// 466 467 /** @hide */ 468 public AudioService(Context context) { 469 mContext = context; 470 mContentResolver = context.getContentResolver(); 471 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 472 mVoiceCapable = mContext.getResources().getBoolean( 473 com.android.internal.R.bool.config_voice_capable); 474 475 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 476 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent"); 477 478 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 479 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); 480 481 // Intialized volume 482 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 483 "ro.config.vc_call_vol_steps", 484 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 485 486 sSoundEffectVolumeDb = context.getResources().getInteger( 487 com.android.internal.R.integer.config_soundEffectVolumeDb); 488 489 mVolumePanel = new VolumePanel(context, this); 490 mForcedUseForComm = AudioSystem.FORCE_NONE; 491 492 createAudioSystemThread(); 493 494 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(), 495 mContext, /*VolumeController*/ mVolumePanel, this); 496 497 boolean cameraSoundForced = mContext.getResources().getBoolean( 498 com.android.internal.R.bool.config_camera_sound_forced); 499 mCameraSoundForced = new Boolean(cameraSoundForced); 500 sendMsg(mAudioHandler, 501 MSG_SET_FORCE_USE, 502 SENDMSG_QUEUE, 503 AudioSystem.FOR_SYSTEM, 504 cameraSoundForced ? 505 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, 506 null, 507 0); 508 509 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver, 510 Settings.Global.AUDIO_SAFE_VOLUME_STATE, 511 SAFE_MEDIA_VOLUME_NOT_CONFIGURED)); 512 // The default safe volume index read here will be replaced by the actual value when 513 // the mcc is read by onConfigureSafeVolume() 514 mSafeMediaVolumeIndex = mContext.getResources().getInteger( 515 com.android.internal.R.integer.config_safe_media_volume_index) * 10; 516 517 mUseFixedVolume = mContext.getResources().getBoolean( 518 com.android.internal.R.bool.config_useFixedVolume); 519 520 readPersistedSettings(); 521 mSettingsObserver = new SettingsObserver(); 522 updateStreamVolumeAlias(false /*updateVolumes*/); 523 createStreamStates(); 524 525 readAndSetLowRamDevice(); 526 mMediaServerOk = true; 527 528 // Call setRingerModeInt() to apply correct mute 529 // state on streams affected by ringer mode. 530 mRingerModeMutedStreams = 0; 531 setRingerModeInt(getRingerMode(), false); 532 533 AudioSystem.setErrorCallback(mAudioSystemCallback); 534 535 // Register for device connection intent broadcasts. 536 IntentFilter intentFilter = 537 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 538 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 539 intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 540 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 541 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 542 intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 543 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 544 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 545 intentFilter.addAction(Intent.ACTION_USER_SWITCHED); 546 547 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 548 // TODO merge orientation and rotation 549 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false); 550 if (mMonitorOrientation) { 551 Log.v(TAG, "monitoring device orientation"); 552 // initialize orientation in AudioSystem 553 setOrientationForAudioSystem(); 554 } 555 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false); 556 if (mMonitorRotation) { 557 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)) 558 .getDefaultDisplay().getRotation(); 559 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation); 560 // initialize rotation in AudioSystem 561 setRotationForAudioSystem(); 562 } 563 564 context.registerReceiver(mReceiver, intentFilter); 565 566 mUseMasterVolume = context.getResources().getBoolean( 567 com.android.internal.R.bool.config_useMasterVolume); 568 restoreMasterVolume(); 569 570 mMasterVolumeRamp = context.getResources().getIntArray( 571 com.android.internal.R.array.config_masterVolumeRamp); 572 573 } 574 575 private void createAudioSystemThread() { 576 mAudioSystemThread = new AudioSystemThread(); 577 mAudioSystemThread.start(); 578 waitForAudioHandlerCreation(); 579 } 580 581 /** Waits for the volume handler to be created by the other thread. */ 582 private void waitForAudioHandlerCreation() { 583 synchronized(this) { 584 while (mAudioHandler == null) { 585 try { 586 // Wait for mAudioHandler to be set by the other thread 587 wait(); 588 } catch (InterruptedException e) { 589 Log.e(TAG, "Interrupted while waiting on volume handler."); 590 } 591 } 592 } 593 } 594 595 private void checkAllAliasStreamVolumes() { 596 int numStreamTypes = AudioSystem.getNumStreamTypes(); 597 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 598 if (streamType != mStreamVolumeAlias[streamType]) { 599 mStreamStates[streamType]. 600 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]); 601 } 602 // apply stream volume 603 if (!mStreamStates[streamType].isMuted()) { 604 mStreamStates[streamType].applyAllVolumes(); 605 } 606 } 607 } 608 609 private void createStreamStates() { 610 int numStreamTypes = AudioSystem.getNumStreamTypes(); 611 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 612 613 for (int i = 0; i < numStreamTypes; i++) { 614 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 615 } 616 617 checkAllAliasStreamVolumes(); 618 } 619 620 private void dumpStreamStates(PrintWriter pw) { 621 pw.println("\nStream volumes (device: index)"); 622 int numStreamTypes = AudioSystem.getNumStreamTypes(); 623 for (int i = 0; i < numStreamTypes; i++) { 624 pw.println("- "+STREAM_NAMES[i]+":"); 625 mStreamStates[i].dump(pw); 626 pw.println(""); 627 } 628 pw.print("\n- mute affected streams = 0x"); 629 pw.println(Integer.toHexString(mMuteAffectedStreams)); 630 } 631 632 633 private void updateStreamVolumeAlias(boolean updateVolumes) { 634 int dtmfStreamAlias; 635 if (mVoiceCapable) { 636 mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 637 dtmfStreamAlias = AudioSystem.STREAM_RING; 638 } else { 639 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 640 dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 641 } 642 if (isInCommunication()) { 643 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 644 } 645 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 646 if (updateVolumes) { 647 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]); 648 sendMsg(mAudioHandler, 649 MSG_SET_ALL_VOLUMES, 650 SENDMSG_QUEUE, 651 0, 652 0, 653 mStreamStates[AudioSystem.STREAM_DTMF], 0); 654 } 655 } 656 657 private void readDockAudioSettings(ContentResolver cr) 658 { 659 mDockAudioMediaEnabled = Settings.Global.getInt( 660 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1; 661 662 if (mDockAudioMediaEnabled) { 663 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 664 } else { 665 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 666 } 667 668 sendMsg(mAudioHandler, 669 MSG_SET_FORCE_USE, 670 SENDMSG_QUEUE, 671 AudioSystem.FOR_DOCK, 672 mDockAudioMediaEnabled ? 673 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE, 674 null, 675 0); 676 } 677 678 private void readPersistedSettings() { 679 final ContentResolver cr = mContentResolver; 680 681 int ringerModeFromSettings = 682 Settings.Global.getInt( 683 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 684 int ringerMode = ringerModeFromSettings; 685 // sanity check in case the settings are restored from a device with incompatible 686 // ringer modes 687 if (!AudioManager.isValidRingerMode(ringerMode)) { 688 ringerMode = AudioManager.RINGER_MODE_NORMAL; 689 } 690 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 691 ringerMode = AudioManager.RINGER_MODE_SILENT; 692 } 693 if (ringerMode != ringerModeFromSettings) { 694 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode); 695 } 696 if (mUseFixedVolume) { 697 ringerMode = AudioManager.RINGER_MODE_NORMAL; 698 } 699 synchronized(mSettingsLock) { 700 mRingerMode = ringerMode; 701 702 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting 703 // are still needed while setVibrateSetting() and getVibrateSetting() are being 704 // deprecated. 705 mVibrateSetting = getValueForVibrateSetting(0, 706 AudioManager.VIBRATE_TYPE_NOTIFICATION, 707 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 708 : AudioManager.VIBRATE_SETTING_OFF); 709 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, 710 AudioManager.VIBRATE_TYPE_RINGER, 711 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 712 : AudioManager.VIBRATE_SETTING_OFF); 713 714 // make sure settings for ringer mode are consistent with device type: non voice capable 715 // devices (tablets) include media stream in silent mode whereas phones don't. 716 mRingerModeAffectedStreams = Settings.System.getIntForUser(cr, 717 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 718 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 719 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)), 720 UserHandle.USER_CURRENT); 721 722 // ringtone, notification and system streams are always affected by ringer mode 723 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)| 724 (1 << AudioSystem.STREAM_NOTIFICATION)| 725 (1 << AudioSystem.STREAM_SYSTEM); 726 727 if (mVoiceCapable) { 728 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 729 } else { 730 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 731 } 732 synchronized (mCameraSoundForced) { 733 if (mCameraSoundForced) { 734 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 735 } else { 736 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 737 } 738 } 739 740 Settings.System.putIntForUser(cr, 741 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 742 mRingerModeAffectedStreams, 743 UserHandle.USER_CURRENT); 744 745 readDockAudioSettings(cr); 746 } 747 748 mMuteAffectedStreams = System.getIntForUser(cr, 749 System.MUTE_STREAMS_AFFECTED, 750 ((1 << AudioSystem.STREAM_MUSIC)| 751 (1 << AudioSystem.STREAM_RING)| 752 (1 << AudioSystem.STREAM_SYSTEM)), 753 UserHandle.USER_CURRENT); 754 755 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE, 756 0, UserHandle.USER_CURRENT) == 1; 757 if (mUseFixedVolume) { 758 masterMute = false; 759 AudioSystem.setMasterVolume(1.0f); 760 } 761 AudioSystem.setMasterMute(masterMute); 762 broadcastMasterMuteStatus(masterMute); 763 764 // Each stream will read its own persisted settings 765 766 // Broadcast the sticky intent 767 broadcastRingerMode(ringerMode); 768 769 // Broadcast vibrate settings 770 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 771 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 772 773 // Restore the default media button receiver from the system settings 774 mMediaFocusControl.restoreMediaButtonReceiver(); 775 } 776 777 private int rescaleIndex(int index, int srcStream, int dstStream) { 778 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 779 } 780 781 /////////////////////////////////////////////////////////////////////////// 782 // IPC methods 783 /////////////////////////////////////////////////////////////////////////// 784 785 /** @see AudioManager#adjustVolume(int, int) */ 786 public void adjustVolume(int direction, int flags, String callingPackage) { 787 adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags, 788 callingPackage); 789 } 790 791 /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption 792 * on streamType: fixed to STREAM_MUSIC */ 793 public void adjustLocalOrRemoteStreamVolume(int streamType, int direction, 794 String callingPackage) { 795 if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")"); 796 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 797 mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); 798 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 799 adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage); 800 } 801 } 802 803 /** @see AudioManager#adjustVolume(int, int) */ 804 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, 805 String callingPackage) { 806 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType); 807 int streamType; 808 if (mVolumeControlStream != -1) { 809 streamType = mVolumeControlStream; 810 } else { 811 streamType = getActiveStreamType(suggestedStreamType); 812 } 813 814 // Play sounds on STREAM_RING only and if lock screen is not on. 815 if ((streamType != STREAM_REMOTE_MUSIC) && 816 (flags & AudioManager.FLAG_PLAY_SOUND) != 0 && 817 ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) 818 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { 819 flags &= ~AudioManager.FLAG_PLAY_SOUND; 820 } 821 822 if (streamType == STREAM_REMOTE_MUSIC) { 823 // don't play sounds for remote 824 flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME); 825 //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()"); 826 mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); 827 } else { 828 adjustStreamVolume(streamType, direction, flags, callingPackage); 829 } 830 } 831 832 /** @see AudioManager#adjustStreamVolume(int, int, int) */ 833 public void adjustStreamVolume(int streamType, int direction, int flags, 834 String callingPackage) { 835 if (mUseFixedVolume) { 836 return; 837 } 838 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); 839 840 ensureValidDirection(direction); 841 ensureValidStreamType(streamType); 842 843 // use stream type alias here so that streams with same alias have the same behavior, 844 // including with regard to silent mode control (e.g the use of STREAM_RING below and in 845 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) 846 int streamTypeAlias = mStreamVolumeAlias[streamType]; 847 VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 848 849 final int device = getDeviceForStream(streamTypeAlias); 850 851 int aliasIndex = streamState.getIndex(device); 852 boolean adjustVolume = true; 853 int step; 854 855 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(), 856 callingPackage) != AppOpsManager.MODE_ALLOWED) { 857 return; 858 } 859 860 // reset any pending volume command 861 synchronized (mSafeMediaVolumeState) { 862 mPendingVolumeCommand = null; 863 } 864 865 flags &= ~AudioManager.FLAG_FIXED_VOLUME; 866 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && 867 ((device & mFixedVolumeDevices) != 0)) { 868 flags |= AudioManager.FLAG_FIXED_VOLUME; 869 870 // Always toggle between max safe volume and 0 for fixed volume devices where safe 871 // volume is enforced, and max and 0 for the others. 872 // This is simulated by stepping by the full allowed volume range 873 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && 874 (device & mSafeMediaVolumeDevices) != 0) { 875 step = mSafeMediaVolumeIndex; 876 } else { 877 step = streamState.getMaxIndex(); 878 } 879 if (aliasIndex != 0) { 880 aliasIndex = step; 881 } 882 } else { 883 // convert one UI step (+/-1) into a number of internal units on the stream alias 884 step = rescaleIndex(10, streamType, streamTypeAlias); 885 } 886 887 // If either the client forces allowing ringer modes for this adjustment, 888 // or the stream type is one that is affected by ringer modes 889 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 890 (streamTypeAlias == getMasterStreamType())) { 891 int ringerMode = getRingerMode(); 892 // do not vibrate if already in vibrate mode 893 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 894 flags &= ~AudioManager.FLAG_VIBRATE; 895 } 896 // Check if the ringer mode changes with this volume adjustment. If 897 // it does, it will handle adjusting the volume, so we won't below 898 adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); 899 } 900 901 int oldIndex = mStreamStates[streamType].getIndex(device); 902 903 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) { 904 if ((direction == AudioManager.ADJUST_RAISE) && 905 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { 906 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex); 907 mVolumePanel.postDisplaySafeVolumeWarning(flags); 908 } else if (streamState.adjustIndex(direction * step, device)) { 909 // Post message to set system volume (it in turn will post a message 910 // to persist). Do not change volume if stream is muted. 911 sendMsg(mAudioHandler, 912 MSG_SET_DEVICE_VOLUME, 913 SENDMSG_QUEUE, 914 device, 915 0, 916 streamState, 917 0); 918 } 919 } 920 int index = mStreamStates[streamType].getIndex(device); 921 sendVolumeUpdate(streamType, oldIndex, index, flags); 922 } 923 924 /** @see AudioManager#adjustMasterVolume(int, int) */ 925 public void adjustMasterVolume(int steps, int flags, String callingPackage) { 926 if (mUseFixedVolume) { 927 return; 928 } 929 ensureValidSteps(steps); 930 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 931 int delta = 0; 932 int numSteps = Math.abs(steps); 933 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER; 934 for (int i = 0; i < numSteps; ++i) { 935 delta = findVolumeDelta(direction, volume); 936 volume += delta; 937 } 938 939 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps); 940 setMasterVolume(volume, flags, callingPackage); 941 } 942 943 // StreamVolumeCommand contains the information needed to defer the process of 944 // setStreamVolume() in case the user has to acknowledge the safe volume warning message. 945 class StreamVolumeCommand { 946 public final int mStreamType; 947 public final int mIndex; 948 public final int mFlags; 949 public final int mDevice; 950 951 StreamVolumeCommand(int streamType, int index, int flags, int device) { 952 mStreamType = streamType; 953 mIndex = index; 954 mFlags = flags; 955 mDevice = device; 956 } 957 }; 958 959 private void onSetStreamVolume(int streamType, int index, int flags, int device) { 960 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false); 961 // setting volume on master stream type also controls silent mode 962 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 963 (mStreamVolumeAlias[streamType] == getMasterStreamType())) { 964 int newRingerMode; 965 if (index == 0) { 966 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE 967 : AudioManager.RINGER_MODE_SILENT; 968 } else { 969 newRingerMode = AudioManager.RINGER_MODE_NORMAL; 970 } 971 setRingerMode(newRingerMode); 972 } 973 } 974 975 /** @see AudioManager#setStreamVolume(int, int, int) */ 976 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) { 977 if (mUseFixedVolume) { 978 return; 979 } 980 981 ensureValidStreamType(streamType); 982 int streamTypeAlias = mStreamVolumeAlias[streamType]; 983 VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 984 985 final int device = getDeviceForStream(streamType); 986 int oldIndex; 987 988 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(), 989 callingPackage) != AppOpsManager.MODE_ALLOWED) { 990 return; 991 } 992 993 synchronized (mSafeMediaVolumeState) { 994 // reset any pending volume command 995 mPendingVolumeCommand = null; 996 997 oldIndex = streamState.getIndex(device); 998 999 index = rescaleIndex(index * 10, streamType, streamTypeAlias); 1000 1001 flags &= ~AudioManager.FLAG_FIXED_VOLUME; 1002 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && 1003 ((device & mFixedVolumeDevices) != 0)) { 1004 flags |= AudioManager.FLAG_FIXED_VOLUME; 1005 1006 // volume is either 0 or max allowed for fixed volume devices 1007 if (index != 0) { 1008 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && 1009 (device & mSafeMediaVolumeDevices) != 0) { 1010 index = mSafeMediaVolumeIndex; 1011 } else { 1012 index = streamState.getMaxIndex(); 1013 } 1014 } 1015 } 1016 1017 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) { 1018 mVolumePanel.postDisplaySafeVolumeWarning(flags); 1019 mPendingVolumeCommand = new StreamVolumeCommand( 1020 streamType, index, flags, device); 1021 } else { 1022 onSetStreamVolume(streamType, index, flags, device); 1023 index = mStreamStates[streamType].getIndex(device); 1024 } 1025 } 1026 sendVolumeUpdate(streamType, oldIndex, index, flags); 1027 } 1028 1029 /** @see AudioManager#forceVolumeControlStream(int) */ 1030 public void forceVolumeControlStream(int streamType, IBinder cb) { 1031 synchronized(mForceControlStreamLock) { 1032 mVolumeControlStream = streamType; 1033 if (mVolumeControlStream == -1) { 1034 if (mForceControlStreamClient != null) { 1035 mForceControlStreamClient.release(); 1036 mForceControlStreamClient = null; 1037 } 1038 } else { 1039 mForceControlStreamClient = new ForceControlStreamClient(cb); 1040 } 1041 } 1042 } 1043 1044 private class ForceControlStreamClient implements IBinder.DeathRecipient { 1045 private IBinder mCb; // To be notified of client's death 1046 1047 ForceControlStreamClient(IBinder cb) { 1048 if (cb != null) { 1049 try { 1050 cb.linkToDeath(this, 0); 1051 } catch (RemoteException e) { 1052 // Client has died! 1053 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death"); 1054 cb = null; 1055 } 1056 } 1057 mCb = cb; 1058 } 1059 1060 public void binderDied() { 1061 synchronized(mForceControlStreamLock) { 1062 Log.w(TAG, "SCO client died"); 1063 if (mForceControlStreamClient != this) { 1064 Log.w(TAG, "unregistered control stream client died"); 1065 } else { 1066 mForceControlStreamClient = null; 1067 mVolumeControlStream = -1; 1068 } 1069 } 1070 } 1071 1072 public void release() { 1073 if (mCb != null) { 1074 mCb.unlinkToDeath(this, 0); 1075 mCb = null; 1076 } 1077 } 1078 } 1079 1080 private int findVolumeDelta(int direction, int volume) { 1081 int delta = 0; 1082 if (direction == AudioManager.ADJUST_RAISE) { 1083 if (volume == MAX_MASTER_VOLUME) { 1084 return 0; 1085 } 1086 // This is the default value if we make it to the end 1087 delta = mMasterVolumeRamp[1]; 1088 // If we're raising the volume move down the ramp array until we 1089 // find the volume we're above and use that groups delta. 1090 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) { 1091 if (volume >= mMasterVolumeRamp[i - 1]) { 1092 delta = mMasterVolumeRamp[i]; 1093 break; 1094 } 1095 } 1096 } else if (direction == AudioManager.ADJUST_LOWER){ 1097 if (volume == 0) { 1098 return 0; 1099 } 1100 int length = mMasterVolumeRamp.length; 1101 // This is the default value if we make it to the end 1102 delta = -mMasterVolumeRamp[length - 1]; 1103 // If we're lowering the volume move up the ramp array until we 1104 // find the volume we're below and use the group below it's delta 1105 for (int i = 2; i < length; i += 2) { 1106 if (volume <= mMasterVolumeRamp[i]) { 1107 delta = -mMasterVolumeRamp[i - 1]; 1108 break; 1109 } 1110 } 1111 } 1112 return delta; 1113 } 1114 1115 private void sendBroadcastToAll(Intent intent) { 1116 final long ident = Binder.clearCallingIdentity(); 1117 try { 1118 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1119 } finally { 1120 Binder.restoreCallingIdentity(ident); 1121 } 1122 } 1123 1124 private void sendStickyBroadcastToAll(Intent intent) { 1125 final long ident = Binder.clearCallingIdentity(); 1126 try { 1127 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1128 } finally { 1129 Binder.restoreCallingIdentity(ident); 1130 } 1131 } 1132 1133 // UI update and Broadcast Intent 1134 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { 1135 if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { 1136 streamType = AudioSystem.STREAM_NOTIFICATION; 1137 } 1138 1139 mVolumePanel.postVolumeChanged(streamType, flags); 1140 1141 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) { 1142 oldIndex = (oldIndex + 5) / 10; 1143 index = (index + 5) / 10; 1144 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 1145 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 1146 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 1147 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 1148 sendBroadcastToAll(intent); 1149 } 1150 } 1151 1152 // UI update and Broadcast Intent 1153 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { 1154 mVolumePanel.postMasterVolumeChanged(flags); 1155 1156 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); 1157 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); 1158 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume); 1159 sendBroadcastToAll(intent); 1160 } 1161 1162 // UI update and Broadcast Intent 1163 private void sendMasterMuteUpdate(boolean muted, int flags) { 1164 mVolumePanel.postMasterMuteChanged(flags); 1165 broadcastMasterMuteStatus(muted); 1166 } 1167 1168 private void broadcastMasterMuteStatus(boolean muted) { 1169 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 1170 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 1171 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 1172 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1173 sendStickyBroadcastToAll(intent); 1174 } 1175 1176 /** 1177 * Sets the stream state's index, and posts a message to set system volume. 1178 * This will not call out to the UI. Assumes a valid stream type. 1179 * 1180 * @param streamType Type of the stream 1181 * @param index Desired volume index of the stream 1182 * @param device the device whose volume must be changed 1183 * @param force If true, set the volume even if the desired volume is same 1184 * as the current volume. 1185 */ 1186 private void setStreamVolumeInt(int streamType, 1187 int index, 1188 int device, 1189 boolean force) { 1190 VolumeStreamState streamState = mStreamStates[streamType]; 1191 1192 if (streamState.setIndex(index, device) || force) { 1193 // Post message to set system volume (it in turn will post a message 1194 // to persist). 1195 sendMsg(mAudioHandler, 1196 MSG_SET_DEVICE_VOLUME, 1197 SENDMSG_QUEUE, 1198 device, 1199 0, 1200 streamState, 1201 0); 1202 } 1203 } 1204 1205 /** @see AudioManager#setStreamSolo(int, boolean) */ 1206 public void setStreamSolo(int streamType, boolean state, IBinder cb) { 1207 if (mUseFixedVolume) { 1208 return; 1209 } 1210 1211 for (int stream = 0; stream < mStreamStates.length; stream++) { 1212 if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 1213 mStreamStates[stream].mute(cb, state); 1214 } 1215 } 1216 1217 /** @see AudioManager#setStreamMute(int, boolean) */ 1218 public void setStreamMute(int streamType, boolean state, IBinder cb) { 1219 if (mUseFixedVolume) { 1220 return; 1221 } 1222 1223 if (isStreamAffectedByMute(streamType)) { 1224 mStreamStates[streamType].mute(cb, state); 1225 } 1226 } 1227 1228 /** get stream mute state. */ 1229 public boolean isStreamMute(int streamType) { 1230 return mStreamStates[streamType].isMuted(); 1231 } 1232 1233 /** @see AudioManager#setMasterMute(boolean, int) */ 1234 public void setMasterMute(boolean state, int flags, IBinder cb) { 1235 if (mUseFixedVolume) { 1236 return; 1237 } 1238 1239 if (state != AudioSystem.getMasterMute()) { 1240 AudioSystem.setMasterMute(state); 1241 // Post a persist master volume msg 1242 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1 1243 : 0, 0, null, PERSIST_DELAY); 1244 sendMasterMuteUpdate(state, flags); 1245 } 1246 } 1247 1248 /** get master mute state. */ 1249 public boolean isMasterMute() { 1250 return AudioSystem.getMasterMute(); 1251 } 1252 1253 protected static int getMaxStreamVolume(int streamType) { 1254 return MAX_STREAM_VOLUME[streamType]; 1255 } 1256 1257 /** @see AudioManager#getStreamVolume(int) */ 1258 public int getStreamVolume(int streamType) { 1259 ensureValidStreamType(streamType); 1260 int device = getDeviceForStream(streamType); 1261 int index = mStreamStates[streamType].getIndex(device); 1262 1263 // by convention getStreamVolume() returns 0 when a stream is muted. 1264 if (mStreamStates[streamType].isMuted()) { 1265 index = 0; 1266 } 1267 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && 1268 (device & mFixedVolumeDevices) != 0) { 1269 index = mStreamStates[streamType].getMaxIndex(); 1270 } 1271 return (index + 5) / 10; 1272 } 1273 1274 public int getMasterVolume() { 1275 if (isMasterMute()) return 0; 1276 return getLastAudibleMasterVolume(); 1277 } 1278 1279 public void setMasterVolume(int volume, int flags, String callingPackage) { 1280 if (mUseFixedVolume) { 1281 return; 1282 } 1283 1284 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(), 1285 callingPackage) != AppOpsManager.MODE_ALLOWED) { 1286 return; 1287 } 1288 1289 if (volume < 0) { 1290 volume = 0; 1291 } else if (volume > MAX_MASTER_VOLUME) { 1292 volume = MAX_MASTER_VOLUME; 1293 } 1294 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags); 1295 } 1296 1297 private void doSetMasterVolume(float volume, int flags) { 1298 // don't allow changing master volume when muted 1299 if (!AudioSystem.getMasterMute()) { 1300 int oldVolume = getMasterVolume(); 1301 AudioSystem.setMasterVolume(volume); 1302 1303 int newVolume = getMasterVolume(); 1304 if (newVolume != oldVolume) { 1305 // Post a persist master volume msg 1306 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE, 1307 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY); 1308 } 1309 // Send the volume update regardless whether there was a change. 1310 sendMasterVolumeUpdate(flags, oldVolume, newVolume); 1311 } 1312 } 1313 1314 /** @see AudioManager#getStreamMaxVolume(int) */ 1315 public int getStreamMaxVolume(int streamType) { 1316 ensureValidStreamType(streamType); 1317 return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 1318 } 1319 1320 public int getMasterMaxVolume() { 1321 return MAX_MASTER_VOLUME; 1322 } 1323 1324 /** Get last audible volume before stream was muted. */ 1325 public int getLastAudibleStreamVolume(int streamType) { 1326 ensureValidStreamType(streamType); 1327 int device = getDeviceForStream(streamType); 1328 return (mStreamStates[streamType].getIndex(device) + 5) / 10; 1329 } 1330 1331 /** Get last audible master volume before it was muted. */ 1332 public int getLastAudibleMasterVolume() { 1333 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 1334 } 1335 1336 /** @see AudioManager#getMasterStreamType() */ 1337 public int getMasterStreamType() { 1338 if (mVoiceCapable) { 1339 return AudioSystem.STREAM_RING; 1340 } else { 1341 return AudioSystem.STREAM_MUSIC; 1342 } 1343 } 1344 1345 /** @see AudioManager#getRingerMode() */ 1346 public int getRingerMode() { 1347 synchronized(mSettingsLock) { 1348 return mRingerMode; 1349 } 1350 } 1351 1352 private void ensureValidRingerMode(int ringerMode) { 1353 if (!AudioManager.isValidRingerMode(ringerMode)) { 1354 throw new IllegalArgumentException("Bad ringer mode " + ringerMode); 1355 } 1356 } 1357 1358 /** @see AudioManager#setRingerMode(int) */ 1359 public void setRingerMode(int ringerMode) { 1360 if (mUseFixedVolume) { 1361 return; 1362 } 1363 1364 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 1365 ringerMode = AudioManager.RINGER_MODE_SILENT; 1366 } 1367 if (ringerMode != getRingerMode()) { 1368 setRingerModeInt(ringerMode, true); 1369 // Send sticky broadcast 1370 broadcastRingerMode(ringerMode); 1371 } 1372 } 1373 1374 private void setRingerModeInt(int ringerMode, boolean persist) { 1375 synchronized(mSettingsLock) { 1376 mRingerMode = ringerMode; 1377 } 1378 1379 // Mute stream if not previously muted by ringer mode and ringer mode 1380 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 1381 // Unmute stream if previously muted by ringer mode and ringer mode 1382 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 1383 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1384 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 1385 if (isStreamMutedByRingerMode(streamType)) { 1386 if (!isStreamAffectedByRingerMode(streamType) || 1387 ringerMode == AudioManager.RINGER_MODE_NORMAL) { 1388 // ring and notifications volume should never be 0 when not silenced 1389 // on voice capable devices 1390 if (mVoiceCapable && 1391 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { 1392 synchronized (mStreamStates[streamType]) { 1393 Set set = mStreamStates[streamType].mIndex.entrySet(); 1394 Iterator i = set.iterator(); 1395 while (i.hasNext()) { 1396 Map.Entry entry = (Map.Entry)i.next(); 1397 if ((Integer)entry.getValue() == 0) { 1398 entry.setValue(10); 1399 } 1400 } 1401 } 1402 } 1403 mStreamStates[streamType].mute(null, false); 1404 mRingerModeMutedStreams &= ~(1 << streamType); 1405 } 1406 } else { 1407 if (isStreamAffectedByRingerMode(streamType) && 1408 ringerMode != AudioManager.RINGER_MODE_NORMAL) { 1409 mStreamStates[streamType].mute(null, true); 1410 mRingerModeMutedStreams |= (1 << streamType); 1411 } 1412 } 1413 } 1414 1415 // Post a persist ringer mode msg 1416 if (persist) { 1417 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, 1418 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 1419 } 1420 } 1421 1422 private void restoreMasterVolume() { 1423 if (mUseFixedVolume) { 1424 AudioSystem.setMasterVolume(1.0f); 1425 return; 1426 } 1427 if (mUseMasterVolume) { 1428 float volume = Settings.System.getFloatForUser(mContentResolver, 1429 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT); 1430 if (volume >= 0.0f) { 1431 AudioSystem.setMasterVolume(volume); 1432 } 1433 } 1434 } 1435 1436 /** @see AudioManager#shouldVibrate(int) */ 1437 public boolean shouldVibrate(int vibrateType) { 1438 if (!mHasVibrator) return false; 1439 1440 switch (getVibrateSetting(vibrateType)) { 1441 1442 case AudioManager.VIBRATE_SETTING_ON: 1443 return getRingerMode() != AudioManager.RINGER_MODE_SILENT; 1444 1445 case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 1446 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; 1447 1448 case AudioManager.VIBRATE_SETTING_OFF: 1449 // return false, even for incoming calls 1450 return false; 1451 1452 default: 1453 return false; 1454 } 1455 } 1456 1457 /** @see AudioManager#getVibrateSetting(int) */ 1458 public int getVibrateSetting(int vibrateType) { 1459 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF; 1460 return (mVibrateSetting >> (vibrateType * 2)) & 3; 1461 } 1462 1463 /** @see AudioManager#setVibrateSetting(int, int) */ 1464 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 1465 1466 if (!mHasVibrator) return; 1467 1468 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 1469 1470 // Broadcast change 1471 broadcastVibrateSetting(vibrateType); 1472 1473 } 1474 1475 /** 1476 * @see #setVibrateSetting(int, int) 1477 */ 1478 public static int getValueForVibrateSetting(int existingValue, int vibrateType, 1479 int vibrateSetting) { 1480 1481 // First clear the existing setting. Each vibrate type has two bits in 1482 // the value. Note '3' is '11' in binary. 1483 existingValue &= ~(3 << (vibrateType * 2)); 1484 1485 // Set into the old value 1486 existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 1487 1488 return existingValue; 1489 } 1490 1491 private class SetModeDeathHandler implements IBinder.DeathRecipient { 1492 private IBinder mCb; // To be notified of client's death 1493 private int mPid; 1494 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 1495 1496 SetModeDeathHandler(IBinder cb, int pid) { 1497 mCb = cb; 1498 mPid = pid; 1499 } 1500 1501 public void binderDied() { 1502 int newModeOwnerPid = 0; 1503 synchronized(mSetModeDeathHandlers) { 1504 Log.w(TAG, "setMode() client died"); 1505 int index = mSetModeDeathHandlers.indexOf(this); 1506 if (index < 0) { 1507 Log.w(TAG, "unregistered setMode() client died"); 1508 } else { 1509 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid); 1510 } 1511 } 1512 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1513 // SCO connections not started by the application changing the mode 1514 if (newModeOwnerPid != 0) { 1515 final long ident = Binder.clearCallingIdentity(); 1516 disconnectBluetoothSco(newModeOwnerPid); 1517 Binder.restoreCallingIdentity(ident); 1518 } 1519 } 1520 1521 public int getPid() { 1522 return mPid; 1523 } 1524 1525 public void setMode(int mode) { 1526 mMode = mode; 1527 } 1528 1529 public int getMode() { 1530 return mMode; 1531 } 1532 1533 public IBinder getBinder() { 1534 return mCb; 1535 } 1536 } 1537 1538 /** @see AudioManager#setMode(int) */ 1539 public void setMode(int mode, IBinder cb) { 1540 if (!checkAudioSettingsPermission("setMode()")) { 1541 return; 1542 } 1543 1544 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { 1545 return; 1546 } 1547 1548 int newModeOwnerPid = 0; 1549 synchronized(mSetModeDeathHandlers) { 1550 if (mode == AudioSystem.MODE_CURRENT) { 1551 mode = mMode; 1552 } 1553 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid()); 1554 } 1555 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 1556 // SCO connections not started by the application changing the mode 1557 if (newModeOwnerPid != 0) { 1558 disconnectBluetoothSco(newModeOwnerPid); 1559 } 1560 } 1561 1562 // must be called synchronized on mSetModeDeathHandlers 1563 // setModeInt() returns a valid PID if the audio mode was successfully set to 1564 // any mode other than NORMAL. 1565 int setModeInt(int mode, IBinder cb, int pid) { 1566 int newModeOwnerPid = 0; 1567 if (cb == null) { 1568 Log.e(TAG, "setModeInt() called with null binder"); 1569 return newModeOwnerPid; 1570 } 1571 1572 SetModeDeathHandler hdlr = null; 1573 Iterator iter = mSetModeDeathHandlers.iterator(); 1574 while (iter.hasNext()) { 1575 SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 1576 if (h.getPid() == pid) { 1577 hdlr = h; 1578 // Remove from client list so that it is re-inserted at top of list 1579 iter.remove(); 1580 hdlr.getBinder().unlinkToDeath(hdlr, 0); 1581 break; 1582 } 1583 } 1584 int status = AudioSystem.AUDIO_STATUS_OK; 1585 do { 1586 if (mode == AudioSystem.MODE_NORMAL) { 1587 // get new mode from client at top the list if any 1588 if (!mSetModeDeathHandlers.isEmpty()) { 1589 hdlr = mSetModeDeathHandlers.get(0); 1590 cb = hdlr.getBinder(); 1591 mode = hdlr.getMode(); 1592 } 1593 } else { 1594 if (hdlr == null) { 1595 hdlr = new SetModeDeathHandler(cb, pid); 1596 } 1597 // Register for client death notification 1598 try { 1599 cb.linkToDeath(hdlr, 0); 1600 } catch (RemoteException e) { 1601 // Client has died! 1602 Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 1603 } 1604 1605 // Last client to call setMode() is always at top of client list 1606 // as required by SetModeDeathHandler.binderDied() 1607 mSetModeDeathHandlers.add(0, hdlr); 1608 hdlr.setMode(mode); 1609 } 1610 1611 if (mode != mMode) { 1612 status = AudioSystem.setPhoneState(mode); 1613 if (status == AudioSystem.AUDIO_STATUS_OK) { 1614 mMode = mode; 1615 } else { 1616 if (hdlr != null) { 1617 mSetModeDeathHandlers.remove(hdlr); 1618 cb.unlinkToDeath(hdlr, 0); 1619 } 1620 // force reading new top of mSetModeDeathHandlers stack 1621 mode = AudioSystem.MODE_NORMAL; 1622 } 1623 } else { 1624 status = AudioSystem.AUDIO_STATUS_OK; 1625 } 1626 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty()); 1627 1628 if (status == AudioSystem.AUDIO_STATUS_OK) { 1629 if (mode != AudioSystem.MODE_NORMAL) { 1630 if (mSetModeDeathHandlers.isEmpty()) { 1631 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack"); 1632 } else { 1633 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); 1634 } 1635 } 1636 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 1637 if (streamType == STREAM_REMOTE_MUSIC) { 1638 // here handle remote media playback the same way as local playback 1639 streamType = AudioManager.STREAM_MUSIC; 1640 } 1641 int device = getDeviceForStream(streamType); 1642 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device); 1643 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true); 1644 1645 updateStreamVolumeAlias(true /*updateVolumes*/); 1646 } 1647 return newModeOwnerPid; 1648 } 1649 1650 /** @see AudioManager#getMode() */ 1651 public int getMode() { 1652 return mMode; 1653 } 1654 1655 //========================================================================================== 1656 // Sound Effects 1657 //========================================================================================== 1658 1659 private static final String TAG_AUDIO_ASSETS = "audio_assets"; 1660 private static final String ATTR_VERSION = "version"; 1661 private static final String TAG_GROUP = "group"; 1662 private static final String ATTR_GROUP_NAME = "name"; 1663 private static final String TAG_ASSET = "asset"; 1664 private static final String ATTR_ASSET_ID = "id"; 1665 private static final String ATTR_ASSET_FILE = "file"; 1666 1667 private static final String ASSET_FILE_VERSION = "1.0"; 1668 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds"; 1669 1670 private static final int SOUND_EFECTS_LOAD_TIMEOUT_MS = 5000; 1671 1672 class LoadSoundEffectReply { 1673 public int mStatus = 1; 1674 }; 1675 1676 private void loadTouchSoundAssetDefaults() { 1677 SOUND_EFFECT_FILES.add("Effect_Tick.ogg"); 1678 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) { 1679 SOUND_EFFECT_FILES_MAP[i][0] = 0; 1680 SOUND_EFFECT_FILES_MAP[i][1] = -1; 1681 } 1682 } 1683 1684 private void loadTouchSoundAssets() { 1685 XmlResourceParser parser = null; 1686 1687 // only load assets once. 1688 if (!SOUND_EFFECT_FILES.isEmpty()) { 1689 return; 1690 } 1691 1692 loadTouchSoundAssetDefaults(); 1693 1694 try { 1695 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets); 1696 1697 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS); 1698 String version = parser.getAttributeValue(null, ATTR_VERSION); 1699 boolean inTouchSoundsGroup = false; 1700 1701 if (ASSET_FILE_VERSION.equals(version)) { 1702 while (true) { 1703 XmlUtils.nextElement(parser); 1704 String element = parser.getName(); 1705 if (element == null) { 1706 break; 1707 } 1708 if (element.equals(TAG_GROUP)) { 1709 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME); 1710 if (GROUP_TOUCH_SOUNDS.equals(name)) { 1711 inTouchSoundsGroup = true; 1712 break; 1713 } 1714 } 1715 } 1716 while (inTouchSoundsGroup) { 1717 XmlUtils.nextElement(parser); 1718 String element = parser.getName(); 1719 if (element == null) { 1720 break; 1721 } 1722 if (element.equals(TAG_ASSET)) { 1723 String id = parser.getAttributeValue(null, ATTR_ASSET_ID); 1724 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE); 1725 int fx; 1726 1727 try { 1728 Field field = AudioManager.class.getField(id); 1729 fx = field.getInt(null); 1730 } catch (Exception e) { 1731 Log.w(TAG, "Invalid touch sound ID: "+id); 1732 continue; 1733 } 1734 1735 int i = SOUND_EFFECT_FILES.indexOf(file); 1736 if (i == -1) { 1737 i = SOUND_EFFECT_FILES.size(); 1738 SOUND_EFFECT_FILES.add(file); 1739 } 1740 SOUND_EFFECT_FILES_MAP[fx][0] = i; 1741 } else { 1742 break; 1743 } 1744 } 1745 } 1746 } catch (Resources.NotFoundException e) { 1747 Log.w(TAG, "audio assets file not found", e); 1748 } catch (XmlPullParserException e) { 1749 Log.w(TAG, "XML parser exception reading touch sound assets", e); 1750 } catch (IOException e) { 1751 Log.w(TAG, "I/O exception reading touch sound assets", e); 1752 } finally { 1753 if (parser != null) { 1754 parser.close(); 1755 } 1756 } 1757 } 1758 1759 /** @see AudioManager#playSoundEffect(int) */ 1760 public void playSoundEffect(int effectType) { 1761 playSoundEffectVolume(effectType, -1.0f); 1762 } 1763 1764 /** @see AudioManager#playSoundEffect(int, float) */ 1765 public void playSoundEffectVolume(int effectType, float volume) { 1766 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE, 1767 effectType, (int) (volume * 1000), null, 0); 1768 } 1769 1770 /** 1771 * Loads samples into the soundpool. 1772 * This method must be called at first when sound effects are enabled 1773 */ 1774 public boolean loadSoundEffects() { 1775 int attempts = 3; 1776 LoadSoundEffectReply reply = new LoadSoundEffectReply(); 1777 1778 synchronized (reply) { 1779 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0); 1780 while ((reply.mStatus == 1) && (attempts-- > 0)) { 1781 try { 1782 reply.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS); 1783 } catch (InterruptedException e) { 1784 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded."); 1785 } 1786 } 1787 } 1788 return (reply.mStatus == 0); 1789 } 1790 1791 /** 1792 * Unloads samples from the sound pool. 1793 * This method can be called to free some memory when 1794 * sound effects are disabled. 1795 */ 1796 public void unloadSoundEffects() { 1797 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0); 1798 } 1799 1800 class SoundPoolListenerThread extends Thread { 1801 public SoundPoolListenerThread() { 1802 super("SoundPoolListenerThread"); 1803 } 1804 1805 @Override 1806 public void run() { 1807 1808 Looper.prepare(); 1809 mSoundPoolLooper = Looper.myLooper(); 1810 1811 synchronized (mSoundEffectsLock) { 1812 if (mSoundPool != null) { 1813 mSoundPoolCallBack = new SoundPoolCallback(); 1814 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack); 1815 } 1816 mSoundEffectsLock.notify(); 1817 } 1818 Looper.loop(); 1819 } 1820 } 1821 1822 private final class SoundPoolCallback implements 1823 android.media.SoundPool.OnLoadCompleteListener { 1824 1825 int mStatus = 1; // 1 means neither error nor last sample loaded yet 1826 List<Integer> mSamples = new ArrayList<Integer>(); 1827 1828 public int status() { 1829 return mStatus; 1830 } 1831 1832 public void setSamples(int[] samples) { 1833 for (int i = 0; i < samples.length; i++) { 1834 // do not wait ack for samples rejected upfront by SoundPool 1835 if (samples[i] > 0) { 1836 mSamples.add(samples[i]); 1837 } 1838 } 1839 } 1840 1841 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 1842 synchronized (mSoundEffectsLock) { 1843 int i = mSamples.indexOf(sampleId); 1844 if (i >= 0) { 1845 mSamples.remove(i); 1846 } 1847 if ((status != 0) || mSamples. isEmpty()) { 1848 mStatus = status; 1849 mSoundEffectsLock.notify(); 1850 } 1851 } 1852 } 1853 } 1854 1855 /** @see AudioManager#reloadAudioSettings() */ 1856 public void reloadAudioSettings() { 1857 readAudioSettings(false /*userSwitch*/); 1858 } 1859 1860 private void readAudioSettings(boolean userSwitch) { 1861 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 1862 readPersistedSettings(); 1863 1864 // restore volume settings 1865 int numStreamTypes = AudioSystem.getNumStreamTypes(); 1866 for (int streamType = 0; streamType < numStreamTypes; streamType++) { 1867 VolumeStreamState streamState = mStreamStates[streamType]; 1868 1869 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) { 1870 continue; 1871 } 1872 1873 synchronized (streamState) { 1874 streamState.readSettings(); 1875 1876 // unmute stream that was muted but is not affect by mute anymore 1877 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) && 1878 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) { 1879 int size = streamState.mDeathHandlers.size(); 1880 for (int i = 0; i < size; i++) { 1881 streamState.mDeathHandlers.get(i).mMuteCount = 1; 1882 streamState.mDeathHandlers.get(i).mute(false); 1883 } 1884 } 1885 } 1886 } 1887 1888 // apply new ringer mode before checking volume for alias streams so that streams 1889 // muted by ringer mode have the correct volume 1890 setRingerModeInt(getRingerMode(), false); 1891 1892 checkAllAliasStreamVolumes(); 1893 1894 synchronized (mSafeMediaVolumeState) { 1895 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) { 1896 enforceSafeMediaVolume(); 1897 } 1898 } 1899 } 1900 1901 /** @see AudioManager#setSpeakerphoneOn(boolean) */ 1902 public void setSpeakerphoneOn(boolean on){ 1903 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 1904 return; 1905 } 1906 mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; 1907 1908 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1909 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1910 } 1911 1912 /** @see AudioManager#isSpeakerphoneOn() */ 1913 public boolean isSpeakerphoneOn() { 1914 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER); 1915 } 1916 1917 /** @see AudioManager#setBluetoothScoOn(boolean) */ 1918 public void setBluetoothScoOn(boolean on){ 1919 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 1920 return; 1921 } 1922 mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 1923 1924 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1925 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1926 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1927 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); 1928 } 1929 1930 /** @see AudioManager#isBluetoothScoOn() */ 1931 public boolean isBluetoothScoOn() { 1932 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); 1933 } 1934 1935 /** @see AudioManager#setBluetoothA2dpOn(boolean) */ 1936 public void setBluetoothA2dpOn(boolean on) { 1937 synchronized (mBluetoothA2dpEnabledLock) { 1938 mBluetoothA2dpEnabled = on; 1939 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, 1940 AudioSystem.FOR_MEDIA, 1941 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 1942 null, 0); 1943 } 1944 } 1945 1946 /** @see AudioManager#isBluetoothA2dpOn() */ 1947 public boolean isBluetoothA2dpOn() { 1948 synchronized (mBluetoothA2dpEnabledLock) { 1949 return mBluetoothA2dpEnabled; 1950 } 1951 } 1952 1953 /** @see AudioManager#startBluetoothSco() */ 1954 public void startBluetoothSco(IBinder cb, int targetSdkVersion){ 1955 if (!checkAudioSettingsPermission("startBluetoothSco()") || 1956 !mBootCompleted) { 1957 return; 1958 } 1959 ScoClient client = getScoClient(cb, true); 1960 // The calling identity must be cleared before calling ScoClient.incCount(). 1961 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs 1962 // and this must be done on behalf of system server to make sure permissions are granted. 1963 // The caller identity must be cleared after getScoClient() because it is needed if a new 1964 // client is created. 1965 final long ident = Binder.clearCallingIdentity(); 1966 client.incCount(targetSdkVersion); 1967 Binder.restoreCallingIdentity(ident); 1968 } 1969 1970 /** @see AudioManager#stopBluetoothSco() */ 1971 public void stopBluetoothSco(IBinder cb){ 1972 if (!checkAudioSettingsPermission("stopBluetoothSco()") || 1973 !mBootCompleted) { 1974 return; 1975 } 1976 ScoClient client = getScoClient(cb, false); 1977 // The calling identity must be cleared before calling ScoClient.decCount(). 1978 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs 1979 // and this must be done on behalf of system server to make sure permissions are granted. 1980 final long ident = Binder.clearCallingIdentity(); 1981 if (client != null) { 1982 client.decCount(); 1983 } 1984 Binder.restoreCallingIdentity(ident); 1985 } 1986 1987 1988 private class ScoClient implements IBinder.DeathRecipient { 1989 private IBinder mCb; // To be notified of client's death 1990 private int mCreatorPid; 1991 private int mStartcount; // number of SCO connections started by this client 1992 1993 ScoClient(IBinder cb) { 1994 mCb = cb; 1995 mCreatorPid = Binder.getCallingPid(); 1996 mStartcount = 0; 1997 } 1998 1999 public void binderDied() { 2000 synchronized(mScoClients) { 2001 Log.w(TAG, "SCO client died"); 2002 int index = mScoClients.indexOf(this); 2003 if (index < 0) { 2004 Log.w(TAG, "unregistered SCO client died"); 2005 } else { 2006 clearCount(true); 2007 mScoClients.remove(this); 2008 } 2009 } 2010 } 2011 2012 public void incCount(int targetSdkVersion) { 2013 synchronized(mScoClients) { 2014 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion); 2015 if (mStartcount == 0) { 2016 try { 2017 mCb.linkToDeath(this, 0); 2018 } catch (RemoteException e) { 2019 // client has already died! 2020 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 2021 } 2022 } 2023 mStartcount++; 2024 } 2025 } 2026 2027 public void decCount() { 2028 synchronized(mScoClients) { 2029 if (mStartcount == 0) { 2030 Log.w(TAG, "ScoClient.decCount() already 0"); 2031 } else { 2032 mStartcount--; 2033 if (mStartcount == 0) { 2034 try { 2035 mCb.unlinkToDeath(this, 0); 2036 } catch (NoSuchElementException e) { 2037 Log.w(TAG, "decCount() going to 0 but not registered to binder"); 2038 } 2039 } 2040 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); 2041 } 2042 } 2043 } 2044 2045 public void clearCount(boolean stopSco) { 2046 synchronized(mScoClients) { 2047 if (mStartcount != 0) { 2048 try { 2049 mCb.unlinkToDeath(this, 0); 2050 } catch (NoSuchElementException e) { 2051 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder"); 2052 } 2053 } 2054 mStartcount = 0; 2055 if (stopSco) { 2056 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0); 2057 } 2058 } 2059 } 2060 2061 public int getCount() { 2062 return mStartcount; 2063 } 2064 2065 public IBinder getBinder() { 2066 return mCb; 2067 } 2068 2069 public int getPid() { 2070 return mCreatorPid; 2071 } 2072 2073 public int totalCount() { 2074 synchronized(mScoClients) { 2075 int count = 0; 2076 int size = mScoClients.size(); 2077 for (int i = 0; i < size; i++) { 2078 count += mScoClients.get(i).getCount(); 2079 } 2080 return count; 2081 } 2082 } 2083 2084 private void requestScoState(int state, int targetSdkVersion) { 2085 checkScoAudioState(); 2086 if (totalCount() == 0) { 2087 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 2088 // Make sure that the state transitions to CONNECTING even if we cannot initiate 2089 // the connection. 2090 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); 2091 // Accept SCO audio activation only in NORMAL audio mode or if the mode is 2092 // currently controlled by the same client process. 2093 synchronized(mSetModeDeathHandlers) { 2094 if ((mSetModeDeathHandlers.isEmpty() || 2095 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) && 2096 (mScoAudioState == SCO_STATE_INACTIVE || 2097 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 2098 if (mScoAudioState == SCO_STATE_INACTIVE) { 2099 mScoAudioMode = 2100 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ? 2101 SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW; 2102 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 2103 boolean status; 2104 if (mScoAudioMode == SCO_MODE_RAW) { 2105 status = mBluetoothHeadset.connectAudio(); 2106 } else { 2107 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 2108 mBluetoothHeadsetDevice); 2109 } 2110 if (status) { 2111 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 2112 } else { 2113 broadcastScoConnectionState( 2114 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 2115 } 2116 } else if (getBluetoothHeadset()) { 2117 mScoAudioState = SCO_STATE_ACTIVATE_REQ; 2118 } 2119 } else { 2120 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 2121 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); 2122 } 2123 } else { 2124 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 2125 } 2126 } 2127 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED && 2128 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 2129 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { 2130 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { 2131 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 2132 boolean status; 2133 if (mScoAudioMode == SCO_MODE_RAW) { 2134 status = mBluetoothHeadset.disconnectAudio(); 2135 } else { 2136 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 2137 mBluetoothHeadsetDevice); 2138 } 2139 if (!status) { 2140 mScoAudioState = SCO_STATE_INACTIVE; 2141 broadcastScoConnectionState( 2142 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 2143 } 2144 } else if (getBluetoothHeadset()) { 2145 mScoAudioState = SCO_STATE_DEACTIVATE_REQ; 2146 } 2147 } else { 2148 mScoAudioState = SCO_STATE_INACTIVE; 2149 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 2150 } 2151 } 2152 } 2153 } 2154 } 2155 2156 private void checkScoAudioState() { 2157 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null && 2158 mScoAudioState == SCO_STATE_INACTIVE && 2159 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) 2160 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 2161 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 2162 } 2163 } 2164 2165 private ScoClient getScoClient(IBinder cb, boolean create) { 2166 synchronized(mScoClients) { 2167 ScoClient client = null; 2168 int size = mScoClients.size(); 2169 for (int i = 0; i < size; i++) { 2170 client = mScoClients.get(i); 2171 if (client.getBinder() == cb) 2172 return client; 2173 } 2174 if (create) { 2175 client = new ScoClient(cb); 2176 mScoClients.add(client); 2177 } 2178 return client; 2179 } 2180 } 2181 2182 public void clearAllScoClients(int exceptPid, boolean stopSco) { 2183 synchronized(mScoClients) { 2184 ScoClient savedClient = null; 2185 int size = mScoClients.size(); 2186 for (int i = 0; i < size; i++) { 2187 ScoClient cl = mScoClients.get(i); 2188 if (cl.getPid() != exceptPid) { 2189 cl.clearCount(stopSco); 2190 } else { 2191 savedClient = cl; 2192 } 2193 } 2194 mScoClients.clear(); 2195 if (savedClient != null) { 2196 mScoClients.add(savedClient); 2197 } 2198 } 2199 } 2200 2201 private boolean getBluetoothHeadset() { 2202 boolean result = false; 2203 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 2204 if (adapter != null) { 2205 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 2206 BluetoothProfile.HEADSET); 2207 } 2208 // If we could not get a bluetooth headset proxy, send a failure message 2209 // without delay to reset the SCO audio state and clear SCO clients. 2210 // If we could get a proxy, send a delayed failure message that will reset our state 2211 // in case we don't receive onServiceConnected(). 2212 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 2213 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); 2214 return result; 2215 } 2216 2217 private void disconnectBluetoothSco(int exceptPid) { 2218 synchronized(mScoClients) { 2219 checkScoAudioState(); 2220 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL || 2221 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 2222 if (mBluetoothHeadsetDevice != null) { 2223 if (mBluetoothHeadset != null) { 2224 if (!mBluetoothHeadset.stopVoiceRecognition( 2225 mBluetoothHeadsetDevice)) { 2226 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 2227 SENDMSG_REPLACE, 0, 0, null, 0); 2228 } 2229 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && 2230 getBluetoothHeadset()) { 2231 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ; 2232 } 2233 } 2234 } else { 2235 clearAllScoClients(exceptPid, true); 2236 } 2237 } 2238 } 2239 2240 private void resetBluetoothSco() { 2241 synchronized(mScoClients) { 2242 clearAllScoClients(0, false); 2243 mScoAudioState = SCO_STATE_INACTIVE; 2244 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 2245 } 2246 } 2247 2248 private void broadcastScoConnectionState(int state) { 2249 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE, 2250 SENDMSG_QUEUE, state, 0, null, 0); 2251 } 2252 2253 private void onBroadcastScoConnectionState(int state) { 2254 if (state != mScoConnectionState) { 2255 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); 2256 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 2257 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, 2258 mScoConnectionState); 2259 sendStickyBroadcastToAll(newIntent); 2260 mScoConnectionState = state; 2261 } 2262 } 2263 2264 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 2265 new BluetoothProfile.ServiceListener() { 2266 public void onServiceConnected(int profile, BluetoothProfile proxy) { 2267 BluetoothDevice btDevice; 2268 List<BluetoothDevice> deviceList; 2269 switch(profile) { 2270 case BluetoothProfile.A2DP: 2271 BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 2272 deviceList = a2dp.getConnectedDevices(); 2273 if (deviceList.size() > 0) { 2274 btDevice = deviceList.get(0); 2275 synchronized (mConnectedDevices) { 2276 int state = a2dp.getConnectionState(btDevice); 2277 int delay = checkSendBecomingNoisyIntent( 2278 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2279 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 2280 queueMsgUnderWakeLock(mAudioHandler, 2281 MSG_SET_A2DP_CONNECTION_STATE, 2282 state, 2283 0, 2284 btDevice, 2285 delay); 2286 } 2287 } 2288 break; 2289 2290 case BluetoothProfile.HEADSET: 2291 synchronized (mScoClients) { 2292 // Discard timeout message 2293 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 2294 mBluetoothHeadset = (BluetoothHeadset) proxy; 2295 deviceList = mBluetoothHeadset.getConnectedDevices(); 2296 if (deviceList.size() > 0) { 2297 mBluetoothHeadsetDevice = deviceList.get(0); 2298 } else { 2299 mBluetoothHeadsetDevice = null; 2300 } 2301 // Refresh SCO audio state 2302 checkScoAudioState(); 2303 // Continue pending action if any 2304 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || 2305 mScoAudioState == SCO_STATE_DEACTIVATE_REQ || 2306 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 2307 boolean status = false; 2308 if (mBluetoothHeadsetDevice != null) { 2309 switch (mScoAudioState) { 2310 case SCO_STATE_ACTIVATE_REQ: 2311 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 2312 if (mScoAudioMode == SCO_MODE_RAW) { 2313 status = mBluetoothHeadset.connectAudio(); 2314 } else { 2315 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 2316 mBluetoothHeadsetDevice); 2317 } 2318 break; 2319 case SCO_STATE_DEACTIVATE_REQ: 2320 if (mScoAudioMode == SCO_MODE_RAW) { 2321 status = mBluetoothHeadset.disconnectAudio(); 2322 } else { 2323 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 2324 mBluetoothHeadsetDevice); 2325 } 2326 break; 2327 case SCO_STATE_DEACTIVATE_EXT_REQ: 2328 status = mBluetoothHeadset.stopVoiceRecognition( 2329 mBluetoothHeadsetDevice); 2330 } 2331 } 2332 if (!status) { 2333 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 2334 SENDMSG_REPLACE, 0, 0, null, 0); 2335 } 2336 } 2337 } 2338 break; 2339 2340 default: 2341 break; 2342 } 2343 } 2344 public void onServiceDisconnected(int profile) { 2345 switch(profile) { 2346 case BluetoothProfile.A2DP: 2347 synchronized (mConnectedDevices) { 2348 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { 2349 makeA2dpDeviceUnavailableNow( 2350 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); 2351 } 2352 } 2353 break; 2354 2355 case BluetoothProfile.HEADSET: 2356 synchronized (mScoClients) { 2357 mBluetoothHeadset = null; 2358 } 2359 break; 2360 2361 default: 2362 break; 2363 } 2364 } 2365 }; 2366 2367 /** see AudioManager.setRemoteSubmixOn(boolean on) */ 2368 public void setRemoteSubmixOn(boolean on, int address) { 2369 sendMsg(mAudioHandler, MSG_SET_RSX_CONNECTION_STATE, 2370 SENDMSG_REPLACE /* replace with QUEUE when multiple addresses are supported */, 2371 on ? 1 : 0 /*arg1*/, 2372 address /*arg2*/, 2373 null/*obj*/, 0/*delay*/); 2374 } 2375 2376 private void onSetRsxConnectionState(int available, int address) { 2377 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, 2378 available == 1 ? 2379 AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE, 2380 String.valueOf(address) /*device_address*/); 2381 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, 2382 available == 1 ? 2383 AudioSystem.DEVICE_STATE_AVAILABLE : AudioSystem.DEVICE_STATE_UNAVAILABLE, 2384 String.valueOf(address) /*device_address*/); 2385 } 2386 2387 private void onCheckMusicActive() { 2388 synchronized (mSafeMediaVolumeState) { 2389 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) { 2390 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC); 2391 2392 if ((device & mSafeMediaVolumeDevices) != 0) { 2393 sendMsg(mAudioHandler, 2394 MSG_CHECK_MUSIC_ACTIVE, 2395 SENDMSG_REPLACE, 2396 0, 2397 0, 2398 null, 2399 MUSIC_ACTIVE_POLL_PERIOD_MS); 2400 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device); 2401 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) && 2402 (index > mSafeMediaVolumeIndex)) { 2403 // Approximate cumulative active music time 2404 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS; 2405 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) { 2406 setSafeMediaVolumeEnabled(true); 2407 mMusicActiveMs = 0; 2408 } 2409 } 2410 } 2411 } 2412 } 2413 } 2414 2415 private void onConfigureSafeVolume(boolean force) { 2416 synchronized (mSafeMediaVolumeState) { 2417 int mcc = mContext.getResources().getConfiguration().mcc; 2418 if ((mMcc != mcc) || ((mMcc == 0) && force)) { 2419 mSafeMediaVolumeIndex = mContext.getResources().getInteger( 2420 com.android.internal.R.integer.config_safe_media_volume_index) * 10; 2421 boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean( 2422 com.android.internal.R.bool.config_safe_media_volume_enabled); 2423 2424 // The persisted state is either "disabled" or "active": this is the state applied 2425 // next time we boot and cannot be "inactive" 2426 int persistedState; 2427 if (safeMediaVolumeEnabled) { 2428 persistedState = SAFE_MEDIA_VOLUME_ACTIVE; 2429 // The state can already be "inactive" here if the user has forced it before 2430 // the 30 seconds timeout for forced configuration. In this case we don't reset 2431 // it to "active". 2432 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) { 2433 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; 2434 enforceSafeMediaVolume(); 2435 } 2436 } else { 2437 persistedState = SAFE_MEDIA_VOLUME_DISABLED; 2438 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; 2439 } 2440 mMcc = mcc; 2441 sendMsg(mAudioHandler, 2442 MSG_PERSIST_SAFE_VOLUME_STATE, 2443 SENDMSG_QUEUE, 2444 persistedState, 2445 0, 2446 null, 2447 0); 2448 } 2449 } 2450 } 2451 2452 /////////////////////////////////////////////////////////////////////////// 2453 // Internal methods 2454 /////////////////////////////////////////////////////////////////////////// 2455 2456 /** 2457 * Checks if the adjustment should change ringer mode instead of just 2458 * adjusting volume. If so, this will set the proper ringer mode and volume 2459 * indices on the stream states. 2460 */ 2461 private boolean checkForRingerModeChange(int oldIndex, int direction, int step) { 2462 boolean adjustVolumeIndex = true; 2463 int ringerMode = getRingerMode(); 2464 2465 switch (ringerMode) { 2466 case RINGER_MODE_NORMAL: 2467 if (direction == AudioManager.ADJUST_LOWER) { 2468 if (mHasVibrator) { 2469 // "step" is the delta in internal index units corresponding to a 2470 // change of 1 in UI index units. 2471 // Because of rounding when rescaling from one stream index range to its alias 2472 // index range, we cannot simply test oldIndex == step: 2473 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1) 2474 if (step <= oldIndex && oldIndex < 2 * step) { 2475 ringerMode = RINGER_MODE_VIBRATE; 2476 } 2477 } else { 2478 // (oldIndex < step) is equivalent to (old UI index == 0) 2479 if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2480 ringerMode = RINGER_MODE_SILENT; 2481 } 2482 } 2483 } 2484 break; 2485 case RINGER_MODE_VIBRATE: 2486 if (!mHasVibrator) { 2487 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" + 2488 "but no vibrator is present"); 2489 break; 2490 } 2491 if ((direction == AudioManager.ADJUST_LOWER)) { 2492 if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2493 ringerMode = RINGER_MODE_SILENT; 2494 } 2495 } else if (direction == AudioManager.ADJUST_RAISE) { 2496 ringerMode = RINGER_MODE_NORMAL; 2497 } 2498 adjustVolumeIndex = false; 2499 break; 2500 case RINGER_MODE_SILENT: 2501 if (direction == AudioManager.ADJUST_RAISE) { 2502 if (mHasVibrator) { 2503 ringerMode = RINGER_MODE_VIBRATE; 2504 } else { 2505 ringerMode = RINGER_MODE_NORMAL; 2506 } 2507 } 2508 adjustVolumeIndex = false; 2509 break; 2510 default: 2511 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode); 2512 break; 2513 } 2514 2515 setRingerMode(ringerMode); 2516 2517 mPrevVolDirection = direction; 2518 2519 return adjustVolumeIndex; 2520 } 2521 2522 public boolean isStreamAffectedByRingerMode(int streamType) { 2523 return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 2524 } 2525 2526 private boolean isStreamMutedByRingerMode(int streamType) { 2527 return (mRingerModeMutedStreams & (1 << streamType)) != 0; 2528 } 2529 2530 public boolean isStreamAffectedByMute(int streamType) { 2531 return (mMuteAffectedStreams & (1 << streamType)) != 0; 2532 } 2533 2534 private void ensureValidDirection(int direction) { 2535 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 2536 throw new IllegalArgumentException("Bad direction " + direction); 2537 } 2538 } 2539 2540 private void ensureValidSteps(int steps) { 2541 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 2542 throw new IllegalArgumentException("Bad volume adjust steps " + steps); 2543 } 2544 } 2545 2546 private void ensureValidStreamType(int streamType) { 2547 if (streamType < 0 || streamType >= mStreamStates.length) { 2548 throw new IllegalArgumentException("Bad stream type " + streamType); 2549 } 2550 } 2551 2552 private boolean isInCommunication() { 2553 boolean isOffhook = false; 2554 2555 if (mVoiceCapable) { 2556 try { 2557 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 2558 if (phone != null) isOffhook = phone.isOffhook(); 2559 } catch (RemoteException e) { 2560 Log.w(TAG, "Couldn't connect to phone service", e); 2561 } 2562 } 2563 return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 2564 } 2565 2566 private int getActiveStreamType(int suggestedStreamType) { 2567 if (mVoiceCapable) { 2568 if (isInCommunication()) { 2569 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2570 == AudioSystem.FORCE_BT_SCO) { 2571 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 2572 return AudioSystem.STREAM_BLUETOOTH_SCO; 2573 } else { 2574 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 2575 return AudioSystem.STREAM_VOICE_CALL; 2576 } 2577 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2578 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 2579 // volume can have priority over STREAM_MUSIC 2580 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 2581 if (DEBUG_VOL) 2582 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 2583 return STREAM_REMOTE_MUSIC; 2584 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 2585 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { 2586 if (DEBUG_VOL) 2587 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 2588 return AudioSystem.STREAM_MUSIC; 2589 } else { 2590 if (DEBUG_VOL) 2591 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); 2592 return AudioSystem.STREAM_RING; 2593 } 2594 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 2595 if (DEBUG_VOL) 2596 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 2597 return AudioSystem.STREAM_MUSIC; 2598 } else { 2599 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 2600 + suggestedStreamType); 2601 return suggestedStreamType; 2602 } 2603 } else { 2604 if (isInCommunication()) { 2605 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 2606 == AudioSystem.FORCE_BT_SCO) { 2607 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); 2608 return AudioSystem.STREAM_BLUETOOTH_SCO; 2609 } else { 2610 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); 2611 return AudioSystem.STREAM_VOICE_CALL; 2612 } 2613 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 2614 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) || 2615 AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 2616 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) { 2617 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); 2618 return AudioSystem.STREAM_NOTIFICATION; 2619 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 2620 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 2621 // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 2622 // volume can have priority over STREAM_MUSIC 2623 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 2624 return STREAM_REMOTE_MUSIC; 2625 } else { 2626 if (DEBUG_VOL) 2627 Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); 2628 return AudioSystem.STREAM_MUSIC; 2629 } 2630 } else { 2631 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 2632 + suggestedStreamType); 2633 return suggestedStreamType; 2634 } 2635 } 2636 } 2637 2638 private void broadcastRingerMode(int ringerMode) { 2639 // Send sticky broadcast 2640 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2641 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 2642 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2643 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2644 sendStickyBroadcastToAll(broadcast); 2645 } 2646 2647 private void broadcastVibrateSetting(int vibrateType) { 2648 // Send broadcast 2649 if (ActivityManagerNative.isSystemReady()) { 2650 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 2651 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 2652 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 2653 sendBroadcastToAll(broadcast); 2654 } 2655 } 2656 2657 // Message helper methods 2658 /** 2659 * Queue a message on the given handler's message queue, after acquiring the service wake lock. 2660 * Note that the wake lock needs to be released after the message has been handled. 2661 */ 2662 private void queueMsgUnderWakeLock(Handler handler, int msg, 2663 int arg1, int arg2, Object obj, int delay) { 2664 mAudioEventWakeLock.acquire(); 2665 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); 2666 } 2667 2668 private static void sendMsg(Handler handler, int msg, 2669 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 2670 2671 if (existingMsgPolicy == SENDMSG_REPLACE) { 2672 handler.removeMessages(msg); 2673 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 2674 return; 2675 } 2676 2677 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 2678 } 2679 2680 boolean checkAudioSettingsPermission(String method) { 2681 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 2682 == PackageManager.PERMISSION_GRANTED) { 2683 return true; 2684 } 2685 String msg = "Audio Settings Permission Denial: " + method + " from pid=" 2686 + Binder.getCallingPid() 2687 + ", uid=" + Binder.getCallingUid(); 2688 Log.w(TAG, msg); 2689 return false; 2690 } 2691 2692 private int getDeviceForStream(int stream) { 2693 int device = AudioSystem.getDevicesForStream(stream); 2694 if ((device & (device - 1)) != 0) { 2695 // Multiple device selection is either: 2696 // - speaker + one other device: give priority to speaker in this case. 2697 // - one A2DP device + another device: happens with duplicated output. In this case 2698 // retain the device on the A2DP output as the other must not correspond to an active 2699 // selection if not the speaker. 2700 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 2701 device = AudioSystem.DEVICE_OUT_SPEAKER; 2702 } else { 2703 device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 2704 } 2705 } 2706 return device; 2707 } 2708 2709 public void setWiredDeviceConnectionState(int device, int state, String name) { 2710 synchronized (mConnectedDevices) { 2711 int delay = checkSendBecomingNoisyIntent(device, state); 2712 queueMsgUnderWakeLock(mAudioHandler, 2713 MSG_SET_WIRED_DEVICE_CONNECTION_STATE, 2714 device, 2715 state, 2716 name, 2717 delay); 2718 } 2719 } 2720 2721 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state) 2722 { 2723 int delay; 2724 synchronized (mConnectedDevices) { 2725 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2726 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 2727 queueMsgUnderWakeLock(mAudioHandler, 2728 MSG_SET_A2DP_CONNECTION_STATE, 2729 state, 2730 0, 2731 device, 2732 delay); 2733 } 2734 return delay; 2735 } 2736 2737 /////////////////////////////////////////////////////////////////////////// 2738 // Inner classes 2739 /////////////////////////////////////////////////////////////////////////// 2740 2741 public class VolumeStreamState { 2742 private final int mStreamType; 2743 2744 private String mVolumeIndexSettingName; 2745 private int mIndexMax; 2746 private final ConcurrentHashMap<Integer, Integer> mIndex = 2747 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 2748 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 2749 2750 private VolumeStreamState(String settingName, int streamType) { 2751 2752 mVolumeIndexSettingName = settingName; 2753 2754 mStreamType = streamType; 2755 mIndexMax = MAX_STREAM_VOLUME[streamType]; 2756 AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2757 mIndexMax *= 10; 2758 2759 // mDeathHandlers must be created before calling readSettings() 2760 mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 2761 2762 readSettings(); 2763 } 2764 2765 public String getSettingNameForDevice(int device) { 2766 String name = mVolumeIndexSettingName; 2767 String suffix = AudioSystem.getDeviceName(device); 2768 if (suffix.isEmpty()) { 2769 return name; 2770 } 2771 return name + "_" + suffix; 2772 } 2773 2774 public synchronized void readSettings() { 2775 // force maximum volume on all streams if fixed volume property is set 2776 if (mUseFixedVolume) { 2777 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); 2778 return; 2779 } 2780 // do not read system stream volume from settings: this stream is always aliased 2781 // to another stream type and its volume is never persisted. Values in settings can 2782 // only be stale values 2783 if ((mStreamType == AudioSystem.STREAM_SYSTEM) || 2784 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) { 2785 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 2786 synchronized (mCameraSoundForced) { 2787 if (mCameraSoundForced) { 2788 index = mIndexMax; 2789 } 2790 } 2791 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); 2792 return; 2793 } 2794 2795 int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 2796 2797 for (int i = 0; remainingDevices != 0; i++) { 2798 int device = (1 << i); 2799 if ((device & remainingDevices) == 0) { 2800 continue; 2801 } 2802 remainingDevices &= ~device; 2803 2804 // retrieve current volume for device 2805 String name = getSettingNameForDevice(device); 2806 // if no volume stored for current stream and device, use default volume if default 2807 // device, continue otherwise 2808 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 2809 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 2810 int index = Settings.System.getIntForUser( 2811 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT); 2812 if (index == -1) { 2813 continue; 2814 } 2815 2816 // ignore settings for fixed volume devices: volume should always be at max or 0 2817 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) && 2818 ((device & mFixedVolumeDevices) != 0)) { 2819 mIndex.put(device, (index != 0) ? mIndexMax : 0); 2820 } else { 2821 mIndex.put(device, getValidIndex(10 * index)); 2822 } 2823 } 2824 } 2825 2826 public void applyDeviceVolume(int device) { 2827 int index; 2828 if (isMuted()) { 2829 index = 0; 2830 } else { 2831 index = (getIndex(device) + 5)/10; 2832 } 2833 AudioSystem.setStreamVolumeIndex(mStreamType, index, device); 2834 } 2835 2836 public synchronized void applyAllVolumes() { 2837 // apply default volume first: by convention this will reset all 2838 // devices volumes in audio policy manager to the supplied value 2839 int index; 2840 if (isMuted()) { 2841 index = 0; 2842 } else { 2843 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; 2844 } 2845 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT); 2846 // then apply device specific volumes 2847 Set set = mIndex.entrySet(); 2848 Iterator i = set.iterator(); 2849 while (i.hasNext()) { 2850 Map.Entry entry = (Map.Entry)i.next(); 2851 int device = ((Integer)entry.getKey()).intValue(); 2852 if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 2853 if (isMuted()) { 2854 index = 0; 2855 } else { 2856 index = ((Integer)entry.getValue() + 5)/10; 2857 } 2858 AudioSystem.setStreamVolumeIndex(mStreamType, index, device); 2859 } 2860 } 2861 } 2862 2863 public boolean adjustIndex(int deltaIndex, int device) { 2864 return setIndex(getIndex(device) + deltaIndex, 2865 device); 2866 } 2867 2868 public synchronized boolean setIndex(int index, int device) { 2869 int oldIndex = getIndex(device); 2870 index = getValidIndex(index); 2871 synchronized (mCameraSoundForced) { 2872 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) { 2873 index = mIndexMax; 2874 } 2875 } 2876 mIndex.put(device, index); 2877 2878 if (oldIndex != index) { 2879 // Apply change to all streams using this one as alias 2880 // if changing volume of current device, also change volume of current 2881 // device on aliased stream 2882 boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2883 int numStreamTypes = AudioSystem.getNumStreamTypes(); 2884 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2885 if (streamType != mStreamType && 2886 mStreamVolumeAlias[streamType] == mStreamType) { 2887 int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2888 mStreamStates[streamType].setIndex(scaledIndex, 2889 device); 2890 if (currentDevice) { 2891 mStreamStates[streamType].setIndex(scaledIndex, 2892 getDeviceForStream(streamType)); 2893 } 2894 } 2895 } 2896 return true; 2897 } else { 2898 return false; 2899 } 2900 } 2901 2902 public synchronized int getIndex(int device) { 2903 Integer index = mIndex.get(device); 2904 if (index == null) { 2905 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 2906 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT); 2907 } 2908 return index.intValue(); 2909 } 2910 2911 public int getMaxIndex() { 2912 return mIndexMax; 2913 } 2914 2915 public synchronized void setAllIndexes(VolumeStreamState srcStream) { 2916 Set set = srcStream.mIndex.entrySet(); 2917 Iterator i = set.iterator(); 2918 while (i.hasNext()) { 2919 Map.Entry entry = (Map.Entry)i.next(); 2920 int device = ((Integer)entry.getKey()).intValue(); 2921 int index = ((Integer)entry.getValue()).intValue(); 2922 index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 2923 2924 setIndex(index, device); 2925 } 2926 } 2927 2928 public synchronized void setAllIndexesToMax() { 2929 Set set = mIndex.entrySet(); 2930 Iterator i = set.iterator(); 2931 while (i.hasNext()) { 2932 Map.Entry entry = (Map.Entry)i.next(); 2933 entry.setValue(mIndexMax); 2934 } 2935 } 2936 2937 public synchronized void mute(IBinder cb, boolean state) { 2938 VolumeDeathHandler handler = getDeathHandler(cb, state); 2939 if (handler == null) { 2940 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 2941 return; 2942 } 2943 handler.mute(state); 2944 } 2945 2946 public int getStreamType() { 2947 return mStreamType; 2948 } 2949 2950 private int getValidIndex(int index) { 2951 if (index < 0) { 2952 return 0; 2953 } else if (mUseFixedVolume || index > mIndexMax) { 2954 return mIndexMax; 2955 } 2956 2957 return index; 2958 } 2959 2960 private class VolumeDeathHandler implements IBinder.DeathRecipient { 2961 private IBinder mICallback; // To be notified of client's death 2962 private int mMuteCount; // Number of active mutes for this client 2963 2964 VolumeDeathHandler(IBinder cb) { 2965 mICallback = cb; 2966 } 2967 2968 // must be called while synchronized on parent VolumeStreamState 2969 public void mute(boolean state) { 2970 boolean updateVolume = false; 2971 if (state) { 2972 if (mMuteCount == 0) { 2973 // Register for client death notification 2974 try { 2975 // mICallback can be 0 if muted by AudioService 2976 if (mICallback != null) { 2977 mICallback.linkToDeath(this, 0); 2978 } 2979 VolumeStreamState.this.mDeathHandlers.add(this); 2980 // If the stream is not yet muted by any client, set level to 0 2981 if (!VolumeStreamState.this.isMuted()) { 2982 updateVolume = true; 2983 } 2984 } catch (RemoteException e) { 2985 // Client has died! 2986 binderDied(); 2987 return; 2988 } 2989 } else { 2990 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 2991 } 2992 mMuteCount++; 2993 } else { 2994 if (mMuteCount == 0) { 2995 Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 2996 } else { 2997 mMuteCount--; 2998 if (mMuteCount == 0) { 2999 // Unregister from client death notification 3000 VolumeStreamState.this.mDeathHandlers.remove(this); 3001 // mICallback can be 0 if muted by AudioService 3002 if (mICallback != null) { 3003 mICallback.unlinkToDeath(this, 0); 3004 } 3005 if (!VolumeStreamState.this.isMuted()) { 3006 updateVolume = true; 3007 } 3008 } 3009 } 3010 } 3011 if (updateVolume) { 3012 sendMsg(mAudioHandler, 3013 MSG_SET_ALL_VOLUMES, 3014 SENDMSG_QUEUE, 3015 0, 3016 0, 3017 VolumeStreamState.this, 0); 3018 } 3019 } 3020 3021 public void binderDied() { 3022 Log.w(TAG, "Volume service client died for stream: "+mStreamType); 3023 if (mMuteCount != 0) { 3024 // Reset all active mute requests from this client. 3025 mMuteCount = 1; 3026 mute(false); 3027 } 3028 } 3029 } 3030 3031 private synchronized int muteCount() { 3032 int count = 0; 3033 int size = mDeathHandlers.size(); 3034 for (int i = 0; i < size; i++) { 3035 count += mDeathHandlers.get(i).mMuteCount; 3036 } 3037 return count; 3038 } 3039 3040 private synchronized boolean isMuted() { 3041 return muteCount() != 0; 3042 } 3043 3044 // only called by mute() which is already synchronized 3045 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 3046 VolumeDeathHandler handler; 3047 int size = mDeathHandlers.size(); 3048 for (int i = 0; i < size; i++) { 3049 handler = mDeathHandlers.get(i); 3050 if (cb == handler.mICallback) { 3051 return handler; 3052 } 3053 } 3054 // If this is the first mute request for this client, create a new 3055 // client death handler. Otherwise, it is an out of sequence unmute request. 3056 if (state) { 3057 handler = new VolumeDeathHandler(cb); 3058 } else { 3059 Log.w(TAG, "stream was not muted by this client"); 3060 handler = null; 3061 } 3062 return handler; 3063 } 3064 3065 private void dump(PrintWriter pw) { 3066 pw.print(" Mute count: "); 3067 pw.println(muteCount()); 3068 pw.print(" Current: "); 3069 Set set = mIndex.entrySet(); 3070 Iterator i = set.iterator(); 3071 while (i.hasNext()) { 3072 Map.Entry entry = (Map.Entry)i.next(); 3073 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 3074 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 3075 } 3076 } 3077 } 3078 3079 /** Thread that handles native AudioSystem control. */ 3080 private class AudioSystemThread extends Thread { 3081 AudioSystemThread() { 3082 super("AudioService"); 3083 } 3084 3085 @Override 3086 public void run() { 3087 // Set this thread up so the handler will work on it 3088 Looper.prepare(); 3089 3090 synchronized(AudioService.this) { 3091 mAudioHandler = new AudioHandler(); 3092 3093 // Notify that the handler has been created 3094 AudioService.this.notify(); 3095 } 3096 3097 // Listen for volume change requests that are set by VolumePanel 3098 Looper.loop(); 3099 } 3100 } 3101 3102 /** Handles internal volume messages in separate volume thread. */ 3103 private class AudioHandler extends Handler { 3104 3105 private void setDeviceVolume(VolumeStreamState streamState, int device) { 3106 3107 // Apply volume 3108 streamState.applyDeviceVolume(device); 3109 3110 // Apply change to all streams using this one as alias 3111 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3112 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3113 if (streamType != streamState.mStreamType && 3114 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 3115 mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 3116 } 3117 } 3118 3119 // Post a persist volume msg 3120 sendMsg(mAudioHandler, 3121 MSG_PERSIST_VOLUME, 3122 SENDMSG_QUEUE, 3123 device, 3124 0, 3125 streamState, 3126 PERSIST_DELAY); 3127 3128 } 3129 3130 private void setAllVolumes(VolumeStreamState streamState) { 3131 3132 // Apply volume 3133 streamState.applyAllVolumes(); 3134 3135 // Apply change to all streams using this one as alias 3136 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3137 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3138 if (streamType != streamState.mStreamType && 3139 mStreamVolumeAlias[streamType] == streamState.mStreamType) { 3140 mStreamStates[streamType].applyAllVolumes(); 3141 } 3142 } 3143 } 3144 3145 private void persistVolume(VolumeStreamState streamState, int device) { 3146 if (mUseFixedVolume) { 3147 return; 3148 } 3149 System.putIntForUser(mContentResolver, 3150 streamState.getSettingNameForDevice(device), 3151 (streamState.getIndex(device) + 5)/ 10, 3152 UserHandle.USER_CURRENT); 3153 } 3154 3155 private void persistRingerMode(int ringerMode) { 3156 if (mUseFixedVolume) { 3157 return; 3158 } 3159 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode); 3160 } 3161 3162 private boolean onLoadSoundEffects() { 3163 int status; 3164 3165 synchronized (mSoundEffectsLock) { 3166 if (!mBootCompleted) { 3167 Log.w(TAG, "onLoadSoundEffects() called before boot complete"); 3168 return false; 3169 } 3170 3171 if (mSoundPool != null) { 3172 return true; 3173 } 3174 3175 loadTouchSoundAssets(); 3176 3177 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 3178 mSoundPoolCallBack = null; 3179 mSoundPoolListenerThread = new SoundPoolListenerThread(); 3180 mSoundPoolListenerThread.start(); 3181 int attempts = 3; 3182 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) { 3183 try { 3184 // Wait for mSoundPoolCallBack to be set by the other thread 3185 mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS); 3186 } catch (InterruptedException e) { 3187 Log.w(TAG, "Interrupted while waiting sound pool listener thread."); 3188 } 3189 } 3190 3191 if (mSoundPoolCallBack == null) { 3192 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error"); 3193 if (mSoundPoolLooper != null) { 3194 mSoundPoolLooper.quit(); 3195 mSoundPoolLooper = null; 3196 } 3197 mSoundPoolListenerThread = null; 3198 mSoundPool.release(); 3199 mSoundPool = null; 3200 return false; 3201 } 3202 /* 3203 * poolId table: The value -1 in this table indicates that corresponding 3204 * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 3205 * Once loaded, the value in poolId is the sample ID and the same 3206 * sample can be reused for another effect using the same file. 3207 */ 3208 int[] poolId = new int[SOUND_EFFECT_FILES.size()]; 3209 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) { 3210 poolId[fileIdx] = -1; 3211 } 3212 /* 3213 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 3214 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 3215 * this indicates we have a valid sample loaded for this effect. 3216 */ 3217 3218 int numSamples = 0; 3219 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 3220 // Do not load sample if this effect uses the MediaPlayer 3221 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 3222 continue; 3223 } 3224 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 3225 String filePath = Environment.getRootDirectory() 3226 + SOUND_EFFECTS_PATH 3227 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]); 3228 int sampleId = mSoundPool.load(filePath, 0); 3229 if (sampleId <= 0) { 3230 Log.w(TAG, "Soundpool could not load file: "+filePath); 3231 } else { 3232 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 3233 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 3234 numSamples++; 3235 } 3236 } else { 3237 SOUND_EFFECT_FILES_MAP[effect][1] = 3238 poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 3239 } 3240 } 3241 // wait for all samples to be loaded 3242 if (numSamples > 0) { 3243 mSoundPoolCallBack.setSamples(poolId); 3244 3245 attempts = 3; 3246 status = 1; 3247 while ((status == 1) && (attempts-- > 0)) { 3248 try { 3249 mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS); 3250 status = mSoundPoolCallBack.status(); 3251 } catch (InterruptedException e) { 3252 Log.w(TAG, "Interrupted while waiting sound pool callback."); 3253 } 3254 } 3255 } else { 3256 status = -1; 3257 } 3258 3259 if (mSoundPoolLooper != null) { 3260 mSoundPoolLooper.quit(); 3261 mSoundPoolLooper = null; 3262 } 3263 mSoundPoolListenerThread = null; 3264 if (status != 0) { 3265 Log.w(TAG, 3266 "onLoadSoundEffects(), Error "+status+ " while loading samples"); 3267 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 3268 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) { 3269 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 3270 } 3271 } 3272 3273 mSoundPool.release(); 3274 mSoundPool = null; 3275 } 3276 } 3277 return (status == 0); 3278 } 3279 3280 /** 3281 * Unloads samples from the sound pool. 3282 * This method can be called to free some memory when 3283 * sound effects are disabled. 3284 */ 3285 private void onUnloadSoundEffects() { 3286 synchronized (mSoundEffectsLock) { 3287 if (mSoundPool == null) { 3288 return; 3289 } 3290 3291 int[] poolId = new int[SOUND_EFFECT_FILES.size()]; 3292 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) { 3293 poolId[fileIdx] = 0; 3294 } 3295 3296 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 3297 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 3298 continue; 3299 } 3300 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 3301 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 3302 SOUND_EFFECT_FILES_MAP[effect][1] = -1; 3303 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 3304 } 3305 } 3306 mSoundPool.release(); 3307 mSoundPool = null; 3308 } 3309 } 3310 3311 private void onPlaySoundEffect(int effectType, int volume) { 3312 synchronized (mSoundEffectsLock) { 3313 3314 onLoadSoundEffects(); 3315 3316 if (mSoundPool == null) { 3317 return; 3318 } 3319 float volFloat; 3320 // use default if volume is not specified by caller 3321 if (volume < 0) { 3322 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20); 3323 } else { 3324 volFloat = (float) volume / 1000.0f; 3325 } 3326 3327 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 3328 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], 3329 volFloat, volFloat, 0, 0, 1.0f); 3330 } else { 3331 MediaPlayer mediaPlayer = new MediaPlayer(); 3332 try { 3333 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + 3334 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]); 3335 mediaPlayer.setDataSource(filePath); 3336 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 3337 mediaPlayer.prepare(); 3338 mediaPlayer.setVolume(volFloat); 3339 mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 3340 public void onCompletion(MediaPlayer mp) { 3341 cleanupPlayer(mp); 3342 } 3343 }); 3344 mediaPlayer.setOnErrorListener(new OnErrorListener() { 3345 public boolean onError(MediaPlayer mp, int what, int extra) { 3346 cleanupPlayer(mp); 3347 return true; 3348 } 3349 }); 3350 mediaPlayer.start(); 3351 } catch (IOException ex) { 3352 Log.w(TAG, "MediaPlayer IOException: "+ex); 3353 } catch (IllegalArgumentException ex) { 3354 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 3355 } catch (IllegalStateException ex) { 3356 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 3357 } 3358 } 3359 } 3360 } 3361 3362 private void cleanupPlayer(MediaPlayer mp) { 3363 if (mp != null) { 3364 try { 3365 mp.stop(); 3366 mp.release(); 3367 } catch (IllegalStateException ex) { 3368 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 3369 } 3370 } 3371 } 3372 3373 private void setForceUse(int usage, int config) { 3374 AudioSystem.setForceUse(usage, config); 3375 } 3376 3377 private void onPersistSafeVolumeState(int state) { 3378 Settings.Global.putInt(mContentResolver, 3379 Settings.Global.AUDIO_SAFE_VOLUME_STATE, 3380 state); 3381 } 3382 3383 @Override 3384 public void handleMessage(Message msg) { 3385 3386 switch (msg.what) { 3387 3388 case MSG_SET_DEVICE_VOLUME: 3389 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 3390 break; 3391 3392 case MSG_SET_ALL_VOLUMES: 3393 setAllVolumes((VolumeStreamState) msg.obj); 3394 break; 3395 3396 case MSG_PERSIST_VOLUME: 3397 persistVolume((VolumeStreamState) msg.obj, msg.arg1); 3398 break; 3399 3400 case MSG_PERSIST_MASTER_VOLUME: 3401 if (mUseFixedVolume) { 3402 return; 3403 } 3404 Settings.System.putFloatForUser(mContentResolver, 3405 Settings.System.VOLUME_MASTER, 3406 (float)msg.arg1 / (float)1000.0, 3407 UserHandle.USER_CURRENT); 3408 break; 3409 3410 case MSG_PERSIST_MASTER_VOLUME_MUTE: 3411 if (mUseFixedVolume) { 3412 return; 3413 } 3414 Settings.System.putIntForUser(mContentResolver, 3415 Settings.System.VOLUME_MASTER_MUTE, 3416 msg.arg1, 3417 UserHandle.USER_CURRENT); 3418 break; 3419 3420 case MSG_PERSIST_RINGER_MODE: 3421 // note that the value persisted is the current ringer mode, not the 3422 // value of ringer mode as of the time the request was made to persist 3423 persistRingerMode(getRingerMode()); 3424 break; 3425 3426 case MSG_MEDIA_SERVER_DIED: 3427 if (!mMediaServerOk) { 3428 Log.e(TAG, "Media server died."); 3429 // Force creation of new IAudioFlinger interface so that we are notified 3430 // when new media_server process is back to life. 3431 AudioSystem.setErrorCallback(mAudioSystemCallback); 3432 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 3433 null, 500); 3434 } 3435 break; 3436 3437 case MSG_MEDIA_SERVER_STARTED: 3438 Log.e(TAG, "Media server started."); 3439 // indicate to audio HAL that we start the reconfiguration phase after a media 3440 // server crash 3441 // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 3442 // process restarts after a crash, not the first time it is started. 3443 AudioSystem.setParameters("restarting=true"); 3444 3445 readAndSetLowRamDevice(); 3446 3447 // Restore device connection states 3448 synchronized (mConnectedDevices) { 3449 Set set = mConnectedDevices.entrySet(); 3450 Iterator i = set.iterator(); 3451 while (i.hasNext()) { 3452 Map.Entry device = (Map.Entry)i.next(); 3453 AudioSystem.setDeviceConnectionState( 3454 ((Integer)device.getKey()).intValue(), 3455 AudioSystem.DEVICE_STATE_AVAILABLE, 3456 (String)device.getValue()); 3457 } 3458 } 3459 // Restore call state 3460 AudioSystem.setPhoneState(mMode); 3461 3462 // Restore forced usage for communcations and record 3463 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 3464 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 3465 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ? 3466 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE); 3467 3468 // Restore stream volumes 3469 int numStreamTypes = AudioSystem.getNumStreamTypes(); 3470 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 3471 VolumeStreamState streamState = mStreamStates[streamType]; 3472 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 3473 3474 streamState.applyAllVolumes(); 3475 } 3476 3477 // Restore ringer mode 3478 setRingerModeInt(getRingerMode(), false); 3479 3480 // Restore master volume 3481 restoreMasterVolume(); 3482 3483 // Reset device orientation (if monitored for this device) 3484 if (mMonitorOrientation) { 3485 setOrientationForAudioSystem(); 3486 } 3487 if (mMonitorRotation) { 3488 setRotationForAudioSystem(); 3489 } 3490 3491 synchronized (mBluetoothA2dpEnabledLock) { 3492 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 3493 mBluetoothA2dpEnabled ? 3494 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 3495 } 3496 3497 synchronized (mSettingsLock) { 3498 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, 3499 mDockAudioMediaEnabled ? 3500 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE); 3501 } 3502 3503 // indicate the end of reconfiguration phase to audio HAL 3504 AudioSystem.setParameters("restarting=false"); 3505 break; 3506 3507 case MSG_UNLOAD_SOUND_EFFECTS: 3508 onUnloadSoundEffects(); 3509 break; 3510 3511 case MSG_LOAD_SOUND_EFFECTS: 3512 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it 3513 // can take several dozens of milliseconds to complete 3514 boolean loaded = onLoadSoundEffects(); 3515 if (msg.obj != null) { 3516 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj; 3517 synchronized (reply) { 3518 reply.mStatus = loaded ? 0 : -1; 3519 reply.notify(); 3520 } 3521 } 3522 break; 3523 3524 case MSG_PLAY_SOUND_EFFECT: 3525 onPlaySoundEffect(msg.arg1, msg.arg2); 3526 break; 3527 3528 case MSG_BTA2DP_DOCK_TIMEOUT: 3529 // msg.obj == address of BTA2DP device 3530 synchronized (mConnectedDevices) { 3531 makeA2dpDeviceUnavailableNow( (String) msg.obj ); 3532 } 3533 break; 3534 3535 case MSG_SET_FORCE_USE: 3536 case MSG_SET_FORCE_BT_A2DP_USE: 3537 setForceUse(msg.arg1, msg.arg2); 3538 break; 3539 3540 case MSG_BT_HEADSET_CNCT_FAILED: 3541 resetBluetoothSco(); 3542 break; 3543 3544 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: 3545 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj); 3546 mAudioEventWakeLock.release(); 3547 break; 3548 3549 case MSG_SET_A2DP_CONNECTION_STATE: 3550 onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1); 3551 mAudioEventWakeLock.release(); 3552 break; 3553 3554 case MSG_REPORT_NEW_ROUTES: { 3555 int N = mRoutesObservers.beginBroadcast(); 3556 if (N > 0) { 3557 AudioRoutesInfo routes; 3558 synchronized (mCurAudioRoutes) { 3559 routes = new AudioRoutesInfo(mCurAudioRoutes); 3560 } 3561 while (N > 0) { 3562 N--; 3563 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N); 3564 try { 3565 obs.dispatchAudioRoutesChanged(routes); 3566 } catch (RemoteException e) { 3567 } 3568 } 3569 } 3570 mRoutesObservers.finishBroadcast(); 3571 break; 3572 } 3573 3574 case MSG_SET_RSX_CONNECTION_STATE: 3575 onSetRsxConnectionState(msg.arg1/*available*/, msg.arg2/*address*/); 3576 break; 3577 3578 case MSG_CHECK_MUSIC_ACTIVE: 3579 onCheckMusicActive(); 3580 break; 3581 3582 case MSG_BROADCAST_AUDIO_BECOMING_NOISY: 3583 onSendBecomingNoisyIntent(); 3584 break; 3585 3586 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED: 3587 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME: 3588 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED)); 3589 break; 3590 case MSG_PERSIST_SAFE_VOLUME_STATE: 3591 onPersistSafeVolumeState(msg.arg1); 3592 break; 3593 3594 case MSG_BROADCAST_BT_CONNECTION_STATE: 3595 onBroadcastScoConnectionState(msg.arg1); 3596 break; 3597 } 3598 } 3599 } 3600 3601 private class SettingsObserver extends ContentObserver { 3602 3603 SettingsObserver() { 3604 super(new Handler()); 3605 mContentResolver.registerContentObserver(Settings.System.getUriFor( 3606 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 3607 mContentResolver.registerContentObserver(Settings.Global.getUriFor( 3608 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this); 3609 } 3610 3611 @Override 3612 public void onChange(boolean selfChange) { 3613 super.onChange(selfChange); 3614 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 3615 // However there appear to be some missing locks around mRingerModeMutedStreams 3616 // and mRingerModeAffectedStreams, so will leave this synchronized for now. 3617 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 3618 synchronized (mSettingsLock) { 3619 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver, 3620 Settings.System.MODE_RINGER_STREAMS_AFFECTED, 3621 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 3622 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)), 3623 UserHandle.USER_CURRENT); 3624 if (mVoiceCapable) { 3625 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 3626 } else { 3627 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 3628 } 3629 synchronized (mCameraSoundForced) { 3630 if (mCameraSoundForced) { 3631 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 3632 } else { 3633 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 3634 } 3635 } 3636 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 3637 /* 3638 * Ensure all stream types that should be affected by ringer mode 3639 * are in the proper state. 3640 */ 3641 mRingerModeAffectedStreams = ringerModeAffectedStreams; 3642 setRingerModeInt(getRingerMode(), false); 3643 } 3644 readDockAudioSettings(mContentResolver); 3645 } 3646 } 3647 } 3648 3649 // must be called synchronized on mConnectedDevices 3650 private void makeA2dpDeviceAvailable(String address) { 3651 // enable A2DP before notifying A2DP connection to avoid unecessary processing in 3652 // audio policy manager 3653 setBluetoothA2dpOnInt(true); 3654 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 3655 AudioSystem.DEVICE_STATE_AVAILABLE, 3656 address); 3657 // Reset A2DP suspend state each time a new sink is connected 3658 AudioSystem.setParameters("A2dpSuspended=false"); 3659 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 3660 address); 3661 } 3662 3663 private void onSendBecomingNoisyIntent() { 3664 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); 3665 } 3666 3667 // must be called synchronized on mConnectedDevices 3668 private void makeA2dpDeviceUnavailableNow(String address) { 3669 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 3670 AudioSystem.DEVICE_STATE_UNAVAILABLE, 3671 address); 3672 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 3673 } 3674 3675 // must be called synchronized on mConnectedDevices 3676 private void makeA2dpDeviceUnavailableLater(String address) { 3677 // prevent any activity on the A2DP audio output to avoid unwanted 3678 // reconnection of the sink. 3679 AudioSystem.setParameters("A2dpSuspended=true"); 3680 // the device will be made unavailable later, so consider it disconnected right away 3681 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 3682 // send the delayed message to make the device unavailable later 3683 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 3684 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 3685 3686 } 3687 3688 // must be called synchronized on mConnectedDevices 3689 private void cancelA2dpDeviceTimeout() { 3690 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3691 } 3692 3693 // must be called synchronized on mConnectedDevices 3694 private boolean hasScheduledA2dpDockTimeout() { 3695 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3696 } 3697 3698 private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) 3699 { 3700 if (btDevice == null) { 3701 return; 3702 } 3703 String address = btDevice.getAddress(); 3704 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3705 address = ""; 3706 } 3707 synchronized (mConnectedDevices) { 3708 boolean isConnected = 3709 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 3710 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 3711 3712 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 3713 if (btDevice.isBluetoothDock()) { 3714 if (state == BluetoothProfile.STATE_DISCONNECTED) { 3715 // introduction of a delay for transient disconnections of docks when 3716 // power is rapidly turned off/on, this message will be canceled if 3717 // we reconnect the dock under a preset delay 3718 makeA2dpDeviceUnavailableLater(address); 3719 // the next time isConnected is evaluated, it will be false for the dock 3720 } 3721 } else { 3722 makeA2dpDeviceUnavailableNow(address); 3723 } 3724 synchronized (mCurAudioRoutes) { 3725 if (mCurAudioRoutes.mBluetoothName != null) { 3726 mCurAudioRoutes.mBluetoothName = null; 3727 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3728 SENDMSG_NOOP, 0, 0, null, 0); 3729 } 3730 } 3731 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 3732 if (btDevice.isBluetoothDock()) { 3733 // this could be a reconnection after a transient disconnection 3734 cancelA2dpDeviceTimeout(); 3735 mDockAddress = address; 3736 } else { 3737 // this could be a connection of another A2DP device before the timeout of 3738 // a dock: cancel the dock timeout, and make the dock unavailable now 3739 if(hasScheduledA2dpDockTimeout()) { 3740 cancelA2dpDeviceTimeout(); 3741 makeA2dpDeviceUnavailableNow(mDockAddress); 3742 } 3743 } 3744 makeA2dpDeviceAvailable(address); 3745 synchronized (mCurAudioRoutes) { 3746 String name = btDevice.getAliasName(); 3747 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) { 3748 mCurAudioRoutes.mBluetoothName = name; 3749 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3750 SENDMSG_NOOP, 0, 0, null, 0); 3751 } 3752 } 3753 } 3754 } 3755 } 3756 3757 private boolean handleDeviceConnection(boolean connected, int device, String params) { 3758 synchronized (mConnectedDevices) { 3759 boolean isConnected = (mConnectedDevices.containsKey(device) && 3760 (params.isEmpty() || mConnectedDevices.get(device).equals(params))); 3761 3762 if (isConnected && !connected) { 3763 AudioSystem.setDeviceConnectionState(device, 3764 AudioSystem.DEVICE_STATE_UNAVAILABLE, 3765 mConnectedDevices.get(device)); 3766 mConnectedDevices.remove(device); 3767 return true; 3768 } else if (!isConnected && connected) { 3769 AudioSystem.setDeviceConnectionState(device, 3770 AudioSystem.DEVICE_STATE_AVAILABLE, 3771 params); 3772 mConnectedDevices.put(new Integer(device), params); 3773 return true; 3774 } 3775 } 3776 return false; 3777 } 3778 3779 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only 3780 // sent if none of these devices is connected. 3781 int mBecomingNoisyIntentDevices = 3782 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | 3783 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL | 3784 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | 3785 AudioSystem.DEVICE_OUT_ALL_USB; 3786 3787 // must be called before removing the device from mConnectedDevices 3788 private int checkSendBecomingNoisyIntent(int device, int state) { 3789 int delay = 0; 3790 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) { 3791 int devices = 0; 3792 for (int dev : mConnectedDevices.keySet()) { 3793 if ((dev & mBecomingNoisyIntentDevices) != 0) { 3794 devices |= dev; 3795 } 3796 } 3797 if (devices == device) { 3798 sendMsg(mAudioHandler, 3799 MSG_BROADCAST_AUDIO_BECOMING_NOISY, 3800 SENDMSG_REPLACE, 3801 0, 3802 0, 3803 null, 3804 0); 3805 delay = 1000; 3806 } 3807 } 3808 3809 if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) || 3810 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { 3811 delay = 1000; 3812 } 3813 return delay; 3814 } 3815 3816 private void sendDeviceConnectionIntent(int device, int state, String name) 3817 { 3818 Intent intent = new Intent(); 3819 3820 intent.putExtra("state", state); 3821 intent.putExtra("name", name); 3822 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3823 3824 int connType = 0; 3825 3826 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) { 3827 connType = AudioRoutesInfo.MAIN_HEADSET; 3828 intent.setAction(Intent.ACTION_HEADSET_PLUG); 3829 intent.putExtra("microphone", 1); 3830 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) { 3831 connType = AudioRoutesInfo.MAIN_HEADPHONES; 3832 intent.setAction(Intent.ACTION_HEADSET_PLUG); 3833 intent.putExtra("microphone", 0); 3834 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) { 3835 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3836 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 3837 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { 3838 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3839 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 3840 } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { 3841 connType = AudioRoutesInfo.MAIN_HDMI; 3842 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); 3843 } 3844 3845 synchronized (mCurAudioRoutes) { 3846 if (connType != 0) { 3847 int newConn = mCurAudioRoutes.mMainType; 3848 if (state != 0) { 3849 newConn |= connType; 3850 } else { 3851 newConn &= ~connType; 3852 } 3853 if (newConn != mCurAudioRoutes.mMainType) { 3854 mCurAudioRoutes.mMainType = newConn; 3855 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3856 SENDMSG_NOOP, 0, 0, null, 0); 3857 } 3858 } 3859 } 3860 3861 final long ident = Binder.clearCallingIdentity(); 3862 try { 3863 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); 3864 } finally { 3865 Binder.restoreCallingIdentity(ident); 3866 } 3867 } 3868 3869 private void onSetWiredDeviceConnectionState(int device, int state, String name) 3870 { 3871 synchronized (mConnectedDevices) { 3872 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3873 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3874 setBluetoothA2dpOnInt(true); 3875 } 3876 boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0); 3877 handleDeviceConnection((state == 1), device, (isUsb ? name : "")); 3878 if (state != 0) { 3879 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3880 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) { 3881 setBluetoothA2dpOnInt(false); 3882 } 3883 if ((device & mSafeMediaVolumeDevices) != 0) { 3884 sendMsg(mAudioHandler, 3885 MSG_CHECK_MUSIC_ACTIVE, 3886 SENDMSG_REPLACE, 3887 0, 3888 0, 3889 null, 3890 MUSIC_ACTIVE_POLL_PERIOD_MS); 3891 } 3892 } 3893 if (!isUsb) { 3894 sendDeviceConnectionIntent(device, state, name); 3895 } 3896 } 3897 } 3898 3899 /* cache of the address of the last dock the device was connected to */ 3900 private String mDockAddress; 3901 3902 /** 3903 * Receiver for misc intent broadcasts the Phone app cares about. 3904 */ 3905 private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 3906 @Override 3907 public void onReceive(Context context, Intent intent) { 3908 String action = intent.getAction(); 3909 int device; 3910 int state; 3911 3912 if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3913 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3914 Intent.EXTRA_DOCK_STATE_UNDOCKED); 3915 int config; 3916 switch (dockState) { 3917 case Intent.EXTRA_DOCK_STATE_DESK: 3918 config = AudioSystem.FORCE_BT_DESK_DOCK; 3919 break; 3920 case Intent.EXTRA_DOCK_STATE_CAR: 3921 config = AudioSystem.FORCE_BT_CAR_DOCK; 3922 break; 3923 case Intent.EXTRA_DOCK_STATE_LE_DESK: 3924 config = AudioSystem.FORCE_ANALOG_DOCK; 3925 break; 3926 case Intent.EXTRA_DOCK_STATE_HE_DESK: 3927 config = AudioSystem.FORCE_DIGITAL_DOCK; 3928 break; 3929 case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3930 default: 3931 config = AudioSystem.FORCE_NONE; 3932 } 3933 // Low end docks have a menu to enable or disable audio 3934 // (see mDockAudioMediaEnabled) 3935 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) || 3936 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) && 3937 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) { 3938 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 3939 } 3940 mDockState = dockState; 3941 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 3942 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 3943 BluetoothProfile.STATE_DISCONNECTED); 3944 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3945 String address = null; 3946 3947 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3948 if (btDevice == null) { 3949 return; 3950 } 3951 3952 address = btDevice.getAddress(); 3953 BluetoothClass btClass = btDevice.getBluetoothClass(); 3954 if (btClass != null) { 3955 switch (btClass.getDeviceClass()) { 3956 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3957 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3958 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3959 break; 3960 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3961 device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3962 break; 3963 } 3964 } 3965 3966 if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3967 address = ""; 3968 } 3969 3970 boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 3971 if (handleDeviceConnection(connected, device, address)) { 3972 synchronized (mScoClients) { 3973 if (connected) { 3974 mBluetoothHeadsetDevice = btDevice; 3975 } else { 3976 mBluetoothHeadsetDevice = null; 3977 resetBluetoothSco(); 3978 } 3979 } 3980 } 3981 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 3982 action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 3983 state = intent.getIntExtra("state", 0); 3984 int alsaCard = intent.getIntExtra("card", -1); 3985 int alsaDevice = intent.getIntExtra("device", -1); 3986 String params = (alsaCard == -1 && alsaDevice == -1 ? "" 3987 : "card=" + alsaCard + ";device=" + alsaDevice); 3988 device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3989 AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 3990 Log.v(TAG, "Broadcast Receiver: Got " 3991 + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 3992 "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 3993 + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 3994 setWiredDeviceConnectionState(device, state, params); 3995 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 3996 boolean broadcast = false; 3997 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 3998 synchronized (mScoClients) { 3999 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 4000 // broadcast intent if the connection was initated by AudioService 4001 if (!mScoClients.isEmpty() && 4002 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 4003 mScoAudioState == SCO_STATE_ACTIVATE_REQ || 4004 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 4005 broadcast = true; 4006 } 4007 switch (btState) { 4008 case BluetoothHeadset.STATE_AUDIO_CONNECTED: 4009 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 4010 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 4011 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 4012 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 4013 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 4014 } 4015 break; 4016 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 4017 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 4018 mScoAudioState = SCO_STATE_INACTIVE; 4019 clearAllScoClients(0, false); 4020 break; 4021 case BluetoothHeadset.STATE_AUDIO_CONNECTING: 4022 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 4023 mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 4024 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 4025 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 4026 } 4027 default: 4028 // do not broadcast CONNECTING or invalid state 4029 broadcast = false; 4030 break; 4031 } 4032 } 4033 if (broadcast) { 4034 broadcastScoConnectionState(scoAudioState); 4035 //FIXME: this is to maintain compatibility with deprecated intent 4036 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 4037 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 4038 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 4039 sendStickyBroadcastToAll(newIntent); 4040 } 4041 } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 4042 mBootCompleted = true; 4043 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 4044 0, 0, null, 0); 4045 4046 mKeyguardManager = 4047 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 4048 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 4049 resetBluetoothSco(); 4050 getBluetoothHeadset(); 4051 //FIXME: this is to maintain compatibility with deprecated intent 4052 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 4053 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 4054 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 4055 AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 4056 sendStickyBroadcastToAll(newIntent); 4057 4058 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 4059 if (adapter != null) { 4060 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 4061 BluetoothProfile.A2DP); 4062 } 4063 4064 sendMsg(mAudioHandler, 4065 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, 4066 SENDMSG_REPLACE, 4067 0, 4068 0, 4069 null, 4070 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); 4071 } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 4072 AudioSystem.setParameters("screen_state=on"); 4073 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 4074 AudioSystem.setParameters("screen_state=off"); 4075 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 4076 handleConfigurationChanged(context); 4077 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { 4078 // attempt to stop music playback for background user 4079 sendMsg(mAudioHandler, 4080 MSG_BROADCAST_AUDIO_BECOMING_NOISY, 4081 SENDMSG_REPLACE, 4082 0, 4083 0, 4084 null, 4085 0); 4086 // the current audio focus owner is no longer valid 4087 mMediaFocusControl.discardAudioFocusOwner(); 4088 4089 // load volume settings for new user 4090 readAudioSettings(true /*userSwitch*/); 4091 // preserve STREAM_MUSIC volume from one user to the next. 4092 sendMsg(mAudioHandler, 4093 MSG_SET_ALL_VOLUMES, 4094 SENDMSG_QUEUE, 4095 0, 4096 0, 4097 mStreamStates[AudioSystem.STREAM_MUSIC], 0); 4098 } 4099 } 4100 } 4101 4102 //========================================================================================== 4103 // RemoteControlDisplay / RemoteControlClient / Remote info 4104 //========================================================================================== 4105 public void registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) { 4106 mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h); 4107 } 4108 4109 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 4110 mMediaFocusControl.unregisterRemoteControlDisplay(rcd); 4111 } 4112 4113 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 4114 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h); 4115 } 4116 4117 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd, 4118 boolean wantsSync) { 4119 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync); 4120 } 4121 4122 public void registerMediaButtonEventReceiverForCalls(ComponentName c) { 4123 mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c); 4124 } 4125 4126 public void unregisterMediaButtonEventReceiverForCalls() { 4127 mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls(); 4128 } 4129 4130 public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) { 4131 mMediaFocusControl.registerMediaButtonIntent(pi, c, token); 4132 } 4133 4134 public void unregisterMediaButtonIntent(PendingIntent pi) { 4135 mMediaFocusControl.unregisterMediaButtonIntent(pi); 4136 } 4137 4138 public int registerRemoteControlClient(PendingIntent mediaIntent, 4139 IRemoteControlClient rcClient, String callingPckg) { 4140 return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg); 4141 } 4142 4143 public void unregisterRemoteControlClient(PendingIntent mediaIntent, 4144 IRemoteControlClient rcClient) { 4145 mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient); 4146 } 4147 4148 public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) { 4149 mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs); 4150 } 4151 4152 public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 4153 mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo); 4154 } 4155 4156 public int getRemoteStreamVolume() { 4157 return mMediaFocusControl.getRemoteStreamVolume(); 4158 } 4159 4160 public int getRemoteStreamMaxVolume() { 4161 return mMediaFocusControl.getRemoteStreamMaxVolume(); 4162 } 4163 4164 public void setRemoteStreamVolume(int index) { 4165 mMediaFocusControl.setRemoteStreamVolume(index); 4166 } 4167 4168 public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) { 4169 mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed); 4170 } 4171 4172 public void setPlaybackInfoForRcc(int rccId, int what, int value) { 4173 mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value); 4174 } 4175 4176 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 4177 mMediaFocusControl.dispatchMediaKeyEvent(keyEvent); 4178 } 4179 4180 public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 4181 mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent); 4182 } 4183 4184 //========================================================================================== 4185 // Audio Focus 4186 //========================================================================================== 4187 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, 4188 IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 4189 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd, 4190 clientId, callingPackageName); 4191 } 4192 4193 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) { 4194 return mMediaFocusControl.abandonAudioFocus(fd, clientId); 4195 } 4196 4197 public void unregisterAudioFocusClient(String clientId) { 4198 mMediaFocusControl.unregisterAudioFocusClient(clientId); 4199 } 4200 4201 public int getCurrentAudioFocus() { 4202 return mMediaFocusControl.getCurrentAudioFocus(); 4203 } 4204 4205 //========================================================================================== 4206 // Device orientation 4207 //========================================================================================== 4208 /** 4209 * Handles device configuration changes that may map to a change in the orientation 4210 * or orientation. 4211 * Monitoring orientation and rotation is optional, and is defined by the definition and value 4212 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties. 4213 */ 4214 private void handleConfigurationChanged(Context context) { 4215 try { 4216 // reading new orientation "safely" (i.e. under try catch) in case anything 4217 // goes wrong when obtaining resources and configuration 4218 Configuration config = context.getResources().getConfiguration(); 4219 // TODO merge rotation and orientation 4220 if (mMonitorOrientation) { 4221 int newOrientation = config.orientation; 4222 if (newOrientation != mDeviceOrientation) { 4223 mDeviceOrientation = newOrientation; 4224 setOrientationForAudioSystem(); 4225 } 4226 } 4227 if (mMonitorRotation) { 4228 int newRotation = ((WindowManager) context.getSystemService( 4229 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); 4230 if (newRotation != mDeviceRotation) { 4231 mDeviceRotation = newRotation; 4232 setRotationForAudioSystem(); 4233 } 4234 } 4235 sendMsg(mAudioHandler, 4236 MSG_CONFIGURE_SAFE_MEDIA_VOLUME, 4237 SENDMSG_REPLACE, 4238 0, 4239 0, 4240 null, 4241 0); 4242 4243 boolean cameraSoundForced = mContext.getResources().getBoolean( 4244 com.android.internal.R.bool.config_camera_sound_forced); 4245 synchronized (mSettingsLock) { 4246 synchronized (mCameraSoundForced) { 4247 if (cameraSoundForced != mCameraSoundForced) { 4248 mCameraSoundForced = cameraSoundForced; 4249 4250 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; 4251 if (cameraSoundForced) { 4252 s.setAllIndexesToMax(); 4253 mRingerModeAffectedStreams &= 4254 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 4255 } else { 4256 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]); 4257 mRingerModeAffectedStreams |= 4258 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); 4259 } 4260 // take new state into account for streams muted by ringer mode 4261 setRingerModeInt(getRingerMode(), false); 4262 4263 sendMsg(mAudioHandler, 4264 MSG_SET_FORCE_USE, 4265 SENDMSG_QUEUE, 4266 AudioSystem.FOR_SYSTEM, 4267 cameraSoundForced ? 4268 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE, 4269 null, 4270 0); 4271 4272 sendMsg(mAudioHandler, 4273 MSG_SET_ALL_VOLUMES, 4274 SENDMSG_QUEUE, 4275 0, 4276 0, 4277 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0); 4278 } 4279 } 4280 } 4281 mVolumePanel.setLayoutDirection(config.getLayoutDirection()); 4282 } catch (Exception e) { 4283 Log.e(TAG, "Error handling configuration change: ", e); 4284 } 4285 } 4286 4287 private void setOrientationForAudioSystem() { 4288 switch (mDeviceOrientation) { 4289 case Configuration.ORIENTATION_LANDSCAPE: 4290 //Log.i(TAG, "orientation is landscape"); 4291 AudioSystem.setParameters("orientation=landscape"); 4292 break; 4293 case Configuration.ORIENTATION_PORTRAIT: 4294 //Log.i(TAG, "orientation is portrait"); 4295 AudioSystem.setParameters("orientation=portrait"); 4296 break; 4297 case Configuration.ORIENTATION_SQUARE: 4298 //Log.i(TAG, "orientation is square"); 4299 AudioSystem.setParameters("orientation=square"); 4300 break; 4301 case Configuration.ORIENTATION_UNDEFINED: 4302 //Log.i(TAG, "orientation is undefined"); 4303 AudioSystem.setParameters("orientation=undefined"); 4304 break; 4305 default: 4306 Log.e(TAG, "Unknown orientation"); 4307 } 4308 } 4309 4310 private void setRotationForAudioSystem() { 4311 switch (mDeviceRotation) { 4312 case Surface.ROTATION_0: 4313 AudioSystem.setParameters("rotation=0"); 4314 break; 4315 case Surface.ROTATION_90: 4316 AudioSystem.setParameters("rotation=90"); 4317 break; 4318 case Surface.ROTATION_180: 4319 AudioSystem.setParameters("rotation=180"); 4320 break; 4321 case Surface.ROTATION_270: 4322 AudioSystem.setParameters("rotation=270"); 4323 break; 4324 default: 4325 Log.e(TAG, "Unknown device rotation"); 4326 } 4327 } 4328 4329 4330 // Handles request to override default use of A2DP for media. 4331 public void setBluetoothA2dpOnInt(boolean on) { 4332 synchronized (mBluetoothA2dpEnabledLock) { 4333 mBluetoothA2dpEnabled = on; 4334 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); 4335 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 4336 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 4337 } 4338 } 4339 4340 @Override 4341 public void setRingtonePlayer(IRingtonePlayer player) { 4342 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 4343 mRingtonePlayer = player; 4344 } 4345 4346 @Override 4347 public IRingtonePlayer getRingtonePlayer() { 4348 return mRingtonePlayer; 4349 } 4350 4351 @Override 4352 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 4353 synchronized (mCurAudioRoutes) { 4354 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes); 4355 mRoutesObservers.register(observer); 4356 return routes; 4357 } 4358 } 4359 4360 4361 //========================================================================================== 4362 // Safe media volume management. 4363 // MUSIC stream volume level is limited when headphones are connected according to safety 4364 // regulation. When the user attempts to raise the volume above the limit, a warning is 4365 // displayed and the user has to acknowlegde before the volume is actually changed. 4366 // The volume index corresponding to the limit is stored in config_safe_media_volume_index 4367 // property. Platforms with a different limit must set this property accordingly in their 4368 // overlay. 4369 //========================================================================================== 4370 4371 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones. 4372 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected 4373 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or 4374 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it 4375 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume() 4376 // (when user opts out). 4377 private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0; 4378 private final int SAFE_MEDIA_VOLUME_DISABLED = 1; 4379 private final int SAFE_MEDIA_VOLUME_INACTIVE = 2; 4380 private final int SAFE_MEDIA_VOLUME_ACTIVE = 3; 4381 private Integer mSafeMediaVolumeState; 4382 4383 private int mMcc = 0; 4384 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property 4385 private int mSafeMediaVolumeIndex; 4386 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced, 4387 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET | 4388 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 4389 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. 4390 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled 4391 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS. 4392 private int mMusicActiveMs; 4393 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours 4394 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval 4395 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed 4396 4397 private void setSafeMediaVolumeEnabled(boolean on) { 4398 synchronized (mSafeMediaVolumeState) { 4399 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) && 4400 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) { 4401 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) { 4402 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE; 4403 enforceSafeMediaVolume(); 4404 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) { 4405 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE; 4406 mMusicActiveMs = 0; 4407 sendMsg(mAudioHandler, 4408 MSG_CHECK_MUSIC_ACTIVE, 4409 SENDMSG_REPLACE, 4410 0, 4411 0, 4412 null, 4413 MUSIC_ACTIVE_POLL_PERIOD_MS); 4414 } 4415 } 4416 } 4417 } 4418 4419 private void enforceSafeMediaVolume() { 4420 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; 4421 int devices = mSafeMediaVolumeDevices; 4422 int i = 0; 4423 4424 while (devices != 0) { 4425 int device = 1 << i++; 4426 if ((device & devices) == 0) { 4427 continue; 4428 } 4429 int index = streamState.getIndex(device); 4430 if (index > mSafeMediaVolumeIndex) { 4431 streamState.setIndex(mSafeMediaVolumeIndex, device); 4432 sendMsg(mAudioHandler, 4433 MSG_SET_DEVICE_VOLUME, 4434 SENDMSG_QUEUE, 4435 device, 4436 0, 4437 streamState, 4438 0); 4439 } 4440 devices &= ~device; 4441 } 4442 } 4443 4444 private boolean checkSafeMediaVolume(int streamType, int index, int device) { 4445 synchronized (mSafeMediaVolumeState) { 4446 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) && 4447 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && 4448 ((device & mSafeMediaVolumeDevices) != 0) && 4449 (index > mSafeMediaVolumeIndex)) { 4450 return false; 4451 } 4452 return true; 4453 } 4454 } 4455 4456 public void disableSafeMediaVolume() { 4457 synchronized (mSafeMediaVolumeState) { 4458 setSafeMediaVolumeEnabled(false); 4459 if (mPendingVolumeCommand != null) { 4460 onSetStreamVolume(mPendingVolumeCommand.mStreamType, 4461 mPendingVolumeCommand.mIndex, 4462 mPendingVolumeCommand.mFlags, 4463 mPendingVolumeCommand.mDevice); 4464 mPendingVolumeCommand = null; 4465 } 4466 } 4467 } 4468 4469 4470 //========================================================================================== 4471 // Camera shutter sound policy. 4472 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter 4473 // sound is forced (sound even if the device is in silent mode) or not. This option is false by 4474 // default and can be overridden by country specific overlay in values-mccXXX/config.xml. 4475 //========================================================================================== 4476 4477 // cached value of com.android.internal.R.bool.config_camera_sound_forced 4478 private Boolean mCameraSoundForced; 4479 4480 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound 4481 public boolean isCameraSoundForced() { 4482 synchronized (mCameraSoundForced) { 4483 return mCameraSoundForced; 4484 } 4485 } 4486 4487 private static final String[] RINGER_MODE_NAMES = new String[] { 4488 "SILENT", 4489 "VIBRATE", 4490 "NORMAL" 4491 }; 4492 4493 private void dumpRingerMode(PrintWriter pw) { 4494 pw.println("\nRinger mode: "); 4495 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]); 4496 pw.print("- ringer mode affected streams = 0x"); 4497 pw.println(Integer.toHexString(mRingerModeAffectedStreams)); 4498 pw.print("- ringer mode muted streams = 0x"); 4499 pw.println(Integer.toHexString(mRingerModeMutedStreams)); 4500 } 4501 4502 @Override 4503 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 4504 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 4505 4506 mMediaFocusControl.dump(pw); 4507 dumpStreamStates(pw); 4508 dumpRingerMode(pw); 4509 pw.println("\nAudio routes:"); 4510 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); 4511 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); 4512 } 4513 4514 // Inform AudioFlinger of our device's low RAM attribute 4515 private static void readAndSetLowRamDevice() 4516 { 4517 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic()); 4518 if (status != 0) { 4519 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status); 4520 } 4521 } 4522} 4523