1 /* 2 * Copyright 2019 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 package com.android.server.audio; 17 18 import android.annotation.NonNull; 19 import android.bluetooth.BluetoothA2dp; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothHeadset; 22 import android.bluetooth.BluetoothHearingAid; 23 import android.bluetooth.BluetoothProfile; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.media.AudioManager; 28 import android.media.AudioRoutesInfo; 29 import android.media.AudioSystem; 30 import android.media.IAudioRoutesObserver; 31 import android.os.Binder; 32 import android.os.Handler; 33 import android.os.IBinder; 34 import android.os.Looper; 35 import android.os.Message; 36 import android.os.PowerManager; 37 import android.os.SystemClock; 38 import android.os.UserHandle; 39 import android.util.Log; 40 import android.util.PrintWriterPrinter; 41 42 import com.android.internal.annotations.GuardedBy; 43 44 import java.io.PrintWriter; 45 46 /** @hide */ 47 /*package*/ final class AudioDeviceBroker { 48 49 private static final String TAG = "AS.AudioDeviceBroker"; 50 51 private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s 52 53 /*package*/ static final int BTA2DP_DOCK_TIMEOUT_MS = 8000; 54 // Timeout for connection to bluetooth headset service 55 /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 56 57 private final @NonNull AudioService mAudioService; 58 private final @NonNull Context mContext; 59 60 /** Forced device usage for communications sent to AudioSystem */ 61 private int mForcedUseForComm; 62 /** 63 * Externally reported force device usage state returned by getters: always consistent 64 * with requests by setters */ 65 private int mForcedUseForCommExt; 66 67 // Manages all connected devices, only ever accessed on the message loop 68 private final AudioDeviceInventory mDeviceInventory; 69 // Manages notifications to BT service 70 private final BtHelper mBtHelper; 71 72 73 //------------------------------------------------------------------- 74 // we use a different lock than mDeviceStateLock so as not to create 75 // lock contention between enqueueing a message and handling them 76 private static final Object sLastDeviceConnectionMsgTimeLock = new Object(); 77 @GuardedBy("sLastDeviceConnectionMsgTimeLock") 78 private static long sLastDeviceConnectMsgTime = 0; 79 80 // General lock to be taken whenever the state of the audio devices is to be checked or changed 81 private final Object mDeviceStateLock = new Object(); 82 83 // Request to override default use of A2DP for media. 84 @GuardedBy("mDeviceStateLock") 85 private boolean mBluetoothA2dpEnabled; 86 87 // lock always taken when accessing AudioService.mSetModeDeathHandlers 88 // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 89 /*package*/ final Object mSetModeLock = new Object(); 90 91 //------------------------------------------------------------------- AudioDeviceBroker(@onNull Context context, @NonNull AudioService service)92 /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service) { 93 mContext = context; 94 mAudioService = service; 95 mBtHelper = new BtHelper(this); 96 mDeviceInventory = new AudioDeviceInventory(this); 97 98 init(); 99 } 100 101 /** for test purposes only, inject AudioDeviceInventory */ AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory)102 AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service, 103 @NonNull AudioDeviceInventory mockDeviceInventory) { 104 mContext = context; 105 mAudioService = service; 106 mBtHelper = new BtHelper(this); 107 mDeviceInventory = mockDeviceInventory; 108 109 init(); 110 } 111 init()112 private void init() { 113 setupMessaging(mContext); 114 115 mForcedUseForComm = AudioSystem.FORCE_NONE; 116 mForcedUseForCommExt = mForcedUseForComm; 117 } 118 getContext()119 /*package*/ Context getContext() { 120 return mContext; 121 } 122 123 //--------------------------------------------------------------------- 124 // Communication from AudioService 125 // All methods are asynchronous and never block 126 // All permission checks are done in AudioService, all incoming calls are considered "safe" 127 // All post* methods are asynchronous 128 onSystemReady()129 /*package*/ void onSystemReady() { 130 synchronized (mSetModeLock) { 131 synchronized (mDeviceStateLock) { 132 mBtHelper.onSystemReady(); 133 } 134 } 135 } 136 onAudioServerDied()137 /*package*/ void onAudioServerDied() { 138 // Restore forced usage for communications and record 139 synchronized (mDeviceStateLock) { 140 AudioSystem.setParameters( 141 "BT_SCO=" + (mForcedUseForComm == AudioSystem.FORCE_BT_SCO ? "on" : "off")); 142 onSetForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, "onAudioServerDied"); 143 onSetForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm, "onAudioServerDied"); 144 } 145 // restore devices 146 sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE); 147 } 148 setForceUse_Async(int useCase, int config, String eventSource)149 /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) { 150 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, 151 useCase, config, eventSource); 152 } 153 toggleHdmiIfConnected_Async()154 /*package*/ void toggleHdmiIfConnected_Async() { 155 sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE); 156 } 157 disconnectAllBluetoothProfiles()158 /*package*/ void disconnectAllBluetoothProfiles() { 159 synchronized (mDeviceStateLock) { 160 mBtHelper.disconnectAllBluetoothProfiles(); 161 } 162 } 163 164 /** 165 * Handle BluetoothHeadset intents where the action is one of 166 * {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or 167 * {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}. 168 * @param intent 169 */ receiveBtEvent(@onNull Intent intent)170 /*package*/ void receiveBtEvent(@NonNull Intent intent) { 171 synchronized (mSetModeLock) { 172 synchronized (mDeviceStateLock) { 173 mBtHelper.receiveBtEvent(intent); 174 } 175 } 176 } 177 setBluetoothA2dpOn_Async(boolean on, String source)178 /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { 179 synchronized (mDeviceStateLock) { 180 if (mBluetoothA2dpEnabled == on) { 181 return; 182 } 183 mBluetoothA2dpEnabled = on; 184 mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); 185 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, 186 AudioSystem.FOR_MEDIA, 187 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 188 source); 189 } 190 } 191 192 /** 193 * Turns speakerphone on/off 194 * @param on 195 * @param eventSource for logging purposes 196 * @return true if speakerphone state changed 197 */ setSpeakerphoneOn(boolean on, String eventSource)198 /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) { 199 synchronized (mDeviceStateLock) { 200 final boolean wasOn = isSpeakerphoneOn(); 201 if (on) { 202 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 203 setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource); 204 } 205 mForcedUseForComm = AudioSystem.FORCE_SPEAKER; 206 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) { 207 mForcedUseForComm = AudioSystem.FORCE_NONE; 208 } 209 210 mForcedUseForCommExt = mForcedUseForComm; 211 setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource); 212 return (wasOn != isSpeakerphoneOn()); 213 } 214 } 215 isSpeakerphoneOn()216 /*package*/ boolean isSpeakerphoneOn() { 217 synchronized (mDeviceStateLock) { 218 return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER); 219 } 220 } 221 setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state, String address, String name, String caller)222 /*package*/ void setWiredDeviceConnectionState(int type, 223 @AudioService.ConnectionState int state, String address, String name, 224 String caller) { 225 //TODO move logging here just like in setBluetooth* methods 226 synchronized (mDeviceStateLock) { 227 mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller); 228 } 229 } 230 231 private static final class BtDeviceConnectionInfo { 232 final @NonNull BluetoothDevice mDevice; 233 final @AudioService.BtProfileConnectionState int mState; 234 final int mProfile; 235 final boolean mSupprNoisy; 236 final int mVolume; 237 BtDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int vol)238 BtDeviceConnectionInfo(@NonNull BluetoothDevice device, 239 @AudioService.BtProfileConnectionState int state, 240 int profile, boolean suppressNoisyIntent, int vol) { 241 mDevice = device; 242 mState = state; 243 mProfile = profile; 244 mSupprNoisy = suppressNoisyIntent; 245 mVolume = vol; 246 } 247 248 // redefine equality op so we can match messages intended for this device 249 @Override equals(Object o)250 public boolean equals(Object o) { 251 return mDevice.equals(o); 252 } 253 } 254 255 postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)256 /*package*/ void postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent( 257 @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, 258 int profile, boolean suppressNoisyIntent, int a2dpVolume) { 259 final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile, 260 suppressNoisyIntent, a2dpVolume); 261 262 // when receiving a request to change the connection state of a device, this last request 263 // is the source of truth, so cancel all previous requests 264 removeAllA2dpConnectionEvents(device); 265 266 sendLMsgNoDelay( 267 state == BluetoothProfile.STATE_CONNECTED 268 ? MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION 269 : MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, 270 SENDMSG_QUEUE, info); 271 } 272 273 /** remove all previously scheduled connection and disconnection events for the given device */ removeAllA2dpConnectionEvents(@onNull BluetoothDevice device)274 private void removeAllA2dpConnectionEvents(@NonNull BluetoothDevice device) { 275 mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION, 276 device); 277 mBrokerHandler.removeMessages(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION, 278 device); 279 mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, 280 device); 281 mBrokerHandler.removeMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, 282 device); 283 } 284 285 private static final class HearingAidDeviceConnectionInfo { 286 final @NonNull BluetoothDevice mDevice; 287 final @AudioService.BtProfileConnectionState int mState; 288 final boolean mSupprNoisy; 289 final int mMusicDevice; 290 final @NonNull String mEventSource; 291 HearingAidDeviceConnectionInfo(@onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)292 HearingAidDeviceConnectionInfo(@NonNull BluetoothDevice device, 293 @AudioService.BtProfileConnectionState int state, 294 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { 295 mDevice = device; 296 mState = state; 297 mSupprNoisy = suppressNoisyIntent; 298 mMusicDevice = musicDevice; 299 mEventSource = eventSource; 300 } 301 } 302 postBluetoothHearingAidDeviceConnectionState( @onNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource)303 /*package*/ void postBluetoothHearingAidDeviceConnectionState( 304 @NonNull BluetoothDevice device, @AudioService.BtProfileConnectionState int state, 305 boolean suppressNoisyIntent, int musicDevice, @NonNull String eventSource) { 306 final HearingAidDeviceConnectionInfo info = new HearingAidDeviceConnectionInfo( 307 device, state, suppressNoisyIntent, musicDevice, eventSource); 308 sendLMsgNoDelay(MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info); 309 } 310 311 // never called by system components setBluetoothScoOnByApp(boolean on)312 /*package*/ void setBluetoothScoOnByApp(boolean on) { 313 synchronized (mDeviceStateLock) { 314 mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 315 } 316 } 317 isBluetoothScoOnForApp()318 /*package*/ boolean isBluetoothScoOnForApp() { 319 synchronized (mDeviceStateLock) { 320 return mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO; 321 } 322 } 323 setBluetoothScoOn(boolean on, String eventSource)324 /*package*/ void setBluetoothScoOn(boolean on, String eventSource) { 325 //Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource); 326 synchronized (mDeviceStateLock) { 327 if (on) { 328 // do not accept SCO ON if SCO audio is not connected 329 if (!mBtHelper.isBluetoothScoOn()) { 330 mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO; 331 return; 332 } 333 mForcedUseForComm = AudioSystem.FORCE_BT_SCO; 334 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) { 335 mForcedUseForComm = AudioSystem.FORCE_NONE; 336 } 337 mForcedUseForCommExt = mForcedUseForComm; 338 AudioSystem.setParameters("BT_SCO=" + (on ? "on" : "off")); 339 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, 340 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource); 341 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, 342 AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource); 343 } 344 // Un-mute ringtone stream volume 345 mAudioService.postUpdateRingerModeServiceInt(); 346 } 347 startWatchingRoutes(IAudioRoutesObserver observer)348 /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 349 synchronized (mDeviceStateLock) { 350 return mDeviceInventory.startWatchingRoutes(observer); 351 } 352 } 353 getCurAudioRoutes()354 /*package*/ AudioRoutesInfo getCurAudioRoutes() { 355 synchronized (mDeviceStateLock) { 356 return mDeviceInventory.getCurAudioRoutes(); 357 } 358 } 359 isAvrcpAbsoluteVolumeSupported()360 /*package*/ boolean isAvrcpAbsoluteVolumeSupported() { 361 synchronized (mDeviceStateLock) { 362 return mBtHelper.isAvrcpAbsoluteVolumeSupported(); 363 } 364 } 365 isBluetoothA2dpOn()366 /*package*/ boolean isBluetoothA2dpOn() { 367 synchronized (mDeviceStateLock) { 368 return mBluetoothA2dpEnabled; 369 } 370 } 371 postSetAvrcpAbsoluteVolumeIndex(int index)372 /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) { 373 sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); 374 } 375 postSetHearingAidVolumeIndex(int index, int streamType)376 /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) { 377 sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); 378 } 379 postDisconnectBluetoothSco(int exceptPid)380 /*package*/ void postDisconnectBluetoothSco(int exceptPid) { 381 sendIMsgNoDelay(MSG_I_DISCONNECT_BT_SCO, SENDMSG_REPLACE, exceptPid); 382 } 383 postBluetoothA2dpDeviceConfigChange(@onNull BluetoothDevice device)384 /*package*/ void postBluetoothA2dpDeviceConfigChange(@NonNull BluetoothDevice device) { 385 sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device); 386 } 387 388 @GuardedBy("mSetModeLock") startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, @NonNull String eventSource)389 /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode, 390 @NonNull String eventSource) { 391 synchronized (mDeviceStateLock) { 392 mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource); 393 } 394 } 395 396 @GuardedBy("mSetModeLock") stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource)397 /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) { 398 synchronized (mDeviceStateLock) { 399 mBtHelper.stopBluetoothScoForClient(cb, eventSource); 400 } 401 } 402 403 //--------------------------------------------------------------------- 404 // Communication with (to) AudioService 405 //TODO check whether the AudioService methods are candidates to move here postAccessoryPlugMediaUnmute(int device)406 /*package*/ void postAccessoryPlugMediaUnmute(int device) { 407 mAudioService.postAccessoryPlugMediaUnmute(device); 408 } 409 getVssVolumeForDevice(int streamType, int device)410 /*package*/ int getVssVolumeForDevice(int streamType, int device) { 411 return mAudioService.getVssVolumeForDevice(streamType, device); 412 } 413 getModeOwnerPid()414 /*package*/ int getModeOwnerPid() { 415 return mAudioService.getModeOwnerPid(); 416 } 417 getDeviceForStream(int streamType)418 /*package*/ int getDeviceForStream(int streamType) { 419 return mAudioService.getDeviceForStream(streamType); 420 } 421 postApplyVolumeOnDevice(int streamType, int device, String caller)422 /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) { 423 mAudioService.postApplyVolumeOnDevice(streamType, device, caller); 424 } 425 postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)426 /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, 427 String caller) { 428 mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller); 429 } 430 postObserveDevicesForAllStreams()431 /*packages*/ void postObserveDevicesForAllStreams() { 432 mAudioService.postObserveDevicesForAllStreams(); 433 } 434 isInCommunication()435 /*package*/ boolean isInCommunication() { 436 return mAudioService.isInCommunication(); 437 } 438 hasMediaDynamicPolicy()439 /*package*/ boolean hasMediaDynamicPolicy() { 440 return mAudioService.hasMediaDynamicPolicy(); 441 } 442 getContentResolver()443 /*package*/ ContentResolver getContentResolver() { 444 return mAudioService.getContentResolver(); 445 } 446 checkMusicActive(int deviceType, String caller)447 /*package*/ void checkMusicActive(int deviceType, String caller) { 448 mAudioService.checkMusicActive(deviceType, caller); 449 } 450 checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)451 /*package*/ void checkVolumeCecOnHdmiConnection( 452 @AudioService.ConnectionState int state, String caller) { 453 mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller); 454 } 455 hasAudioFocusUsers()456 /*package*/ boolean hasAudioFocusUsers() { 457 return mAudioService.hasAudioFocusUsers(); 458 } 459 460 //--------------------------------------------------------------------- 461 // Message handling on behalf of helper classes postBroadcastScoConnectionState(int state)462 /*package*/ void postBroadcastScoConnectionState(int state) { 463 sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); 464 } 465 postBroadcastBecomingNoisy()466 /*package*/ void postBroadcastBecomingNoisy() { 467 sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); 468 } 469 postA2dpSinkConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)470 /*package*/ void postA2dpSinkConnection(@AudioService.BtProfileConnectionState int state, 471 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { 472 sendILMsg(state == BluetoothA2dp.STATE_CONNECTED 473 ? MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED 474 : MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, 475 SENDMSG_QUEUE, 476 state, btDeviceInfo, delay); 477 } 478 postA2dpSourceConnection(@udioService.BtProfileConnectionState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay)479 /*package*/ void postA2dpSourceConnection(@AudioService.BtProfileConnectionState int state, 480 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo, int delay) { 481 sendILMsg(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, 482 state, btDeviceInfo, delay); 483 } 484 postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)485 /*package*/ void postSetWiredDeviceConnectionState( 486 AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) { 487 sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay); 488 } 489 postSetHearingAidConnectionState( @udioService.BtProfileConnectionState int state, @NonNull BluetoothDevice device, int delay)490 /*package*/ void postSetHearingAidConnectionState( 491 @AudioService.BtProfileConnectionState int state, 492 @NonNull BluetoothDevice device, int delay) { 493 sendILMsg(MSG_IL_SET_HEARING_AID_CONNECTION_STATE, SENDMSG_QUEUE, 494 state, 495 device, 496 delay); 497 } 498 postDisconnectA2dp()499 /*package*/ void postDisconnectA2dp() { 500 sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE); 501 } 502 postDisconnectA2dpSink()503 /*package*/ void postDisconnectA2dpSink() { 504 sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE); 505 } 506 postDisconnectHearingAid()507 /*package*/ void postDisconnectHearingAid() { 508 sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE); 509 } 510 postDisconnectHeadset()511 /*package*/ void postDisconnectHeadset() { 512 sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE); 513 } 514 postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile)515 /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) { 516 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile); 517 } 518 postBtA2dpSinkProfileConnected(BluetoothProfile profile)519 /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) { 520 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile); 521 } 522 postBtHeasetProfileConnected(BluetoothHeadset headsetProfile)523 /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) { 524 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile); 525 } 526 postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile)527 /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) { 528 sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE, 529 hearingAidProfile); 530 } 531 postScoClientDied(Object obj)532 /*package*/ void postScoClientDied(Object obj) { 533 sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj); 534 } 535 536 //--------------------------------------------------------------------- 537 // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) 538 // only call from a "handle"* method or "on"* method 539 540 // Handles request to override default use of A2DP for media. 541 //@GuardedBy("mConnectedDevices") setBluetoothA2dpOnInt(boolean on, String source)542 /*package*/ void setBluetoothA2dpOnInt(boolean on, String source) { 543 // for logging only 544 final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on) 545 .append(") from u/pid:").append(Binder.getCallingUid()).append("/") 546 .append(Binder.getCallingPid()).append(" src:").append(source).toString(); 547 548 synchronized (mDeviceStateLock) { 549 mBluetoothA2dpEnabled = on; 550 mBrokerHandler.removeMessages(MSG_IIL_SET_FORCE_BT_A2DP_USE); 551 onSetForceUse( 552 AudioSystem.FOR_MEDIA, 553 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 554 eventSource); 555 } 556 } 557 handleDeviceConnection(boolean connect, int device, String address, String deviceName)558 /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address, 559 String deviceName) { 560 synchronized (mDeviceStateLock) { 561 return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName); 562 } 563 } 564 postSetA2dpSourceConnectionState(@luetoothProfile.BtProfileState int state, @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)565 /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state, 566 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { 567 final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0; 568 sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state, 569 btDeviceInfo); 570 } 571 handleFailureToConnectToBtHeadsetService(int delay)572 /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) { 573 sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); 574 } 575 handleCancelFailureToConnectToBtHeadsetService()576 /*package*/ void handleCancelFailureToConnectToBtHeadsetService() { 577 mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 578 } 579 postReportNewRoutes()580 /*package*/ void postReportNewRoutes() { 581 sendMsgNoDelay(MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); 582 } 583 cancelA2dpDockTimeout()584 /*package*/ void cancelA2dpDockTimeout() { 585 mBrokerHandler.removeMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); 586 } 587 postA2dpActiveDeviceChange( @onNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo)588 /*package*/ void postA2dpActiveDeviceChange( 589 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) { 590 sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo); 591 } 592 hasScheduledA2dpDockTimeout()593 /*package*/ boolean hasScheduledA2dpDockTimeout() { 594 return mBrokerHandler.hasMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT); 595 } 596 597 // must be called synchronized on mConnectedDevices hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice)598 /*package*/ boolean hasScheduledA2dpSinkConnectionState(BluetoothDevice btDevice) { 599 return (mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED, 600 new BtHelper.BluetoothA2dpDeviceInfo(btDevice)) 601 || mBrokerHandler.hasMessages(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED, 602 new BtHelper.BluetoothA2dpDeviceInfo(btDevice))); 603 } 604 setA2dpDockTimeout(String address, int a2dpCodec, int delayMs)605 /*package*/ void setA2dpDockTimeout(String address, int a2dpCodec, int delayMs) { 606 sendILMsg(MSG_IL_BTA2DP_DOCK_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); 607 } 608 setAvrcpAbsoluteVolumeSupported(boolean supported)609 /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { 610 synchronized (mDeviceStateLock) { 611 mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); 612 } 613 } 614 getBluetoothA2dpEnabled()615 /*package*/ boolean getBluetoothA2dpEnabled() { 616 synchronized (mDeviceStateLock) { 617 return mBluetoothA2dpEnabled; 618 } 619 } 620 getA2dpCodec(@onNull BluetoothDevice device)621 /*package*/ int getA2dpCodec(@NonNull BluetoothDevice device) { 622 synchronized (mDeviceStateLock) { 623 return mBtHelper.getA2dpCodec(device); 624 } 625 } 626 dump(PrintWriter pw, String prefix)627 /*package*/ void dump(PrintWriter pw, String prefix) { 628 if (mBrokerHandler != null) { 629 pw.println(prefix + "Message handler (watch for unhandled messages):"); 630 mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + " "); 631 } else { 632 pw.println("Message handler is null"); 633 } 634 } 635 636 //--------------------------------------------------------------------- 637 // Internal handling of messages 638 // These methods are ALL synchronous, in response to message handling in BrokerHandler 639 // Blocking in any of those will block the message queue 640 onSetForceUse(int useCase, int config, String eventSource)641 private void onSetForceUse(int useCase, int config, String eventSource) { 642 if (useCase == AudioSystem.FOR_MEDIA) { 643 postReportNewRoutes(); 644 } 645 AudioService.sForceUseLogger.log( 646 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource)); 647 AudioSystem.setForceUse(useCase, config); 648 } 649 onSendBecomingNoisyIntent()650 private void onSendBecomingNoisyIntent() { 651 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 652 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); 653 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); 654 } 655 656 //--------------------------------------------------------------------- 657 // Message handling 658 private BrokerHandler mBrokerHandler; 659 private BrokerThread mBrokerThread; 660 private PowerManager.WakeLock mBrokerEventWakeLock; 661 setupMessaging(Context ctxt)662 private void setupMessaging(Context ctxt) { 663 final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE); 664 mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 665 "handleAudioDeviceEvent"); 666 mBrokerThread = new BrokerThread(); 667 mBrokerThread.start(); 668 waitForBrokerHandlerCreation(); 669 } 670 waitForBrokerHandlerCreation()671 private void waitForBrokerHandlerCreation() { 672 synchronized (this) { 673 while (mBrokerHandler == null) { 674 try { 675 wait(); 676 } catch (InterruptedException e) { 677 Log.e(TAG, "Interruption while waiting on BrokerHandler"); 678 } 679 } 680 } 681 } 682 683 /** Class that handles the device broker's message queue */ 684 private class BrokerThread extends Thread { BrokerThread()685 BrokerThread() { 686 super("AudioDeviceBroker"); 687 } 688 689 @Override run()690 public void run() { 691 // Set this thread up so the handler will work on it 692 Looper.prepare(); 693 694 synchronized (AudioDeviceBroker.this) { 695 mBrokerHandler = new BrokerHandler(); 696 697 // Notify that the handler has been created 698 AudioDeviceBroker.this.notify(); 699 } 700 701 Looper.loop(); 702 } 703 } 704 705 /** Class that handles the message queue */ 706 private class BrokerHandler extends Handler { 707 708 @Override handleMessage(Message msg)709 public void handleMessage(Message msg) { 710 switch (msg.what) { 711 case MSG_RESTORE_DEVICES: 712 synchronized (mDeviceStateLock) { 713 mDeviceInventory.onRestoreDevices(); 714 mBtHelper.onAudioServerDiedRestoreA2dp(); 715 } 716 break; 717 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 718 synchronized (mDeviceStateLock) { 719 mDeviceInventory.onSetWiredDeviceConnectionState( 720 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj); 721 } 722 break; 723 case MSG_I_BROADCAST_BT_CONNECTION_STATE: 724 synchronized (mDeviceStateLock) { 725 mBtHelper.onBroadcastScoConnectionState(msg.arg1); 726 } 727 break; 728 case MSG_IIL_SET_FORCE_USE: // intended fall-through 729 case MSG_IIL_SET_FORCE_BT_A2DP_USE: 730 onSetForceUse(msg.arg1, msg.arg2, (String) msg.obj); 731 break; 732 case MSG_REPORT_NEW_ROUTES: 733 synchronized (mDeviceStateLock) { 734 mDeviceInventory.onReportNewRoutes(); 735 } 736 break; 737 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 738 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 739 synchronized (mDeviceStateLock) { 740 mDeviceInventory.onSetA2dpSinkConnectionState( 741 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); 742 } 743 break; 744 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 745 synchronized (mDeviceStateLock) { 746 mDeviceInventory.onSetA2dpSourceConnectionState( 747 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); 748 } 749 break; 750 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 751 synchronized (mDeviceStateLock) { 752 mDeviceInventory.onSetHearingAidConnectionState( 753 (BluetoothDevice) msg.obj, msg.arg1, 754 mAudioService.getHearingAidStreamType()); 755 } 756 break; 757 case MSG_BT_HEADSET_CNCT_FAILED: 758 synchronized (mSetModeLock) { 759 synchronized (mDeviceStateLock) { 760 mBtHelper.resetBluetoothSco(); 761 } 762 } 763 break; 764 case MSG_IL_BTA2DP_DOCK_TIMEOUT: 765 // msg.obj == address of BTA2DP device 766 synchronized (mDeviceStateLock) { 767 mDeviceInventory.onMakeA2dpDeviceUnavailableNow((String) msg.obj, msg.arg1); 768 } 769 break; 770 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 771 final int a2dpCodec; 772 final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; 773 synchronized (mDeviceStateLock) { 774 a2dpCodec = mBtHelper.getA2dpCodec(btDevice); 775 mDeviceInventory.onBluetoothA2dpActiveDeviceChange( 776 new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec), 777 BtHelper.EVENT_DEVICE_CONFIG_CHANGE); 778 } 779 break; 780 case MSG_BROADCAST_AUDIO_BECOMING_NOISY: 781 onSendBecomingNoisyIntent(); 782 break; 783 case MSG_II_SET_HEARING_AID_VOLUME: 784 synchronized (mDeviceStateLock) { 785 mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2); 786 } 787 break; 788 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME: 789 synchronized (mDeviceStateLock) { 790 mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); 791 } 792 break; 793 case MSG_I_DISCONNECT_BT_SCO: 794 synchronized (mSetModeLock) { 795 synchronized (mDeviceStateLock) { 796 mBtHelper.disconnectBluetoothSco(msg.arg1); 797 } 798 } 799 break; 800 case MSG_L_SCOCLIENT_DIED: 801 synchronized (mSetModeLock) { 802 synchronized (mDeviceStateLock) { 803 mBtHelper.scoClientDied(msg.obj); 804 } 805 } 806 break; 807 case MSG_TOGGLE_HDMI: 808 synchronized (mDeviceStateLock) { 809 mDeviceInventory.onToggleHdmi(); 810 } 811 break; 812 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 813 synchronized (mDeviceStateLock) { 814 mDeviceInventory.onBluetoothA2dpActiveDeviceChange( 815 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, 816 BtHelper.EVENT_ACTIVE_DEVICE_CHANGE); 817 } 818 break; 819 case MSG_DISCONNECT_A2DP: 820 synchronized (mDeviceStateLock) { 821 mDeviceInventory.disconnectA2dp(); 822 } 823 break; 824 case MSG_DISCONNECT_A2DP_SINK: 825 synchronized (mDeviceStateLock) { 826 mDeviceInventory.disconnectA2dpSink(); 827 } 828 break; 829 case MSG_DISCONNECT_BT_HEARING_AID: 830 synchronized (mDeviceStateLock) { 831 mDeviceInventory.disconnectHearingAid(); 832 } 833 break; 834 case MSG_DISCONNECT_BT_HEADSET: 835 synchronized (mSetModeLock) { 836 synchronized (mDeviceStateLock) { 837 mBtHelper.disconnectHeadset(); 838 } 839 } 840 break; 841 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP: 842 synchronized (mDeviceStateLock) { 843 mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj); 844 } 845 break; 846 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK: 847 synchronized (mDeviceStateLock) { 848 mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj); 849 } 850 break; 851 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID: 852 synchronized (mDeviceStateLock) { 853 mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj); 854 } 855 break; 856 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET: 857 synchronized (mSetModeLock) { 858 synchronized (mDeviceStateLock) { 859 mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj); 860 } 861 } 862 break; 863 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: 864 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: { 865 final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj; 866 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 867 "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent " 868 + " state=" + info.mState 869 // only querying address as this is the only readily available 870 // field on the device 871 + " addr=" + info.mDevice.getAddress() 872 + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy 873 + " vol=" + info.mVolume)).printLog(TAG)); 874 synchronized (mDeviceStateLock) { 875 mDeviceInventory.setBluetoothA2dpDeviceConnectionState( 876 info.mDevice, info.mState, info.mProfile, info.mSupprNoisy, 877 AudioSystem.DEVICE_NONE, info.mVolume); 878 } 879 } break; 880 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: { 881 final HearingAidDeviceConnectionInfo info = 882 (HearingAidDeviceConnectionInfo) msg.obj; 883 AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent( 884 "setHearingAidDeviceConnectionState state=" + info.mState 885 + " addr=" + info.mDevice.getAddress() 886 + " supprNoisy=" + info.mSupprNoisy 887 + " src=" + info.mEventSource)).printLog(TAG)); 888 synchronized (mDeviceStateLock) { 889 mDeviceInventory.setBluetoothHearingAidDeviceConnectionState( 890 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); 891 } 892 } break; 893 default: 894 Log.wtf(TAG, "Invalid message " + msg.what); 895 } 896 if (isMessageHandledUnderWakelock(msg.what)) { 897 try { 898 mBrokerEventWakeLock.release(); 899 } catch (Exception e) { 900 Log.e(TAG, "Exception releasing wakelock", e); 901 } 902 } 903 } 904 } 905 906 // List of all messages. If a message has be handled under wakelock, add it to 907 // the isMessageHandledUnderWakelock(int) method 908 // Naming of msg indicates arguments, using JNI argument grammar 909 // (e.g. II indicates two int args, IL indicates int and Obj arg) 910 private static final int MSG_RESTORE_DEVICES = 1; 911 private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2; 912 private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3; 913 private static final int MSG_IIL_SET_FORCE_USE = 4; 914 private static final int MSG_IIL_SET_FORCE_BT_A2DP_USE = 5; 915 private static final int MSG_TOGGLE_HDMI = 6; 916 private static final int MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE = 7; 917 private static final int MSG_IL_SET_HEARING_AID_CONNECTION_STATE = 8; 918 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; 919 private static final int MSG_IL_BTA2DP_DOCK_TIMEOUT = 10; 920 private static final int MSG_L_A2DP_DEVICE_CONFIG_CHANGE = 11; 921 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12; 922 private static final int MSG_REPORT_NEW_ROUTES = 13; 923 private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; 924 private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; 925 private static final int MSG_I_DISCONNECT_BT_SCO = 16; 926 private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18; 927 private static final int MSG_DISCONNECT_A2DP = 19; 928 private static final int MSG_DISCONNECT_A2DP_SINK = 20; 929 private static final int MSG_DISCONNECT_BT_HEARING_AID = 21; 930 private static final int MSG_DISCONNECT_BT_HEADSET = 22; 931 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23; 932 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24; 933 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25; 934 private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26; 935 private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED = 27; 936 private static final int MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED = 28; 937 // process external command to (dis)connect an A2DP device 938 private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION = 29; 939 private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION = 30; 940 // process external command to (dis)connect a hearing aid device 941 private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; 942 // a ScoClient died in BtHelper 943 private static final int MSG_L_SCOCLIENT_DIED = 32; 944 945 isMessageHandledUnderWakelock(int msgId)946 private static boolean isMessageHandledUnderWakelock(int msgId) { 947 switch(msgId) { 948 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 949 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 950 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 951 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 952 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 953 case MSG_IL_BTA2DP_DOCK_TIMEOUT: 954 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 955 case MSG_TOGGLE_HDMI: 956 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 957 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: 958 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: 959 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: 960 return true; 961 default: 962 return false; 963 } 964 } 965 966 // Message helper methods 967 968 // sendMsg() flags 969 /** If the msg is already queued, replace it with this one. */ 970 private static final int SENDMSG_REPLACE = 0; 971 /** If the msg is already queued, ignore this one and leave the old. */ 972 private static final int SENDMSG_NOOP = 1; 973 /** If the msg is already queued, queue this one and leave the old. */ 974 private static final int SENDMSG_QUEUE = 2; 975 sendMsg(int msg, int existingMsgPolicy, int delay)976 private void sendMsg(int msg, int existingMsgPolicy, int delay) { 977 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay); 978 } 979 sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)980 private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) { 981 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay); 982 } 983 sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)984 private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) { 985 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay); 986 } 987 sendIMsg(int msg, int existingMsgPolicy, int arg, int delay)988 private void sendIMsg(int msg, int existingMsgPolicy, int arg, int delay) { 989 sendIILMsg(msg, existingMsgPolicy, arg, 0, null, delay); 990 } 991 sendMsgNoDelay(int msg, int existingMsgPolicy)992 private void sendMsgNoDelay(int msg, int existingMsgPolicy) { 993 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0); 994 } 995 sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)996 private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) { 997 sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0); 998 } 999 sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)1000 private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) { 1001 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0); 1002 } 1003 sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)1004 private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) { 1005 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0); 1006 } 1007 sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)1008 private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) { 1009 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0); 1010 } 1011 sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)1012 private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) { 1013 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0); 1014 } 1015 sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)1016 private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, 1017 int delay) { 1018 if (existingMsgPolicy == SENDMSG_REPLACE) { 1019 mBrokerHandler.removeMessages(msg); 1020 } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) { 1021 return; 1022 } 1023 1024 if (isMessageHandledUnderWakelock(msg)) { 1025 final long identity = Binder.clearCallingIdentity(); 1026 try { 1027 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS); 1028 } catch (Exception e) { 1029 Log.e(TAG, "Exception acquiring wakelock", e); 1030 } 1031 Binder.restoreCallingIdentity(identity); 1032 } 1033 1034 synchronized (sLastDeviceConnectionMsgTimeLock) { 1035 long time = SystemClock.uptimeMillis() + delay; 1036 1037 switch (msg) { 1038 case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: 1039 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED: 1040 case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED: 1041 case MSG_IL_SET_HEARING_AID_CONNECTION_STATE: 1042 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 1043 case MSG_IL_BTA2DP_DOCK_TIMEOUT: 1044 case MSG_L_A2DP_DEVICE_CONFIG_CHANGE: 1045 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE: 1046 if (sLastDeviceConnectMsgTime >= time) { 1047 // add a little delay to make sure messages are ordered as expected 1048 time = sLastDeviceConnectMsgTime + 30; 1049 } 1050 sLastDeviceConnectMsgTime = time; 1051 break; 1052 default: 1053 break; 1054 } 1055 1056 mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), 1057 time); 1058 } 1059 } 1060 1061 //------------------------------------------------------------- 1062 // internal utilities sendBroadcastToAll(Intent intent)1063 private void sendBroadcastToAll(Intent intent) { 1064 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1065 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 1066 final long ident = Binder.clearCallingIdentity(); 1067 try { 1068 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1069 } finally { 1070 Binder.restoreCallingIdentity(ident); 1071 } 1072 } 1073 } 1074