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 static android.media.audio.Flags.scoManagedByAudio; 19 import static android.media.AudioSystem.DEVICE_IN_ALL_SCO_SET; 20 import static android.media.AudioSystem.DEVICE_IN_BLE_HEADSET; 21 import static android.media.AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 22 import static android.media.AudioSystem.DEVICE_IN_USB_HEADSET; 23 import static android.media.AudioSystem.DEVICE_IN_WIRED_HEADSET; 24 import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO_SET; 25 import static android.media.AudioSystem.DEVICE_OUT_BLE_HEADSET; 26 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 27 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 28 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 29 import static android.media.AudioSystem.DEVICE_OUT_BUS; 30 import static android.media.AudioSystem.DEVICE_OUT_EARPIECE; 31 import static android.media.AudioSystem.DEVICE_OUT_SPEAKER; 32 import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET; 33 import static android.media.AudioSystem.DEVICE_OUT_WIRED_HEADSET; 34 import static android.media.AudioSystem.isBluetoothScoOutDevice; 35 36 import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; 37 import static com.android.media.audio.Flags.optimizeBtDeviceSwitch; 38 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_HEADSET; 39 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER; 40 import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_SCO; 41 42 import android.annotation.NonNull; 43 import android.annotation.Nullable; 44 import android.app.compat.CompatChanges; 45 import android.bluetooth.BluetoothDevice; 46 import android.bluetooth.BluetoothHeadset; 47 import android.bluetooth.BluetoothProfile; 48 import android.compat.annotation.ChangeId; 49 import android.compat.annotation.EnabledSince; 50 import android.content.AttributionSource; 51 import android.content.ContentResolver; 52 import android.content.Context; 53 import android.content.Intent; 54 import android.media.AudioAttributes; 55 import android.media.AudioDeviceAttributes; 56 import android.media.AudioDeviceInfo; 57 import android.media.AudioManager; 58 import android.media.AudioManager.AudioDeviceCategory; 59 import android.media.AudioPlaybackConfiguration; 60 import android.media.AudioRecordingConfiguration; 61 import android.media.AudioRoutesInfo; 62 import android.media.AudioSystem; 63 import android.media.BluetoothProfileConnectionInfo; 64 import android.media.IAudioRoutesObserver; 65 import android.media.ICapturePresetDevicesRoleDispatcher; 66 import android.media.ICommunicationDeviceDispatcher; 67 import android.media.IStrategyNonDefaultDevicesDispatcher; 68 import android.media.IStrategyPreferredDevicesDispatcher; 69 import android.media.MediaMetrics; 70 import android.media.audiopolicy.AudioProductStrategy; 71 import android.os.Binder; 72 import android.os.Handler; 73 import android.os.IBinder; 74 import android.os.Looper; 75 import android.os.Message; 76 import android.os.PowerManager; 77 import android.os.Process; 78 import android.os.RemoteCallbackList; 79 import android.os.RemoteException; 80 import android.os.SystemClock; 81 import android.os.UserHandle; 82 import android.provider.Settings; 83 import android.sysprop.BluetoothProperties; 84 import android.text.TextUtils; 85 import android.util.Log; 86 import android.util.Pair; 87 import android.util.PrintWriterPrinter; 88 89 import com.android.internal.annotations.GuardedBy; 90 import com.android.server.audio.AudioService.BtCommDeviceActiveType; 91 import com.android.server.utils.EventLogger; 92 93 import java.io.PrintWriter; 94 import java.util.ArrayList; 95 import java.util.Arrays; 96 import java.util.Collection; 97 import java.util.HashMap; 98 import java.util.HashSet; 99 import java.util.LinkedList; 100 import java.util.List; 101 import java.util.Map; 102 import java.util.NoSuchElementException; 103 import java.util.Objects; 104 import java.util.Set; 105 import java.util.concurrent.atomic.AtomicBoolean; 106 107 /** 108 * @hide 109 * (non final for mocking/spying) 110 */ 111 public class AudioDeviceBroker { 112 113 private static final String TAG = "AS.AudioDeviceBroker"; 114 115 private static final long BROKER_WAKELOCK_TIMEOUT_MS = 5000; //5s 116 117 /*package*/ static final int BTA2DP_DOCK_TIMEOUT_MS = 8000; 118 // Timeout for connection to bluetooth headset service 119 /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 120 121 // Delay before checking it music should be unmuted after processing an A2DP message 122 private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 100; 123 124 private final @NonNull AudioService mAudioService; 125 private final @NonNull Context mContext; 126 private final @NonNull AudioSystemAdapter mAudioSystem; 127 128 /** ID for Communication strategy retrieved form audio policy manager */ 129 /*package*/ int mCommunicationStrategyId = -1; 130 131 /** ID for Accessibility strategy retrieved form audio policy manager */ 132 private int mAccessibilityStrategyId = -1; 133 134 135 /** Active communication device reported by audio policy manager */ 136 /*package*/ AudioDeviceInfo mActiveCommunicationDevice; 137 /** Last preferred device set for communication strategy */ 138 private AudioDeviceAttributes mPreferredCommunicationDevice; 139 140 // Manages all connected devices, only ever accessed on the message loop 141 private final AudioDeviceInventory mDeviceInventory; 142 // Manages notifications to BT service 143 private final BtHelper mBtHelper; 144 // Adapter for system_server-reserved operations 145 private final SystemServerAdapter mSystemServer; 146 147 148 //------------------------------------------------------------------- 149 // we use a different lock than mDeviceStateLock so as not to create 150 // lock contention between enqueueing a message and handling them 151 private static final Object sLastDeviceConnectionMsgTimeLock = new Object(); 152 @GuardedBy("sLastDeviceConnectionMsgTimeLock") 153 private static long sLastDeviceConnectMsgTime = 0; 154 155 // General lock to be taken whenever the state of the audio devices is to be checked or changed 156 private final Object mDeviceStateLock = new Object(); 157 158 // Request to override default use of A2DP for media. 159 private AtomicBoolean mBluetoothA2dpEnabled = new AtomicBoolean(false); 160 161 // lock always taken when accessing AudioService.mSetModeDeathHandlers 162 // TODO do not "share" the lock between AudioService and BtHelpr, see b/123769055 163 /*package*/ final Object mSetModeLock = new Object(); 164 165 /** AudioModeInfo contains information on current audio mode owner 166 * communicated by AudioService */ 167 /* package */ static final class AudioModeInfo { 168 /** Current audio mode */ 169 final int mMode; 170 /** PID of current audio mode owner */ 171 final int mPid; 172 /** UID of current audio mode owner */ 173 final int mUid; 174 AudioModeInfo(int mode, int pid, int uid)175 AudioModeInfo(int mode, int pid, int uid) { 176 mMode = mode; 177 mPid = pid; 178 mUid = uid; 179 } 180 181 @Override toString()182 public String toString() { 183 return "AudioModeInfo: mMode=" + AudioSystem.modeToString(mMode) 184 + ", mPid=" + mPid 185 + ", mUid=" + mUid; 186 } 187 }; 188 189 private AudioModeInfo mAudioModeOwner = new AudioModeInfo(AudioSystem.MODE_NORMAL, 0, 0); 190 191 /** 192 * Indicates that default communication device is chosen by routing rules in audio policy 193 * manager and not forced by AudioDeviceBroker. 194 */ 195 @ChangeId 196 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2) 197 public static final long USE_SET_COMMUNICATION_DEVICE = 243827847L; 198 199 /** Indicates if headset profile connection and SCO audio control use the new implementation 200 * aligned with other BT profiles. True if both the feature flag Flags.scoManagedByAudio() and 201 * the system property audio.sco.managed.by.audio are true. 202 */ 203 private final boolean mScoManagedByAudio; isScoManagedByAudio()204 /*package*/ boolean isScoManagedByAudio() { 205 return mScoManagedByAudio; 206 } 207 208 //------------------------------------------------------------------- AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioSystemAdapter audioSystem)209 /*package*/ AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service, 210 @NonNull AudioSystemAdapter audioSystem) { 211 mContext = context; 212 mAudioService = service; 213 mBtHelper = new BtHelper(this, context); 214 mDeviceInventory = new AudioDeviceInventory(this); 215 mSystemServer = SystemServerAdapter.getDefaultAdapter(mContext); 216 mAudioSystem = audioSystem; 217 mScoManagedByAudio = scoManagedByAudio() 218 && BluetoothProperties.isScoManagedByAudioEnabled().orElse(false); 219 init(); 220 } 221 222 /** for test purposes only, inject AudioDeviceInventory and adapter for operations running 223 * in system_server */ AudioDeviceBroker(@onNull Context context, @NonNull AudioService service, @NonNull AudioDeviceInventory mockDeviceInventory, @NonNull SystemServerAdapter mockSystemServer, @NonNull AudioSystemAdapter audioSystem)224 AudioDeviceBroker(@NonNull Context context, @NonNull AudioService service, 225 @NonNull AudioDeviceInventory mockDeviceInventory, 226 @NonNull SystemServerAdapter mockSystemServer, 227 @NonNull AudioSystemAdapter audioSystem) { 228 mContext = context; 229 mAudioService = service; 230 mBtHelper = new BtHelper(this, context); 231 mDeviceInventory = mockDeviceInventory; 232 mSystemServer = mockSystemServer; 233 mAudioSystem = audioSystem; 234 mScoManagedByAudio = scoManagedByAudio() 235 && BluetoothProperties.isScoManagedByAudioEnabled().orElse(false); 236 init(); 237 } 238 initRoutingStrategyIds()239 private void initRoutingStrategyIds() { 240 List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies(); 241 mCommunicationStrategyId = -1; 242 mAccessibilityStrategyId = -1; 243 for (AudioProductStrategy strategy : strategies) { 244 if (mCommunicationStrategyId == -1 245 && strategy.getAudioAttributesForLegacyStreamType( 246 AudioSystem.STREAM_VOICE_CALL) != null) { 247 mCommunicationStrategyId = strategy.getId(); 248 } 249 if (mAccessibilityStrategyId == -1 250 && strategy.getAudioAttributesForLegacyStreamType( 251 AudioSystem.STREAM_ACCESSIBILITY) != null) { 252 mAccessibilityStrategyId = strategy.getId(); 253 } 254 } 255 } 256 init()257 private void init() { 258 setupMessaging(mContext); 259 260 initAudioHalBluetoothState(); 261 initRoutingStrategyIds(); 262 mPreferredCommunicationDevice = null; 263 updateActiveCommunicationDevice(); 264 265 mSystemServer.registerUserStartedReceiver(mContext); 266 } 267 getContext()268 /*package*/ Context getContext() { 269 return mContext; 270 } 271 272 //--------------------------------------------------------------------- 273 // Communication from AudioService 274 // All methods are asynchronous and never block 275 // All permission checks are done in AudioService, all incoming calls are considered "safe" 276 // All post* methods are asynchronous 277 onSystemReady()278 /*package*/ void onSystemReady() { 279 synchronized (mSetModeLock) { 280 synchronized (mDeviceStateLock) { 281 mAudioModeOwner = mAudioService.getAudioModeOwner(); 282 mBtHelper.onSystemReady(); 283 } 284 } 285 } 286 onAudioServerDied()287 /*package*/ void onAudioServerDied() { 288 // restore devices 289 sendMsgNoDelay(MSG_RESTORE_DEVICES, SENDMSG_REPLACE); 290 } 291 setForceUse_Async(int useCase, int config, String eventSource)292 /*package*/ void setForceUse_Async(int useCase, int config, String eventSource) { 293 sendIILMsgNoDelay(MSG_IIL_SET_FORCE_USE, SENDMSG_QUEUE, 294 useCase, config, eventSource); 295 } 296 toggleHdmiIfConnected_Async()297 /*package*/ void toggleHdmiIfConnected_Async() { 298 sendMsgNoDelay(MSG_TOGGLE_HDMI, SENDMSG_QUEUE); 299 } 300 301 /** 302 * Handle BluetoothHeadset intents where the action is one of 303 * {@link BluetoothHeadset#ACTION_ACTIVE_DEVICE_CHANGED} or 304 * {@link BluetoothHeadset#ACTION_AUDIO_STATE_CHANGED}. 305 * @param intent the Intent received from BT service 306 */ onReceiveBtEvent(@onNull Intent intent)307 private void onReceiveBtEvent(@NonNull Intent intent) { 308 mBtHelper.onReceiveBtEvent(intent); 309 } 310 311 @GuardedBy("mDeviceStateLock") onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch)312 /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) { 313 mBtHelper.onSetBtScoActiveDevice(btDevice, deviceSwitch); 314 } 315 setBluetoothA2dpOn_Async(boolean on, String source)316 /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { 317 boolean wasOn = mBluetoothA2dpEnabled.getAndSet(on); 318 // do not mute music if we do not anticipate a change in A2DP ON state 319 sendLMsgNoDelay(wasOn == on 320 ? MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE : MSG_L_SET_FORCE_BT_A2DP_USE, 321 SENDMSG_REPLACE, source); 322 } 323 324 /** 325 * Turns speakerphone on/off 326 * @param on true to enable speakerphone 327 * @param eventSource for logging purposes 328 */ setSpeakerphoneOn(IBinder cb, @NonNull AttributionSource attributionSource, boolean on, boolean isPrivileged, String eventSource)329 /*package*/ void setSpeakerphoneOn(IBinder cb, @NonNull AttributionSource attributionSource, 330 boolean on, boolean isPrivileged, String eventSource) { 331 if (AudioService.DEBUG_COMM_RTE) { 332 Log.v(TAG, "setSpeakerphoneOn, on: " + on + " uid: " + attributionSource.getUid()); 333 } 334 postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource, 335 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, ""), 336 on, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged)); 337 } 338 339 private static final long SET_COMMUNICATION_DEVICE_TIMEOUT_MS = 3000; 340 341 /** synchronization for setCommunicationDevice() and getCommunicationDevice */ 342 private final Object mCommunicationDeviceLock = new Object(); 343 @GuardedBy("mCommunicationDeviceLock") 344 private int mCommunicationDeviceUpdateCount = 0; 345 346 /** 347 * Select device for use for communication use cases. 348 * @param cb Client binder for death detection 349 * @param uid Client uid 350 * @param device Device selected or null to unselect. 351 * @param eventSource for logging purposes 352 * @return false if there is no device and no communication client 353 */ setCommunicationDevice(IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceInfo device, boolean isPrivileged, String eventSource)354 /*package*/ boolean setCommunicationDevice(IBinder cb, 355 @NonNull AttributionSource attributionSource, AudioDeviceInfo device, 356 boolean isPrivileged, String eventSource) { 357 if (AudioService.DEBUG_COMM_RTE) { 358 Log.v(TAG, "setCommunicationDevice, device: " + device 359 + ", uid: " + attributionSource.getUid()); 360 } 361 362 if (device == null) { 363 synchronized (mDeviceStateLock) { 364 CommunicationRouteClient client = 365 getCommunicationRouteClientForUid(attributionSource.getUid()); 366 if (client == null) { 367 return false; 368 } 369 } 370 } 371 synchronized (mCommunicationDeviceLock) { 372 mCommunicationDeviceUpdateCount++; 373 AudioDeviceAttributes deviceAttr = 374 (device != null) ? new AudioDeviceAttributes(device) : null; 375 CommunicationDeviceInfo deviceInfo = 376 new CommunicationDeviceInfo(cb, attributionSource, deviceAttr, 377 device != null, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged); 378 postSetCommunicationDeviceForClient(deviceInfo); 379 } 380 return true; 381 } 382 383 /** 384 * Sets or resets the communication device for matching client. If no client matches and the 385 * request is to reset for a given device (deviceInfo.mOn == false), the method is a noop. 386 * @param deviceInfo information on the device and requester {@link #CommunicationDeviceInfo} 387 */ 388 @GuardedBy("mDeviceStateLock") onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo)389 /*package*/ void onSetCommunicationDeviceForClient(CommunicationDeviceInfo deviceInfo) { 390 if (AudioService.DEBUG_COMM_RTE) { 391 Log.v(TAG, "onSetCommunicationDeviceForClient: " + deviceInfo); 392 } 393 if (!deviceInfo.mOn) { 394 CommunicationRouteClient client = 395 getCommunicationRouteClientForUid(deviceInfo.mAttributionSource.getUid()); 396 if (client == null || (deviceInfo.mDevice != null 397 && !deviceInfo.mDevice.equals(client.getDevice()))) { 398 return; 399 } 400 } 401 402 AudioDeviceAttributes device = deviceInfo.mOn ? deviceInfo.mDevice : null; 403 setCommunicationRouteForClient(deviceInfo.mCb, deviceInfo.mAttributionSource, 404 device, deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, 405 deviceInfo.mEventSource); 406 } 407 408 /** 409 * Indicates if a Bluetooth SCO activation request owner is controlling 410 * the SCO audio state itself or not. 411 * @param attributionSource the AttributionSource of the SCO request owner app 412 * @return true if we should control SCO audio state, false otherwise 413 */ shouldStartScoForAttributionSource(AttributionSource attributionSource)414 private boolean shouldStartScoForAttributionSource(AttributionSource attributionSource) { 415 if (attributionSource == null) { 416 return true; 417 } 418 int uid = attributionSource.getUid(); 419 return !(UserHandle.isSameApp(uid, Process.BLUETOOTH_UID) 420 || UserHandle.isSameApp(uid, Process.PHONE_UID) 421 || (UserHandle.isSameApp(uid, Process.SYSTEM_UID) 422 && "com.android.server.telecom".equals(attributionSource.getPackageName()))); 423 } 424 425 @GuardedBy("mDeviceStateLock") setCommunicationRouteForClient( IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, int scoAudioMode, boolean isPrivileged, String eventSource)426 /*package*/ void setCommunicationRouteForClient( 427 IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, 428 int scoAudioMode, boolean isPrivileged, String eventSource) { 429 if (AudioService.DEBUG_COMM_RTE) { 430 Log.v(TAG, "setCommunicationRouteForClient: device: " + device 431 + ", eventSource: " + eventSource); 432 } 433 AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( 434 "setCommunicationRouteForClient for uid: " 435 + attributionSource.getUid() 436 + " device: " + device + " isPrivileged: " + isPrivileged 437 + " from API: " + eventSource)).printLog(TAG)); 438 439 final AttributionSource previousBtScoRequesterAS = 440 bluetoothScoRequestOwnerAttributionSource(); 441 CommunicationRouteClient client; 442 443 // Save previous client route in case of failure to start BT SCO audio 444 AudioDeviceAttributes prevClientDevice = null; 445 boolean prevPrivileged = false; 446 client = getCommunicationRouteClientForUid(attributionSource.getUid()); 447 if (client != null) { 448 prevClientDevice = client.getDevice(); 449 prevPrivileged = client.isPrivileged(); 450 } 451 452 if (device != null) { 453 client = addCommunicationRouteClient(cb, attributionSource, device, isPrivileged); 454 if (client == null) { 455 Log.w(TAG, "setCommunicationRouteForClient: could not add client for uid: " 456 + attributionSource.getUid() + " and device: " + device); 457 } 458 } else { 459 client = removeCommunicationRouteClient(cb, true); 460 } 461 if (client == null) { 462 return; 463 } 464 final AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource(); 465 final boolean isBtScoRequested = btScoRequesterAS != null; 466 final boolean wasBtScoRequested = previousBtScoRequesterAS != null; 467 468 if (mScoManagedByAudio) { 469 if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive() 470 || !mBtHelper.isBluetoothScoRequestedInternally())) { 471 boolean scoStarted = false; 472 if (shouldStartScoForAttributionSource(btScoRequesterAS)) { 473 scoStarted = mBtHelper.startBluetoothSco(scoAudioMode, eventSource); 474 if (!scoStarted) { 475 Log.w(TAG, "setCommunicationRouteForClient: " 476 + "failure to start BT SCO for uid: " + attributionSource.getUid()); 477 // clean up or restore previous client selection 478 if (prevClientDevice != null) { 479 addCommunicationRouteClient(cb, attributionSource, 480 prevClientDevice, prevPrivileged); 481 } else { 482 removeCommunicationRouteClient(cb, true); 483 } 484 postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 485 } 486 } else { 487 scoStarted = true; 488 } 489 if (scoStarted) { 490 setBluetoothScoOn(true, "setCommunicationRouteForClient"); 491 } 492 } else if (!isBtScoRequested && wasBtScoRequested) { 493 if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) { 494 mBtHelper.stopBluetoothSco(eventSource); 495 } 496 setBluetoothScoOn(false, "setCommunicationRouteForClient"); 497 } 498 } else { 499 if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive() 500 || !mBtHelper.isBluetoothScoRequestedInternally())) { 501 if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) { 502 Log.w(TAG, "setCommunicationRouteForClient: failure to start BT SCO for uid: " 503 + attributionSource.getUid()); 504 // clean up or restore previous client selection 505 if (prevClientDevice != null) { 506 addCommunicationRouteClient(cb, attributionSource, 507 prevClientDevice, prevPrivileged); 508 } else { 509 removeCommunicationRouteClient(cb, true); 510 } 511 postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 512 } 513 } else if (!isBtScoRequested && wasBtScoRequested) { 514 mBtHelper.stopBluetoothSco(eventSource); 515 } 516 } 517 // In BT classic for communication, the device changes from a2dp to sco device, 518 // but for LE Audio or Hearing Aid it stays the same and we must trigger the proper 519 // stream volume alignment. 520 mAudioService.postUpdateContextualVolumes(); 521 522 updateCommunicationRoute(eventSource); 523 } 524 525 /** 526 * Returns the communication client with the highest priority: 527 * - 1) the client which is currently also controlling the audio mode 528 * - 2) the first client in the stack if there is no audio mode owner 529 * - 3) no client otherwise 530 * @return CommunicationRouteClient the client driving the communication use case routing. 531 */ 532 @GuardedBy("mDeviceStateLock") topCommunicationRouteClient()533 private CommunicationRouteClient topCommunicationRouteClient() { 534 for (CommunicationRouteClient crc : mCommunicationRouteClients) { 535 if (crc.getUid() == mAudioModeOwner.mUid && !crc.isDisabled()) { 536 return crc; 537 } 538 } 539 if (!mCommunicationRouteClients.isEmpty() && mAudioModeOwner.mPid == 0 540 && mCommunicationRouteClients.get(0).isActive()) { 541 return mCommunicationRouteClients.get(0); 542 } 543 return null; 544 } 545 546 /** 547 * Returns the device currently requested for communication use case. 548 * Use the device requested by the communication route client selected by 549 * {@link #topCommunicationRouteClient()} if any or none otherwise. 550 * @return AudioDeviceAttributes the requested device for communication. 551 */ 552 @GuardedBy("mDeviceStateLock") requestedCommunicationDevice()553 private AudioDeviceAttributes requestedCommunicationDevice() { 554 CommunicationRouteClient crc = topCommunicationRouteClient(); 555 AudioDeviceAttributes device = crc != null ? crc.getDevice() : null; 556 if (AudioService.DEBUG_COMM_RTE) { 557 Log.v(TAG, "requestedCommunicationDevice: " 558 + device + " mAudioModeOwner: " + mAudioModeOwner.toString()); 559 } 560 return device; 561 } 562 563 private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = { 564 AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, 565 AudioDeviceInfo.TYPE_BLUETOOTH_SCO, 566 AudioDeviceInfo.TYPE_WIRED_HEADSET, 567 AudioDeviceInfo.TYPE_USB_HEADSET, 568 AudioDeviceInfo.TYPE_BUILTIN_EARPIECE, 569 AudioDeviceInfo.TYPE_WIRED_HEADPHONES, 570 AudioDeviceInfo.TYPE_HEARING_AID, 571 AudioDeviceInfo.TYPE_BLE_HEADSET, 572 AudioDeviceInfo.TYPE_USB_DEVICE, 573 AudioDeviceInfo.TYPE_BLE_SPEAKER, 574 AudioDeviceInfo.TYPE_LINE_ANALOG, 575 AudioDeviceInfo.TYPE_HDMI, 576 AudioDeviceInfo.TYPE_AUX_LINE, 577 AudioDeviceInfo.TYPE_BUS 578 }; 579 isValidCommunicationDevice(@onNull AudioDeviceInfo device)580 /*package */ static boolean isValidCommunicationDevice(@NonNull AudioDeviceInfo device) { 581 Objects.requireNonNull(device, "device must not be null"); 582 return device.isSink() && isValidCommunicationDeviceType(device.getType()); 583 } 584 isValidCommunicationDeviceType( @udioDeviceInfo.AudioDeviceType int deviceType)585 private static boolean isValidCommunicationDeviceType( 586 @AudioDeviceInfo.AudioDeviceType int deviceType) { 587 for (int type : VALID_COMMUNICATION_DEVICE_TYPES) { 588 if (deviceType == type) { 589 return true; 590 } 591 } 592 return false; 593 } 594 595 596 // check playback or record activity after 6 seconds for UIDs 597 private static final int CHECK_CLIENT_STATE_DELAY_MS = 6000; 598 599 /*package */ postCheckCommunicationRouteClientState(int uid, boolean wasActive, int delay)600 void postCheckCommunicationRouteClientState(int uid, boolean wasActive, int delay) { 601 CommunicationRouteClient client = getCommunicationRouteClientForUid(uid); 602 if (client != null) { 603 sendMsgForCheckClientState(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE, 604 SENDMSG_REPLACE, 605 uid, 606 wasActive ? 1 : 0, 607 client, 608 delay); 609 } 610 } 611 612 @GuardedBy("mDeviceStateLock") onCheckCommunicationRouteClientState(int uid, boolean wasActive)613 void onCheckCommunicationRouteClientState(int uid, boolean wasActive) { 614 CommunicationRouteClient client = getCommunicationRouteClientForUid(uid); 615 if (client == null) { 616 return; 617 } 618 updateCommunicationRouteClientState(client, wasActive); 619 } 620 621 @GuardedBy("mDeviceStateLock") updateCommunicationRouteClientState( CommunicationRouteClient client, boolean wasActive)622 /*package*/ void updateCommunicationRouteClientState( 623 CommunicationRouteClient client, boolean wasActive) { 624 client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid())); 625 client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid())); 626 if (wasActive != client.isActive()) { 627 postUpdateCommunicationRouteClient(wasActive ? 628 client.getAttributionSource() : null, 629 "updateCommunicationRouteClientState"); 630 } 631 } 632 633 @GuardedBy("mDeviceStateLock") setForceCommunicationClientStateAndDelayedCheck( CommunicationRouteClient client, boolean forcePlaybackActive, boolean forceRecordingActive)634 /*package*/ void setForceCommunicationClientStateAndDelayedCheck( 635 CommunicationRouteClient client, 636 boolean forcePlaybackActive, 637 boolean forceRecordingActive) { 638 if (client == null) { 639 return; 640 } 641 if (forcePlaybackActive) { 642 client.setPlaybackActive(true); 643 } 644 if (forceRecordingActive) { 645 client.setRecordingActive(true); 646 } 647 postCheckCommunicationRouteClientState( 648 client.getUid(), client.isActive(), CHECK_CLIENT_STATE_DELAY_MS); 649 } 650 getAvailableCommunicationDevices()651 /* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() { 652 ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>(); 653 AudioDeviceInfo[] allDevices = 654 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS); 655 for (AudioDeviceInfo device : allDevices) { 656 if (isValidCommunicationDevice(device)) { 657 commDevices.add(device); 658 } 659 } 660 return commDevices; 661 } 662 getCommunicationDeviceOfType(int type)663 private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) { 664 return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type) 665 .findFirst().orElse(null); 666 } 667 668 /** 669 * Returns the device currently requested for communication use case. 670 * @return AudioDeviceInfo the requested device for communication. 671 */ getCommunicationDevice()672 /* package */ AudioDeviceInfo getCommunicationDevice() { 673 synchronized (mCommunicationDeviceLock) { 674 final long start = System.currentTimeMillis(); 675 long elapsed = 0; 676 while (mCommunicationDeviceUpdateCount > 0) { 677 try { 678 mCommunicationDeviceLock.wait( 679 SET_COMMUNICATION_DEVICE_TIMEOUT_MS - elapsed); 680 } catch (InterruptedException e) { 681 Log.w(TAG, "Interrupted while waiting for communication device update."); 682 } 683 elapsed = System.currentTimeMillis() - start; 684 if (elapsed >= SET_COMMUNICATION_DEVICE_TIMEOUT_MS) { 685 Log.e(TAG, "Timeout waiting for communication device update."); 686 // reset counter to avoid sticky out of sync condition 687 mCommunicationDeviceUpdateCount = 0; 688 break; 689 } 690 } 691 } 692 synchronized (mDeviceStateLock) { 693 return getCommunicationDeviceInt(); 694 } 695 } 696 697 @GuardedBy("mDeviceStateLock") getCommunicationDeviceInt()698 private AudioDeviceInfo getCommunicationDeviceInt() { 699 updateActiveCommunicationDevice(); 700 AudioDeviceInfo device = mActiveCommunicationDevice; 701 // make sure we return a valid communication device (i.e. a device that is allowed by 702 // setCommunicationDevice()) for consistency. 703 if (device != null) { 704 // a digital dock is used instead of the speaker in speakerphone mode and should 705 // be reflected as such 706 if (device.getType() == AudioDeviceInfo.TYPE_DOCK) { 707 device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 708 } 709 } 710 // Try to default to earpiece when current communication device is not valid. This can 711 // happen for instance if no call is active. If no earpiece device is available take the 712 // first valid communication device 713 if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) { 714 device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE); 715 if (device == null) { 716 List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices(); 717 if (!commDevices.isEmpty()) { 718 device = commDevices.get(0); 719 } 720 } 721 } 722 return device; 723 } 724 725 /** 726 * Updates currently active communication device (mActiveCommunicationDevice). 727 */ 728 @GuardedBy("mDeviceStateLock") updateActiveCommunicationDevice()729 void updateActiveCommunicationDevice() { 730 AudioDeviceAttributes device = preferredCommunicationDevice(); 731 if (device == null) { 732 AudioAttributes attr = 733 AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType( 734 AudioSystem.STREAM_VOICE_CALL); 735 List<AudioDeviceAttributes> devices = mAudioSystem.getDevicesForAttributes( 736 attr, false /* forVolume */); 737 if (devices.isEmpty()) { 738 if (mAudioService.isPlatformVoice()) { 739 Log.w(TAG, 740 "updateActiveCommunicationDevice(): no device for phone strategy"); 741 } 742 mActiveCommunicationDevice = null; 743 return; 744 } 745 device = devices.get(0); 746 } 747 mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress( 748 device.getType(), device.getAddress()); 749 } 750 751 /** 752 * Indicates if the device which type is passed as argument is currently resquested to be used 753 * for communication. 754 * @param deviceType the device type the query applies to. 755 * @return true if this device type is requested for communication. 756 */ isDeviceRequestedForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)757 private boolean isDeviceRequestedForCommunication( 758 @AudioDeviceInfo.AudioDeviceType int deviceType) { 759 synchronized (mDeviceStateLock) { 760 AudioDeviceAttributes device = requestedCommunicationDevice(); 761 return device != null && device.getType() == deviceType; 762 } 763 } 764 765 /** 766 * Indicates if the device which type is passed as argument is currently either resquested 767 * to be used for communication or selected for an other reason (e.g bluetooth SCO audio 768 * is active for SCO device). 769 * @param deviceType the device type the query applies to. 770 * @return true if this device type is requested for communication. 771 */ isDeviceOnForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)772 private boolean isDeviceOnForCommunication( 773 @AudioDeviceInfo.AudioDeviceType int deviceType) { 774 synchronized (mDeviceStateLock) { 775 AudioDeviceAttributes device = preferredCommunicationDevice(); 776 return device != null && device.getType() == deviceType; 777 } 778 } 779 780 /** 781 * Indicates if the device which type is passed as argument is active for communication. 782 * Active means not only currently used by audio policy manager for communication strategy 783 * but also explicitly requested for use by communication strategy. 784 * @param deviceType the device type the query applies to. 785 * @return true if this device type is requested for communication. 786 */ isDeviceActiveForCommunication( @udioDeviceInfo.AudioDeviceType int deviceType)787 private boolean isDeviceActiveForCommunication( 788 @AudioDeviceInfo.AudioDeviceType int deviceType) { 789 return mActiveCommunicationDevice != null 790 && mActiveCommunicationDevice.getType() == deviceType 791 && mPreferredCommunicationDevice != null 792 && mPreferredCommunicationDevice.getType() == deviceType; 793 } 794 795 /** 796 * Indicates if preferred route selection for communication is speakerphone. 797 * @return true if speakerphone is active, false otherwise. 798 */ isSpeakerphoneOn()799 /*package*/ boolean isSpeakerphoneOn() { 800 return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 801 } 802 isSpeakerphoneActive()803 private boolean isSpeakerphoneActive() { 804 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER); 805 } 806 807 /** 808 * Helper method on top of isDeviceRequestedForCommunication() indicating if 809 * Bluetooth SCO ON is currently requested or not. 810 * @return true if Bluetooth SCO ON is requested, false otherwise. 811 */ isBluetoothScoRequested()812 /*package*/ boolean isBluetoothScoRequested() { 813 return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 814 } 815 816 /** 817 * Helper method on top of isBluetoothScoRequested() returning the Attribution Source of the 818 * BT SCO route request owner or null if SCO is not requested. 819 * @return the AttributionSource of the BT SCO route request owner of null. 820 */ 821 @GuardedBy("mDeviceStateLock") bluetoothScoRequestOwnerAttributionSource()822 /*package*/ @Nullable AttributionSource bluetoothScoRequestOwnerAttributionSource() { 823 if (!isBluetoothScoRequested()) { 824 return null; 825 } 826 CommunicationRouteClient crc = topCommunicationRouteClient(); 827 if (crc == null) { 828 return null; 829 } 830 return crc.getAttributionSource(); 831 } 832 safeUidFromAttributionSource(AttributionSource attributionSource)833 private static int safeUidFromAttributionSource(AttributionSource attributionSource) { 834 return (attributionSource != null) ? attributionSource.getUid() : -1; 835 } 836 837 /** 838 * Helper method on top of isDeviceRequestedForCommunication() indicating if 839 * Bluetooth LE Audio communication device is currently requested or not. 840 * @return true if Bluetooth LE Audio device is requested, false otherwise. 841 */ isBluetoothLeAudioRequested()842 /*package*/ boolean isBluetoothLeAudioRequested() { 843 return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET) 844 || isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER); 845 } 846 847 /** 848 * Indicates if preferred route selection for communication is Bluetooth SCO. 849 * @return true if Bluetooth SCO is preferred , false otherwise. 850 */ isBluetoothScoOn()851 /*package*/ boolean isBluetoothScoOn() { 852 return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 853 } 854 isBluetoothScoActive()855 private boolean isBluetoothScoActive() { 856 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO); 857 } 858 isBluetoothBleHeadsetActive()859 private boolean isBluetoothBleHeadsetActive() { 860 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_HEADSET); 861 } 862 isBluetoothBleSpeakerActive()863 private boolean isBluetoothBleSpeakerActive() { 864 return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLE_SPEAKER); 865 } 866 isDeviceConnected(@onNull AudioDeviceAttributes device)867 /*package*/ boolean isDeviceConnected(@NonNull AudioDeviceAttributes device) { 868 synchronized (mDeviceStateLock) { 869 return mDeviceInventory.isDeviceConnected(device); 870 } 871 } 872 setWiredDeviceConnectionState(AudioDeviceAttributes attributes, @AudioService.ConnectionState int state, String caller)873 /*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, 874 @AudioService.ConnectionState int state, String caller) { 875 //TODO move logging here just like in setBluetooth* methods 876 synchronized (mDeviceStateLock) { 877 mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller); 878 } 879 } 880 setTestDeviceConnectionState(@onNull AudioDeviceAttributes device, @AudioService.ConnectionState int state)881 /*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, 882 @AudioService.ConnectionState int state) { 883 synchronized (mDeviceStateLock) { 884 mDeviceInventory.setTestDeviceConnectionState(device, state); 885 } 886 } 887 888 /*package*/ static final class BleVolumeInfo { 889 final int mIndex; 890 final int mMaxIndex; 891 final int mStreamType; 892 BleVolumeInfo(int index, int maxIndex, int streamType)893 BleVolumeInfo(int index, int maxIndex, int streamType) { 894 mIndex = index; 895 mMaxIndex = maxIndex; 896 mStreamType = streamType; 897 } 898 }; 899 900 /*package*/ static final class BtDeviceChangedData { 901 final @Nullable BluetoothDevice mNewDevice; 902 final @Nullable BluetoothDevice mPreviousDevice; 903 final @NonNull BluetoothProfileConnectionInfo mInfo; 904 final @NonNull String mEventSource; 905 BtDeviceChangedData(@ullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource)906 BtDeviceChangedData(@Nullable BluetoothDevice newDevice, 907 @Nullable BluetoothDevice previousDevice, 908 @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource) { 909 mNewDevice = newDevice; 910 mPreviousDevice = previousDevice; 911 mInfo = info; 912 mEventSource = eventSource; 913 } 914 915 @Override toString()916 public String toString() { 917 return "BtDeviceChangedData profile=" + BluetoothProfile.getProfileName( 918 mInfo.getProfile()) 919 + ", switch device: [" + mPreviousDevice + "] -> [" + mNewDevice + "]"; 920 } 921 } 922 923 /*package*/ static final class BtDeviceInfo { 924 final @NonNull BluetoothDevice mDevice; 925 final @AudioService.BtProfileConnectionState int mState; 926 final @AudioService.BtProfile int mProfile; 927 final boolean mSupprNoisy; 928 final int mVolume; 929 final boolean mIsLeOutput; 930 final @NonNull String mEventSource; 931 final int mAudioSystemDevice; 932 final int mMusicDevice; 933 final boolean mIsDeviceSwitch; 934 BtDeviceInfo(@onNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state, int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec)935 BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state, 936 int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) { 937 mDevice = device; 938 mState = state; 939 mProfile = d.mInfo.getProfile(); 940 mSupprNoisy = d.mInfo.isSuppressNoisyIntent(); 941 mVolume = d.mInfo.getVolume(); 942 mIsLeOutput = d.mInfo.isLeOutput(); 943 mEventSource = d.mEventSource; 944 mAudioSystemDevice = audioDevice; 945 mMusicDevice = AudioSystem.DEVICE_NONE; 946 mIsDeviceSwitch = optimizeBtDeviceSwitch() 947 && d.mNewDevice != null && d.mPreviousDevice != null; 948 } 949 950 // constructor used by AudioDeviceBroker to search similar message BtDeviceInfo(@onNull BluetoothDevice device, int profile)951 BtDeviceInfo(@NonNull BluetoothDevice device, int profile) { 952 mDevice = device; 953 mProfile = profile; 954 mEventSource = ""; 955 mMusicDevice = AudioSystem.DEVICE_NONE; 956 mAudioSystemDevice = 0; 957 mState = 0; 958 mSupprNoisy = false; 959 mVolume = -1; 960 mIsLeOutput = false; 961 mIsDeviceSwitch = false; 962 } 963 964 // constructor used by AudioDeviceInventory when config change failed BtDeviceInfo(@onNull BluetoothDevice device, int profile, int state, int musicDevice, int audioSystemDevice)965 BtDeviceInfo(@NonNull BluetoothDevice device, int profile, int state, int musicDevice, 966 int audioSystemDevice) { 967 mDevice = device; 968 mProfile = profile; 969 mEventSource = ""; 970 mMusicDevice = musicDevice; 971 mAudioSystemDevice = audioSystemDevice; 972 mState = state; 973 mSupprNoisy = false; 974 mVolume = -1; 975 mIsLeOutput = false; 976 mIsDeviceSwitch = false; 977 } 978 BtDeviceInfo(@onNull BtDeviceInfo src, int state)979 BtDeviceInfo(@NonNull BtDeviceInfo src, int state) { 980 mDevice = src.mDevice; 981 mState = state; 982 mProfile = src.mProfile; 983 mSupprNoisy = src.mSupprNoisy; 984 mVolume = src.mVolume; 985 mIsLeOutput = src.mIsLeOutput; 986 mEventSource = src.mEventSource; 987 mAudioSystemDevice = src.mAudioSystemDevice; 988 mMusicDevice = src.mMusicDevice; 989 mIsDeviceSwitch = false; 990 } 991 992 // redefine equality op so we can match messages intended for this device 993 @Override equals(Object o)994 public boolean equals(Object o) { 995 if (o == null) { 996 return false; 997 } 998 if (this == o) { 999 return true; 1000 } 1001 if (o instanceof BtDeviceInfo) { 1002 return mProfile == ((BtDeviceInfo) o).mProfile 1003 && mDevice.equals(((BtDeviceInfo) o).mDevice); 1004 } 1005 return false; 1006 } 1007 1008 @Override hashCode()1009 public int hashCode() { 1010 // only hashing on the fields used in equals() 1011 return Objects.hash(mProfile, mDevice); 1012 } 1013 1014 @Override toString()1015 public String toString() { 1016 return "BtDeviceInfo: device=" + mDevice.toString() 1017 + " state=" + mState 1018 + " prof=" + mProfile 1019 + " supprNoisy=" + mSupprNoisy 1020 + " volume=" + mVolume 1021 + " isLeOutput=" + mIsLeOutput 1022 + " eventSource=" + mEventSource 1023 + " audioSystemDevice=" + mAudioSystemDevice 1024 + " musicDevice=" + mMusicDevice 1025 + " isDeviceSwitch=" + mIsDeviceSwitch; 1026 } 1027 } 1028 createBtDeviceInfo(@onNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state)1029 /*package*/ static BtDeviceInfo createBtDeviceInfo(@NonNull BtDeviceChangedData d, 1030 @NonNull BluetoothDevice device, int state) { 1031 int audioDevice = BtHelper.getTypeFromProfile(d.mInfo.getProfile(), d.mInfo.isLeOutput()); 1032 return new BtDeviceInfo(d, device, state, audioDevice, AudioSystem.AUDIO_FORMAT_DEFAULT); 1033 } 1034 btMediaMetricRecord(@onNull BluetoothDevice device, String state, @NonNull BtDeviceChangedData data)1035 private void btMediaMetricRecord(@NonNull BluetoothDevice device, String state, 1036 @NonNull BtDeviceChangedData data) { 1037 final String name = TextUtils.emptyIfNull(device.getName()); 1038 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR 1039 + "queueOnBluetoothActiveDeviceChanged") 1040 .set(MediaMetrics.Property.STATE, state) 1041 .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile()) 1042 .set(MediaMetrics.Property.NAME, name) 1043 .record(); 1044 } 1045 1046 /** 1047 * will block on mDeviceStateLock, which is held during an A2DP (dis) connection 1048 * not just a simple message post 1049 * @param data struct with the (dis)connection information 1050 */ queueOnBluetoothActiveDeviceChanged(@onNull BtDeviceChangedData data)1051 /*package*/ void queueOnBluetoothActiveDeviceChanged(@NonNull BtDeviceChangedData data) { 1052 if (data.mPreviousDevice != null 1053 && data.mPreviousDevice.equals(data.mNewDevice)) { 1054 final String name = TextUtils.emptyIfNull(data.mNewDevice.getName()); 1055 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR 1056 + "queueOnBluetoothActiveDeviceChanged_update") 1057 .set(MediaMetrics.Property.NAME, name) 1058 .set(MediaMetrics.Property.STATUS, data.mInfo.getProfile()) 1059 .record(); 1060 synchronized (mDeviceStateLock) { 1061 postBluetoothDeviceConfigChange(createBtDeviceInfo(data, data.mNewDevice, 1062 BluetoothProfile.STATE_CONNECTED)); 1063 } 1064 } else { 1065 synchronized (mDeviceStateLock) { 1066 if (data.mPreviousDevice != null) { 1067 btMediaMetricRecord(data.mPreviousDevice, MediaMetrics.Value.DISCONNECTED, 1068 data); 1069 sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, 1070 createBtDeviceInfo(data, data.mPreviousDevice, 1071 BluetoothProfile.STATE_DISCONNECTED)); 1072 } 1073 if (data.mNewDevice != null) { 1074 btMediaMetricRecord(data.mNewDevice, MediaMetrics.Value.CONNECTED, data); 1075 sendLMsgNoDelay(MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, 1076 createBtDeviceInfo(data, data.mNewDevice, 1077 BluetoothProfile.STATE_CONNECTED)); 1078 } 1079 } 1080 } 1081 } 1082 1083 // Lock protecting state variable related to Bluetooth audio state 1084 private final Object mBluetoothAudioStateLock = new Object(); 1085 1086 // Current Bluetooth SCO audio active state indicated by BtHelper via setBluetoothScoOn(). 1087 @GuardedBy("mBluetoothAudioStateLock") 1088 private boolean mBluetoothScoOn; 1089 // value of BT_SCO parameter currently applied to audio HAL. 1090 @GuardedBy("mBluetoothAudioStateLock") 1091 private boolean mBluetoothScoOnApplied; 1092 1093 // A2DP suspend state requested by AudioManager.setA2dpSuspended() API. 1094 @GuardedBy("mBluetoothAudioStateLock") 1095 private boolean mBluetoothA2dpSuspendedExt; 1096 // A2DP suspend state requested by AudioDeviceInventory. 1097 @GuardedBy("mBluetoothAudioStateLock") 1098 private boolean mBluetoothA2dpSuspendedInt; 1099 // value of BT_A2dpSuspendedSCO parameter currently applied to audio HAL. 1100 1101 @GuardedBy("mBluetoothAudioStateLock") 1102 private boolean mBluetoothA2dpSuspendedApplied; 1103 1104 // LE Audio suspend state requested by AudioManager.setLeAudioSuspended() API. 1105 @GuardedBy("mBluetoothAudioStateLock") 1106 private boolean mBluetoothLeSuspendedExt; 1107 // LE Audio suspend state requested by AudioDeviceInventory. 1108 @GuardedBy("mBluetoothAudioStateLock") 1109 private boolean mBluetoothLeSuspendedInt; 1110 // value of LeAudioSuspended parameter currently applied to audio HAL. 1111 @GuardedBy("mBluetoothAudioStateLock") 1112 private boolean mBluetoothLeSuspendedApplied; 1113 initAudioHalBluetoothState()1114 private void initAudioHalBluetoothState() { 1115 synchronized (mBluetoothAudioStateLock) { 1116 mBluetoothScoOnApplied = false; 1117 mBluetoothA2dpSuspendedApplied = false; 1118 mBluetoothLeSuspendedApplied = false; 1119 reapplyAudioHalBluetoothState(); 1120 } 1121 } 1122 1123 @GuardedBy("mBluetoothAudioStateLock") updateAudioHalBluetoothState()1124 private void updateAudioHalBluetoothState() { 1125 if (mBluetoothScoOn != mBluetoothScoOnApplied) { 1126 if (AudioService.DEBUG_COMM_RTE) { 1127 Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothScoOn: " 1128 + mBluetoothScoOn + ", mBluetoothScoOnApplied: " + mBluetoothScoOnApplied); 1129 } 1130 if (mBluetoothScoOn) { 1131 if (!mBluetoothA2dpSuspendedApplied) { 1132 AudioSystem.setParameters("A2dpSuspended=true"); 1133 mBluetoothA2dpSuspendedApplied = true; 1134 } 1135 if (!mBluetoothLeSuspendedApplied) { 1136 AudioSystem.setParameters("LeAudioSuspended=true"); 1137 mBluetoothLeSuspendedApplied = true; 1138 } 1139 AudioSystem.setParameters("BT_SCO=on"); 1140 } else { 1141 AudioSystem.setParameters("BT_SCO=off"); 1142 } 1143 mBluetoothScoOnApplied = mBluetoothScoOn; 1144 } 1145 if (!mBluetoothScoOnApplied) { 1146 if ((mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt) 1147 != mBluetoothA2dpSuspendedApplied) { 1148 if (AudioService.DEBUG_COMM_RTE) { 1149 Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothA2dpSuspendedExt: " 1150 + mBluetoothA2dpSuspendedExt 1151 + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt 1152 + ", mBluetoothA2dpSuspendedApplied: " 1153 + mBluetoothA2dpSuspendedApplied); 1154 } 1155 mBluetoothA2dpSuspendedApplied = 1156 mBluetoothA2dpSuspendedExt || mBluetoothA2dpSuspendedInt; 1157 if (mBluetoothA2dpSuspendedApplied) { 1158 AudioSystem.setParameters("A2dpSuspended=true"); 1159 } else { 1160 AudioSystem.setParameters("A2dpSuspended=false"); 1161 } 1162 } 1163 if ((mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt) 1164 != mBluetoothLeSuspendedApplied) { 1165 if (AudioService.DEBUG_COMM_RTE) { 1166 Log.v(TAG, "updateAudioHalBluetoothState() mBluetoothLeSuspendedExt: " 1167 + mBluetoothLeSuspendedExt 1168 + ", mBluetoothLeSuspendedInt: " + mBluetoothLeSuspendedInt 1169 + ", mBluetoothLeSuspendedApplied: " + mBluetoothLeSuspendedApplied); 1170 } 1171 mBluetoothLeSuspendedApplied = 1172 mBluetoothLeSuspendedExt || mBluetoothLeSuspendedInt; 1173 if (mBluetoothLeSuspendedApplied) { 1174 AudioSystem.setParameters("LeAudioSuspended=true"); 1175 } else { 1176 AudioSystem.setParameters("LeAudioSuspended=false"); 1177 } 1178 } 1179 } 1180 } 1181 1182 @GuardedBy("mBluetoothAudioStateLock") reapplyAudioHalBluetoothState()1183 private void reapplyAudioHalBluetoothState() { 1184 if (AudioService.DEBUG_COMM_RTE) { 1185 Log.v(TAG, "reapplyAudioHalBluetoothState() mBluetoothScoOnApplied: " 1186 + mBluetoothScoOnApplied + ", mBluetoothA2dpSuspendedApplied: " 1187 + mBluetoothA2dpSuspendedApplied + ", mBluetoothLeSuspendedApplied: " 1188 + mBluetoothLeSuspendedApplied); 1189 } 1190 // Note: the order of parameters is important. 1191 if (mBluetoothScoOnApplied) { 1192 AudioSystem.setParameters("A2dpSuspended=true"); 1193 AudioSystem.setParameters("LeAudioSuspended=true"); 1194 AudioSystem.setParameters("BT_SCO=on"); 1195 mBluetoothA2dpSuspendedApplied = true; 1196 mBluetoothLeSuspendedApplied = true; 1197 } else { 1198 AudioSystem.setParameters("BT_SCO=off"); 1199 if (mBluetoothA2dpSuspendedApplied) { 1200 AudioSystem.setParameters("A2dpSuspended=true"); 1201 } else { 1202 AudioSystem.setParameters("A2dpSuspended=false"); 1203 } 1204 if (mBluetoothLeSuspendedApplied) { 1205 AudioSystem.setParameters("LeAudioSuspended=true"); 1206 } else { 1207 AudioSystem.setParameters("LeAudioSuspended=false"); 1208 } 1209 } 1210 } 1211 1212 @GuardedBy("mDeviceStateLock") setBluetoothScoOn(boolean on, String eventSource)1213 /*package*/ void setBluetoothScoOn(boolean on, String eventSource) { 1214 synchronized (mBluetoothAudioStateLock) { 1215 AttributionSource btScoRequesterAS = bluetoothScoRequestOwnerAttributionSource(); 1216 Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: " 1217 + mBluetoothScoOn + ", btScoRequesterUId: " 1218 + safeUidFromAttributionSource(btScoRequesterAS) 1219 + ", from: " + eventSource); 1220 mBluetoothScoOn = on; 1221 updateAudioHalBluetoothState(); 1222 if (!mScoManagedByAudio) { 1223 postUpdateCommunicationRouteClient(btScoRequesterAS, eventSource); 1224 } 1225 } 1226 } 1227 setA2dpSuspended(boolean enable, boolean internal, String eventSource)1228 /*package*/ void setA2dpSuspended(boolean enable, boolean internal, String eventSource) { 1229 synchronized (mBluetoothAudioStateLock) { 1230 if (AudioService.DEBUG_COMM_RTE) { 1231 Log.v(TAG, "setA2dpSuspended source: " + eventSource + ", enable: " 1232 + enable + ", internal: " + internal 1233 + ", mBluetoothA2dpSuspendedInt: " + mBluetoothA2dpSuspendedInt 1234 + ", mBluetoothA2dpSuspendedExt: " + mBluetoothA2dpSuspendedExt); 1235 } 1236 if (internal) { 1237 mBluetoothA2dpSuspendedInt = enable; 1238 } else { 1239 mBluetoothA2dpSuspendedExt = enable; 1240 } 1241 updateAudioHalBluetoothState(); 1242 } 1243 } 1244 clearA2dpSuspended(boolean internalOnly)1245 /*package*/ void clearA2dpSuspended(boolean internalOnly) { 1246 if (AudioService.DEBUG_COMM_RTE) { 1247 Log.v(TAG, "clearA2dpSuspended, internalOnly: " + internalOnly); 1248 } 1249 synchronized (mBluetoothAudioStateLock) { 1250 mBluetoothA2dpSuspendedInt = false; 1251 if (!internalOnly) { 1252 mBluetoothA2dpSuspendedExt = false; 1253 } 1254 updateAudioHalBluetoothState(); 1255 } 1256 } 1257 setLeAudioSuspended(boolean enable, boolean internal, String eventSource)1258 /*package*/ void setLeAudioSuspended(boolean enable, boolean internal, String eventSource) { 1259 synchronized (mBluetoothAudioStateLock) { 1260 if (AudioService.DEBUG_COMM_RTE) { 1261 Log.v(TAG, "setLeAudioSuspended source: " + eventSource + ", enable: " 1262 + enable + ", internal: " + internal 1263 + ", mBluetoothLeSuspendedInt: " + mBluetoothA2dpSuspendedInt 1264 + ", mBluetoothLeSuspendedExt: " + mBluetoothA2dpSuspendedExt); 1265 } 1266 if (internal) { 1267 mBluetoothLeSuspendedInt = enable; 1268 } else { 1269 mBluetoothLeSuspendedExt = enable; 1270 } 1271 updateAudioHalBluetoothState(); 1272 } 1273 } 1274 clearLeAudioSuspended(boolean internalOnly)1275 /*package*/ void clearLeAudioSuspended(boolean internalOnly) { 1276 if (AudioService.DEBUG_COMM_RTE) { 1277 Log.v(TAG, "clearLeAudioSuspended, internalOnly: " + internalOnly); 1278 } 1279 synchronized (mBluetoothAudioStateLock) { 1280 mBluetoothLeSuspendedInt = false; 1281 if (!internalOnly) { 1282 mBluetoothLeSuspendedExt = false; 1283 } 1284 updateAudioHalBluetoothState(); 1285 } 1286 } 1287 startWatchingRoutes(IAudioRoutesObserver observer)1288 /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 1289 synchronized (mDeviceStateLock) { 1290 return mDeviceInventory.startWatchingRoutes(observer); 1291 } 1292 } 1293 getCurAudioRoutes()1294 /*package*/ AudioRoutesInfo getCurAudioRoutes() { 1295 synchronized (mDeviceStateLock) { 1296 return mDeviceInventory.getCurAudioRoutes(); 1297 } 1298 } 1299 isBluetoothA2dpOn()1300 /*package*/ boolean isBluetoothA2dpOn() { 1301 return mBluetoothA2dpEnabled.get(); 1302 } 1303 postSetAvrcpAbsoluteVolumeIndex(int index)1304 /*package*/ void postSetAvrcpAbsoluteVolumeIndex(int index) { 1305 sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index); 1306 } 1307 postSetHearingAidVolumeIndex(int index, int streamType)1308 /*package*/ void postSetHearingAidVolumeIndex(int index, int streamType) { 1309 sendIIMsgNoDelay(MSG_II_SET_HEARING_AID_VOLUME, SENDMSG_REPLACE, index, streamType); 1310 } 1311 postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType)1312 /*package*/ void postSetLeAudioVolumeIndex(int index, int maxIndex, int streamType) { 1313 BleVolumeInfo info = new BleVolumeInfo(index, maxIndex, streamType); 1314 sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info); 1315 } 1316 postSetModeOwner(int mode, int pid, int uid, boolean signal)1317 /*package*/ void postSetModeOwner(int mode, int pid, int uid, boolean signal) { 1318 sendLMsgNoDelay(signal ? MSG_L_SET_MODE_OWNER_SIGNAL : MSG_L_SET_MODE_OWNER, 1319 SENDMSG_REPLACE, new AudioModeInfo(mode, pid, uid)); 1320 } 1321 postBluetoothDeviceConfigChange(@onNull BtDeviceInfo info)1322 /*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) { 1323 sendLMsgNoDelay(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, info); 1324 } 1325 startBluetoothScoForClient(IBinder cb, @NonNull AttributionSource attributionSource, int scoAudioMode, boolean isPrivileged, @NonNull String eventSource)1326 /*package*/ void startBluetoothScoForClient(IBinder cb, 1327 @NonNull AttributionSource attributionSource, int scoAudioMode, boolean isPrivileged, 1328 @NonNull String eventSource) { 1329 if (AudioService.DEBUG_COMM_RTE) { 1330 Log.v(TAG, "startBluetoothScoForClient, uid: " + attributionSource.getUid()); 1331 } 1332 postSetCommunicationDeviceForClient(new CommunicationDeviceInfo(cb, attributionSource, 1333 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), 1334 true, scoAudioMode, eventSource, isPrivileged)); 1335 } 1336 stopBluetoothScoForClient(IBinder cb, @NonNull AttributionSource attributionSource, boolean isPrivileged, @NonNull String eventSource)1337 /*package*/ void stopBluetoothScoForClient(IBinder cb, 1338 @NonNull AttributionSource attributionSource, boolean isPrivileged, 1339 @NonNull String eventSource) { 1340 if (AudioService.DEBUG_COMM_RTE) { 1341 Log.v(TAG, "stopBluetoothScoForClient, uid: " + attributionSource.getUid()); 1342 } 1343 postSetCommunicationDeviceForClient(new CommunicationDeviceInfo( 1344 cb, attributionSource, new AudioDeviceAttributes( 1345 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, ""), 1346 false, BtHelper.SCO_MODE_UNDEFINED, eventSource, isPrivileged)); 1347 } 1348 setPreferredDevicesForStrategySync(int strategy, @NonNull List<AudioDeviceAttributes> devices)1349 /*package*/ int setPreferredDevicesForStrategySync(int strategy, 1350 @NonNull List<AudioDeviceAttributes> devices) { 1351 return mDeviceInventory.setPreferredDevicesForStrategyAndSave(strategy, devices); 1352 } 1353 removePreferredDevicesForStrategySync(int strategy)1354 /*package*/ int removePreferredDevicesForStrategySync(int strategy) { 1355 return mDeviceInventory.removePreferredDevicesForStrategyAndSave(strategy); 1356 } 1357 setDeviceAsNonDefaultForStrategySync(int strategy, @NonNull AudioDeviceAttributes device)1358 /*package*/ int setDeviceAsNonDefaultForStrategySync(int strategy, 1359 @NonNull AudioDeviceAttributes device) { 1360 return mDeviceInventory.setDeviceAsNonDefaultForStrategyAndSave(strategy, device); 1361 } 1362 removeDeviceAsNonDefaultForStrategySync(int strategy, @NonNull AudioDeviceAttributes device)1363 /*package*/ int removeDeviceAsNonDefaultForStrategySync(int strategy, 1364 @NonNull AudioDeviceAttributes device) { 1365 return mDeviceInventory.removeDeviceAsNonDefaultForStrategyAndSave(strategy, device); 1366 } 1367 registerStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged)1368 /*package*/ void registerStrategyPreferredDevicesDispatcher( 1369 @NonNull IStrategyPreferredDevicesDispatcher dispatcher, boolean isPrivileged) { 1370 mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher, isPrivileged); 1371 } 1372 unregisterStrategyPreferredDevicesDispatcher( @onNull IStrategyPreferredDevicesDispatcher dispatcher)1373 /*package*/ void unregisterStrategyPreferredDevicesDispatcher( 1374 @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { 1375 mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher); 1376 } 1377 registerStrategyNonDefaultDevicesDispatcher( @onNull IStrategyNonDefaultDevicesDispatcher dispatcher, boolean isPrivileged)1378 /*package*/ void registerStrategyNonDefaultDevicesDispatcher( 1379 @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher, boolean isPrivileged) { 1380 mDeviceInventory.registerStrategyNonDefaultDevicesDispatcher(dispatcher, isPrivileged); 1381 } 1382 unregisterStrategyNonDefaultDevicesDispatcher( @onNull IStrategyNonDefaultDevicesDispatcher dispatcher)1383 /*package*/ void unregisterStrategyNonDefaultDevicesDispatcher( 1384 @NonNull IStrategyNonDefaultDevicesDispatcher dispatcher) { 1385 mDeviceInventory.unregisterStrategyNonDefaultDevicesDispatcher(dispatcher); 1386 } 1387 setPreferredDevicesForCapturePresetSync(int capturePreset, @NonNull List<AudioDeviceAttributes> devices)1388 /*package*/ int setPreferredDevicesForCapturePresetSync(int capturePreset, 1389 @NonNull List<AudioDeviceAttributes> devices) { 1390 return mDeviceInventory.setPreferredDevicesForCapturePresetAndSave(capturePreset, devices); 1391 } 1392 clearPreferredDevicesForCapturePresetSync(int capturePreset)1393 /*package*/ int clearPreferredDevicesForCapturePresetSync(int capturePreset) { 1394 return mDeviceInventory.clearPreferredDevicesForCapturePresetAndSave(capturePreset); 1395 } 1396 registerCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged)1397 /*package*/ void registerCapturePresetDevicesRoleDispatcher( 1398 @NonNull ICapturePresetDevicesRoleDispatcher dispatcher, boolean isPrivileged) { 1399 mDeviceInventory.registerCapturePresetDevicesRoleDispatcher(dispatcher, isPrivileged); 1400 } 1401 unregisterCapturePresetDevicesRoleDispatcher( @onNull ICapturePresetDevicesRoleDispatcher dispatcher)1402 /*package*/ void unregisterCapturePresetDevicesRoleDispatcher( 1403 @NonNull ICapturePresetDevicesRoleDispatcher dispatcher) { 1404 mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher); 1405 } 1406 anonymizeAudioDeviceAttributesListUnchecked( List<AudioDeviceAttributes> devices)1407 /* package */ List<AudioDeviceAttributes> anonymizeAudioDeviceAttributesListUnchecked( 1408 List<AudioDeviceAttributes> devices) { 1409 return mAudioService.anonymizeAudioDeviceAttributesListUnchecked(devices); 1410 } 1411 registerCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)1412 /*package*/ void registerCommunicationDeviceDispatcher( 1413 @NonNull ICommunicationDeviceDispatcher dispatcher) { 1414 mCommDevDispatchers.register(dispatcher); 1415 } 1416 unregisterCommunicationDeviceDispatcher( @onNull ICommunicationDeviceDispatcher dispatcher)1417 /*package*/ void unregisterCommunicationDeviceDispatcher( 1418 @NonNull ICommunicationDeviceDispatcher dispatcher) { 1419 mCommDevDispatchers.unregister(dispatcher); 1420 } 1421 1422 // Monitoring of communication device 1423 final RemoteCallbackList<ICommunicationDeviceDispatcher> mCommDevDispatchers = 1424 new RemoteCallbackList<ICommunicationDeviceDispatcher>(); 1425 1426 // portId of the device currently selected for communication: avoids broadcasting changes 1427 // when same communication route is applied 1428 @GuardedBy("mDeviceStateLock") 1429 int mCurCommunicationPortId = -1; 1430 1431 @GuardedBy("mDeviceStateLock") dispatchCommunicationDevice()1432 private void dispatchCommunicationDevice() { 1433 AudioDeviceInfo device = getCommunicationDeviceInt(); 1434 int portId = device != null ? device.getId() : 0; 1435 if (portId == mCurCommunicationPortId) { 1436 return; 1437 } 1438 mCurCommunicationPortId = portId; 1439 1440 @BtCommDeviceActiveType int btCommDeviceActiveType = 0; 1441 if (equalScoLeaVcIndexRange()) { 1442 if (isBluetoothScoActive()) { 1443 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_SCO; 1444 } else if (isBluetoothBleHeadsetActive()) { 1445 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_HEADSET; 1446 } else if (isBluetoothBleSpeakerActive()) { 1447 btCommDeviceActiveType = BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER; 1448 } 1449 mAudioService.postBtCommDeviceActive(btCommDeviceActiveType); 1450 } else { 1451 mAudioService.postBtCommDeviceActive( 1452 isBluetoothScoActive() ? BT_COMM_DEVICE_ACTIVE_SCO : btCommDeviceActiveType); 1453 } 1454 1455 final int nbDispatchers = mCommDevDispatchers.beginBroadcast(); 1456 for (int i = 0; i < nbDispatchers; i++) { 1457 try { 1458 mCommDevDispatchers.getBroadcastItem(i) 1459 .dispatchCommunicationDeviceChanged(portId); 1460 } catch (RemoteException e) { 1461 Log.e(TAG, "dispatchCommunicationDevice error", e); 1462 } 1463 } 1464 mCommDevDispatchers.finishBroadcast(); 1465 } 1466 1467 1468 //--------------------------------------------------------------------- 1469 // Communication with (to) AudioService 1470 //TODO check whether the AudioService methods are candidates to move here postAccessoryPlugMediaUnmute(int device)1471 /*package*/ void postAccessoryPlugMediaUnmute(int device) { 1472 mAudioService.postAccessoryPlugMediaUnmute(device); 1473 } 1474 getVolumeForDeviceIgnoreMute(int streamType, int device)1475 /*package*/ int getVolumeForDeviceIgnoreMute(int streamType, int device) { 1476 return mAudioService.getVolumeForDeviceIgnoreMute(streamType, device); 1477 } 1478 getMaxVssVolumeForStream(int streamType)1479 /*package*/ int getMaxVssVolumeForStream(int streamType) { 1480 return mAudioService.getMaxVssVolumeForStream(streamType); 1481 } 1482 getDeviceForStream(int streamType)1483 /*package*/ int getDeviceForStream(int streamType) { 1484 return mAudioService.getDeviceForStream(streamType); 1485 } 1486 postApplyVolumeOnDevice(int streamType, int device, String caller)1487 /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) { 1488 mAudioService.postApplyVolumeOnDevice(streamType, device, caller); 1489 } 1490 postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, String caller)1491 /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device, 1492 String caller) { 1493 mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller); 1494 } 1495 postObserveDevicesForAllStreams()1496 /*packages*/ void postObserveDevicesForAllStreams() { 1497 mAudioService.postObserveDevicesForAllStreams(); 1498 } 1499 isInCommunication()1500 /*package*/ boolean isInCommunication() { 1501 return mAudioService.isInCommunication(); 1502 } 1503 hasMediaDynamicPolicy()1504 /*package*/ boolean hasMediaDynamicPolicy() { 1505 return mAudioService.hasMediaDynamicPolicy(); 1506 } 1507 getContentResolver()1508 /*package*/ ContentResolver getContentResolver() { 1509 return mAudioService.getContentResolver(); 1510 } 1511 checkMusicActive(int deviceType, String caller)1512 /*package*/ void checkMusicActive(int deviceType, String caller) { 1513 mAudioService.checkMusicActive(deviceType, caller); 1514 } 1515 checkVolumeCecOnHdmiConnection( @udioService.ConnectionState int state, String caller)1516 /*package*/ void checkVolumeCecOnHdmiConnection( 1517 @AudioService.ConnectionState int state, String caller) { 1518 mAudioService.postCheckVolumeCecOnHdmiConnection(state, caller); 1519 } 1520 hasAudioFocusUsers()1521 /*package*/ boolean hasAudioFocusUsers() { 1522 return mAudioService.hasAudioFocusUsers(); 1523 } 1524 postInitSpatializerHeadTrackingSensors()1525 /*package*/ void postInitSpatializerHeadTrackingSensors() { 1526 mAudioService.postInitSpatializerHeadTrackingSensors(); 1527 } 1528 1529 //--------------------------------------------------------------------- 1530 // Message handling on behalf of helper classes. 1531 // Each of these methods posts a message to mBrokerHandler message queue. postBroadcastScoConnectionState(int state)1532 /*package*/ void postBroadcastScoConnectionState(int state) { 1533 sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state); 1534 } 1535 postBroadcastBecomingNoisy()1536 /*package*/ void postBroadcastBecomingNoisy() { 1537 sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE); 1538 } 1539 postBluetoothActiveDevice(BtDeviceInfo info, int delay)1540 /*package*/ void postBluetoothActiveDevice(BtDeviceInfo info, int delay) { 1541 sendLMsg(MSG_L_SET_BT_ACTIVE_DEVICE, SENDMSG_QUEUE, info, delay); 1542 } 1543 postSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay)1544 /*package*/ void postSetWiredDeviceConnectionState( 1545 AudioDeviceInventory.WiredDeviceConnectionState connectionState, int delay) { 1546 sendLMsg(MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE, SENDMSG_QUEUE, connectionState, delay); 1547 } 1548 postBtProfileDisconnected(int profile)1549 /*package*/ void postBtProfileDisconnected(int profile) { 1550 sendIMsgNoDelay(MSG_I_BT_SERVICE_DISCONNECTED_PROFILE, SENDMSG_QUEUE, profile); 1551 } 1552 postBtProfileConnected(int profile, BluetoothProfile proxy)1553 /*package*/ void postBtProfileConnected(int profile, BluetoothProfile proxy) { 1554 sendILMsgNoDelay(MSG_IL_BT_SERVICE_CONNECTED_PROFILE, SENDMSG_QUEUE, profile, proxy); 1555 } 1556 postCommunicationRouteClientDied(CommunicationRouteClient client)1557 /*package*/ void postCommunicationRouteClientDied(CommunicationRouteClient client) { 1558 sendLMsgNoDelay(MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED, SENDMSG_QUEUE, client); 1559 } 1560 1561 private static final class UpdateCommRouteClientInfo { 1562 @NonNull public final AttributionSource attributionSource; 1563 @NonNull public final String eventSource; 1564 UpdateCommRouteClientInfo(@onNull AttributionSource attributionSource, @NonNull String eventSource)1565 UpdateCommRouteClientInfo(@NonNull AttributionSource attributionSource, 1566 @NonNull String eventSource) { 1567 this.attributionSource = attributionSource; 1568 this.eventSource = eventSource; 1569 } 1570 } 1571 postUpdateCommunicationRouteClient( AttributionSource attributionSource, String eventSource)1572 /*package*/ void postUpdateCommunicationRouteClient( 1573 AttributionSource attributionSource, String eventSource) { 1574 sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, 1575 new UpdateCommRouteClientInfo(attributionSource, eventSource)); 1576 } 1577 postSetCommunicationDeviceForClient(CommunicationDeviceInfo info)1578 /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) { 1579 sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT, SENDMSG_QUEUE, info); 1580 } 1581 postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice)1582 /*package*/ void postNotifyPreferredAudioProfileApplied(BluetoothDevice btDevice) { 1583 sendLMsgNoDelay(MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED, SENDMSG_QUEUE, btDevice); 1584 } 1585 postReceiveBtEvent(Intent intent)1586 /*package*/ void postReceiveBtEvent(Intent intent) { 1587 sendLMsgNoDelay(MSG_L_RECEIVED_BT_EVENT, SENDMSG_QUEUE, intent); 1588 } 1589 postUpdateLeAudioGroupAddresses(int groupId)1590 /*package*/ void postUpdateLeAudioGroupAddresses(int groupId) { 1591 sendIMsgNoDelay( 1592 MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES, SENDMSG_QUEUE, groupId); 1593 } 1594 postSynchronizeAdiDevicesInInventory(AdiDeviceState deviceState)1595 /*package*/ void postSynchronizeAdiDevicesInInventory(AdiDeviceState deviceState) { 1596 sendLMsgNoDelay(MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY, SENDMSG_QUEUE, deviceState); 1597 } 1598 postUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA)1599 /*package*/ void postUpdatedAdiDeviceState(AdiDeviceState deviceState, boolean initSA) { 1600 sendILMsgNoDelay( 1601 MSG_IL_UPDATED_ADI_DEVICE_STATE, SENDMSG_QUEUE, initSA ? 1 : 0, deviceState); 1602 } 1603 1604 /*package*/ static final class CommunicationDeviceInfo { 1605 final @NonNull IBinder mCb; // Identifies the requesting client for death handler 1606 final @NonNull AttributionSource mAttributionSource; // Requester attribution source 1607 final @Nullable AudioDeviceAttributes mDevice; // Device being set or reset. 1608 final boolean mOn; // true if setting, false if resetting 1609 final int mScoAudioMode; // only used for SCO: requested audio mode 1610 final boolean mIsPrivileged; // true if the client app has MODIFY_PHONE_STATE permission 1611 final @NonNull String mEventSource; // caller identifier for logging 1612 CommunicationDeviceInfo(@onNull IBinder cb, @NonNull AttributionSource attributionSource, @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, @NonNull String eventSource, boolean isPrivileged)1613 CommunicationDeviceInfo(@NonNull IBinder cb, @NonNull AttributionSource attributionSource, 1614 @Nullable AudioDeviceAttributes device, boolean on, int scoAudioMode, 1615 @NonNull String eventSource, boolean isPrivileged) { 1616 mCb = cb; 1617 mAttributionSource = attributionSource; 1618 mDevice = device; 1619 mOn = on; 1620 mScoAudioMode = scoAudioMode; 1621 mIsPrivileged = isPrivileged; 1622 mEventSource = eventSource; 1623 } 1624 1625 // redefine equality op so we can match messages intended for this client 1626 @Override equals(Object o)1627 public boolean equals(Object o) { 1628 if (o == null) { 1629 return false; 1630 } 1631 if (this == o) { 1632 return true; 1633 } 1634 if (!(o instanceof CommunicationDeviceInfo)) { 1635 return false; 1636 } 1637 1638 return mCb.equals(((CommunicationDeviceInfo) o).mCb) 1639 && mAttributionSource.equals(((CommunicationDeviceInfo) o).mAttributionSource); 1640 } 1641 1642 @Override hashCode()1643 public int hashCode() { 1644 // only hashing on the fields used in equals() 1645 return Objects.hash(mCb.hashCode(), mAttributionSource); 1646 } 1647 1648 @Override toString()1649 public String toString() { 1650 return "CommunicationDeviceInfo mCb=" + mCb.toString() 1651 + " mAttributionSource=" + mAttributionSource.toString() 1652 + " mDevice=[" + (mDevice != null ? mDevice.toString() : "null") + "]" 1653 + " mOn=" + mOn 1654 + " mScoAudioMode=" + mScoAudioMode 1655 + " mIsPrivileged=" + mIsPrivileged 1656 + " mEventSource=" + mEventSource; 1657 } 1658 } 1659 1660 //--------------------------------------------------------------------- 1661 // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory) 1662 // only call from a "handle"* method or "on"* method 1663 1664 // Handles request to override default use of A2DP for media. 1665 //@GuardedBy("mConnectedDevices") setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source)1666 /*package*/ void setBluetoothA2dpOnInt(boolean on, boolean fromA2dp, String source) { 1667 // for logging only 1668 final String eventSource = "setBluetoothA2dpOn(" + on 1669 + ") from u/pid:" + Binder.getCallingUid() + "/" 1670 + Binder.getCallingPid() + " src:" + source; 1671 1672 mBluetoothA2dpEnabled.set(on); 1673 onSetForceUse( 1674 AudioSystem.FOR_MEDIA, 1675 on ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 1676 fromA2dp, 1677 eventSource); 1678 } 1679 handleDeviceConnection(@onNull AudioDeviceAttributes attributes, boolean connect, @Nullable BluetoothDevice btDevice, boolean deviceSwitch)1680 /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes, 1681 boolean connect, @Nullable BluetoothDevice btDevice, 1682 boolean deviceSwitch) { 1683 synchronized (mDeviceStateLock) { 1684 boolean status = mDeviceInventory.handleDeviceConnection( 1685 attributes, connect, false /*for test*/, btDevice, deviceSwitch); 1686 if (isValidCommunicationDeviceType(attributes.getType()) 1687 || mDuplexCommunicationDevices.containsValue(attributes.getInternalType())) { 1688 checkCommunicationRouteClientsDevices(); 1689 if (connect || !deviceSwitch) { 1690 onUpdateCommunicationRouteClient( 1691 bluetoothScoRequestOwnerAttributionSource(), 1692 "handleDeviceConnection"); 1693 } 1694 } 1695 return status; 1696 } 1697 } 1698 handleFailureToConnectToBtHeadsetService(int delay)1699 /*package*/ void handleFailureToConnectToBtHeadsetService(int delay) { 1700 sendMsg(MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, delay); 1701 } 1702 handleCancelFailureToConnectToBtHeadsetService()1703 /*package*/ void handleCancelFailureToConnectToBtHeadsetService() { 1704 mBrokerHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 1705 } 1706 postReportNewRoutes(boolean fromA2dp)1707 /*package*/ void postReportNewRoutes(boolean fromA2dp) { 1708 sendMsgNoDelay(fromA2dp ? MSG_REPORT_NEW_ROUTES_A2DP : MSG_REPORT_NEW_ROUTES, SENDMSG_NOOP); 1709 } 1710 1711 // must be called synchronized on mConnectedDevices hasScheduledA2dpConnection(BluetoothDevice btDevice, int profile)1712 /*package*/ boolean hasScheduledA2dpConnection(BluetoothDevice btDevice, int profile) { 1713 final BtDeviceInfo devInfoToCheck = new BtDeviceInfo(btDevice, profile); 1714 return mBrokerHandler.hasEqualMessages(MSG_L_SET_BT_ACTIVE_DEVICE, devInfoToCheck); 1715 } 1716 setA2dpTimeout(String address, int a2dpCodec, int delayMs)1717 /*package*/ void setA2dpTimeout(String address, int a2dpCodec, int delayMs) { 1718 sendILMsg(MSG_IL_BTA2DP_TIMEOUT, SENDMSG_QUEUE, a2dpCodec, address, delayMs); 1719 } 1720 setLeAudioTimeout(String address, int device, int codec, int delayMs)1721 /*package*/ void setLeAudioTimeout(String address, int device, int codec, int delayMs) { 1722 sendIILMsg(MSG_IIL_BTLEAUDIO_TIMEOUT, SENDMSG_QUEUE, device, codec, address, delayMs); 1723 } 1724 setHearingAidTimeout(String address, int delayMs)1725 /*package*/ void setHearingAidTimeout(String address, int delayMs) { 1726 sendLMsg(MSG_IL_BT_HEARING_AID_TIMEOUT, SENDMSG_QUEUE, address, delayMs); 1727 } 1728 setAvrcpAbsoluteVolumeSupported(boolean supported)1729 /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean supported) { 1730 synchronized (mDeviceStateLock) { 1731 mBtHelper.setAvrcpAbsoluteVolumeSupported(supported); 1732 } 1733 } 1734 clearAvrcpAbsoluteVolumeSupported()1735 /*package*/ void clearAvrcpAbsoluteVolumeSupported() { 1736 setAvrcpAbsoluteVolumeSupported(false); 1737 mAudioService.setAvrcpAbsoluteVolumeSupported(false); 1738 } 1739 getBluetoothA2dpEnabled()1740 /*package*/ boolean getBluetoothA2dpEnabled() { 1741 return mBluetoothA2dpEnabled.get(); 1742 } 1743 getLeAudioDeviceGroupId(BluetoothDevice device)1744 /*package*/ int getLeAudioDeviceGroupId(BluetoothDevice device) { 1745 return mBtHelper.getLeAudioDeviceGroupId(device); 1746 } 1747 getLeAudioGroupAddresses(int groupId)1748 /*package*/ List<Pair<String, String>> getLeAudioGroupAddresses(int groupId) { 1749 return mBtHelper.getLeAudioGroupAddresses(groupId); 1750 } 1751 broadcastStickyIntentToCurrentProfileGroup(Intent intent)1752 /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { 1753 mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent); 1754 } 1755 dump(PrintWriter pw, String prefix)1756 /*package*/ void dump(PrintWriter pw, String prefix) { 1757 if (mBrokerHandler != null) { 1758 pw.println(prefix + "Message handler (watch for unhandled messages):"); 1759 mBrokerHandler.dump(new PrintWriterPrinter(pw), prefix + " "); 1760 } else { 1761 pw.println("Message handler is null"); 1762 } 1763 1764 mDeviceInventory.dump(pw, prefix); 1765 1766 pw.println("\n" + prefix + "Communication route clients:"); 1767 mCommunicationRouteClients.forEach((cl) -> { 1768 pw.println(" " + prefix + cl.toString()); }); 1769 1770 pw.println("\n" + prefix + "Computed Preferred communication device: " 1771 + preferredCommunicationDevice()); 1772 pw.println("\n" + prefix + "Applied Preferred communication device: " 1773 + mPreferredCommunicationDevice); 1774 pw.println(prefix + "Active communication device: " 1775 + ((mActiveCommunicationDevice == null) ? "None" 1776 : new AudioDeviceAttributes(mActiveCommunicationDevice))); 1777 1778 pw.println(prefix + "mCommunicationStrategyId: " 1779 + mCommunicationStrategyId); 1780 1781 pw.println(prefix + "mAccessibilityStrategyId: " 1782 + mAccessibilityStrategyId); 1783 1784 pw.println("\n" + prefix + "mAudioModeOwner: " + mAudioModeOwner); 1785 1786 pw.println("\n" + prefix + "mScoManagedByAudio: " + mScoManagedByAudio); 1787 1788 pw.println("\n" + prefix + "Bluetooth SCO on" 1789 + ", requested: " + mBluetoothScoOn 1790 + ", applied: " + mBluetoothScoOnApplied); 1791 pw.println("\n" + prefix + "Bluetooth A2DP suspended" 1792 + ", requested ext: " + mBluetoothA2dpSuspendedExt 1793 + ", requested int: " + mBluetoothA2dpSuspendedInt 1794 + ", applied " + mBluetoothA2dpSuspendedApplied); 1795 pw.println("\n" + prefix + "Bluetooth LE Audio suspended" 1796 + ", requested ext: " + mBluetoothLeSuspendedExt 1797 + ", requested int: " + mBluetoothLeSuspendedInt 1798 + ", applied " + mBluetoothLeSuspendedApplied); 1799 1800 mBtHelper.dump(pw, prefix); 1801 } 1802 1803 //--------------------------------------------------------------------- 1804 // Internal handling of messages 1805 // These methods are ALL synchronous, in response to message handling in BrokerHandler 1806 // Blocking in any of those will block the message queue 1807 onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource)1808 private void onSetForceUse(int useCase, int config, boolean fromA2dp, String eventSource) { 1809 if (useCase == AudioSystem.FOR_MEDIA) { 1810 postReportNewRoutes(fromA2dp); 1811 } 1812 AudioService.sForceUseLogger.enqueue( 1813 new AudioServiceEvents.ForceUseEvent(useCase, config, eventSource)); 1814 new MediaMetrics.Item(MediaMetrics.Name.AUDIO_FORCE_USE + MediaMetrics.SEPARATOR 1815 + AudioSystem.forceUseUsageToString(useCase)) 1816 .set(MediaMetrics.Property.EVENT, "onSetForceUse") 1817 .set(MediaMetrics.Property.FORCE_USE_DUE_TO, eventSource) 1818 .set(MediaMetrics.Property.FORCE_USE_MODE, 1819 AudioSystem.forceUseConfigToString(config)) 1820 .record(); 1821 1822 if (AudioService.DEBUG_COMM_RTE) { 1823 Log.v(TAG, "onSetForceUse(useCase<" + useCase + ">, config<" + config + ">, fromA2dp<" 1824 + fromA2dp + ">, eventSource<" + eventSource + ">)"); 1825 } 1826 mAudioSystem.setForceUse(useCase, config); 1827 } 1828 onSendBecomingNoisyIntent()1829 private void onSendBecomingNoisyIntent() { 1830 AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( 1831 "broadcast ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG)); 1832 mSystemServer.sendDeviceBecomingNoisyIntent(); 1833 } 1834 1835 //--------------------------------------------------------------------- 1836 // Message handling 1837 private BrokerHandler mBrokerHandler; 1838 private BrokerThread mBrokerThread; 1839 private PowerManager.WakeLock mBrokerEventWakeLock; 1840 setupMessaging(Context ctxt)1841 private void setupMessaging(Context ctxt) { 1842 final PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE); 1843 mBrokerEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 1844 "handleAudioDeviceEvent"); 1845 mBrokerThread = new BrokerThread(); 1846 mBrokerThread.start(); 1847 waitForBrokerHandlerCreation(); 1848 } 1849 waitForBrokerHandlerCreation()1850 private void waitForBrokerHandlerCreation() { 1851 synchronized (this) { 1852 while (mBrokerHandler == null) { 1853 try { 1854 wait(); 1855 } catch (InterruptedException e) { 1856 Log.e(TAG, "Interruption while waiting on BrokerHandler"); 1857 } 1858 } 1859 } 1860 } 1861 1862 /** Class that handles the device broker's message queue */ 1863 private class BrokerThread extends Thread { BrokerThread()1864 BrokerThread() { 1865 super("AudioDeviceBroker"); 1866 } 1867 1868 @Override run()1869 public void run() { 1870 // Set this thread up so the handler will work on it 1871 Looper.prepare(); 1872 1873 synchronized (AudioDeviceBroker.this) { 1874 mBrokerHandler = new BrokerHandler(); 1875 1876 // Notify that the handler has been created 1877 AudioDeviceBroker.this.notify(); 1878 } 1879 1880 Looper.loop(); 1881 } 1882 } 1883 1884 /** Class that handles the message queue */ 1885 private class BrokerHandler extends Handler { 1886 1887 @Override handleMessage(Message msg)1888 public void handleMessage(Message msg) { 1889 int muteCheckDelayMs = BTA2DP_MUTE_CHECK_DELAY_MS; 1890 switch (msg.what) { 1891 case MSG_RESTORE_DEVICES: 1892 synchronized (mSetModeLock) { 1893 synchronized (mDeviceStateLock) { 1894 initRoutingStrategyIds(); 1895 updateActiveCommunicationDevice(); 1896 mDeviceInventory.onRestoreDevices(); 1897 synchronized (mBluetoothAudioStateLock) { 1898 reapplyAudioHalBluetoothState(); 1899 } 1900 final int forceForMedia = getBluetoothA2dpEnabled() 1901 ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP; 1902 setForceUse_Async( 1903 AudioSystem.FOR_MEDIA, forceForMedia, "MSG_RESTORE_DEVICES"); 1904 updateCommunicationRoute("MSG_RESTORE_DEVICES"); 1905 } 1906 } 1907 break; 1908 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 1909 synchronized (mDeviceStateLock) { 1910 mDeviceInventory.onSetWiredDeviceConnectionState( 1911 (AudioDeviceInventory.WiredDeviceConnectionState) msg.obj); 1912 } 1913 break; 1914 case MSG_I_BROADCAST_BT_CONNECTION_STATE: 1915 synchronized (mDeviceStateLock) { 1916 mBtHelper.onBroadcastScoConnectionState(msg.arg1); 1917 } 1918 break; 1919 case MSG_IIL_SET_FORCE_USE: // intended fall-through 1920 onSetForceUse(msg.arg1, msg.arg2, false, (String) msg.obj); 1921 break; 1922 case MSG_L_SET_FORCE_BT_A2DP_USE: 1923 case MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE: 1924 int forcedUsage = mBluetoothA2dpEnabled.get() 1925 ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP; 1926 onSetForceUse(AudioSystem.FOR_MEDIA, forcedUsage, true, (String) msg.obj); 1927 break; 1928 case MSG_REPORT_NEW_ROUTES: 1929 case MSG_REPORT_NEW_ROUTES_A2DP: 1930 synchronized (mDeviceStateLock) { 1931 mDeviceInventory.onReportNewRoutes(); 1932 } 1933 break; 1934 case MSG_L_SET_BT_ACTIVE_DEVICE: { 1935 final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; 1936 if (btInfo.mState == BluetoothProfile.STATE_CONNECTED 1937 && !mBtHelper.isProfilePoxyConnected(btInfo.mProfile)) { 1938 AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( 1939 "msg: MSG_L_SET_BT_ACTIVE_DEVICE " 1940 + "received with null profile proxy: " 1941 + btInfo)).printLog(TAG)); 1942 } else { 1943 final Pair<Integer, Boolean> codecAndChanged = 1944 mBtHelper.getCodecWithFallback(btInfo.mDevice, 1945 btInfo.mProfile, btInfo.mIsLeOutput, 1946 "MSG_L_SET_BT_ACTIVE_DEVICE"); 1947 synchronized (mSetModeLock) { 1948 synchronized (mDeviceStateLock) { 1949 mDeviceInventory.onSetBtActiveDevice(btInfo, codecAndChanged.first, 1950 (btInfo.mProfile != BluetoothProfile.LE_AUDIO 1951 || btInfo.mIsLeOutput) 1952 ? mAudioService.getBluetoothContextualVolumeStream() 1953 : AudioSystem.STREAM_DEFAULT); 1954 if (btInfo.mProfile == BluetoothProfile.LE_AUDIO 1955 || btInfo.mProfile == BluetoothProfile.HEARING_AID 1956 || (mScoManagedByAudio 1957 && btInfo.mProfile == BluetoothProfile.HEADSET)) { 1958 checkCommunicationRouteClientsDevices(); 1959 if (btInfo.mState == BluetoothProfile.STATE_CONNECTED 1960 || !btInfo.mIsDeviceSwitch) { 1961 onUpdateCommunicationRouteClient( 1962 bluetoothScoRequestOwnerAttributionSource(), 1963 "setBluetoothActiveDevice"); 1964 } 1965 } 1966 } 1967 } 1968 } 1969 } break; 1970 case MSG_BT_HEADSET_CNCT_FAILED: 1971 synchronized (mSetModeLock) { 1972 synchronized (mDeviceStateLock) { 1973 mBtHelper.resetBluetoothSco(); 1974 } 1975 } 1976 break; 1977 case MSG_IL_BTA2DP_TIMEOUT: 1978 // msg.obj == address of BTA2DP device 1979 synchronized (mDeviceStateLock) { 1980 mDeviceInventory.onMakeA2dpDeviceUnavailableNow( 1981 (String) msg.obj, msg.arg1); 1982 } 1983 break; 1984 case MSG_IIL_BTLEAUDIO_TIMEOUT: 1985 // msg.obj == address of LE Audio device 1986 synchronized (mDeviceStateLock) { 1987 mDeviceInventory.onMakeLeAudioDeviceUnavailableNow( 1988 (String) msg.obj, msg.arg1, msg.arg2); 1989 } 1990 break; 1991 case MSG_IL_BT_HEARING_AID_TIMEOUT: 1992 // msg.obj == address of Hearing Aid device 1993 synchronized (mDeviceStateLock) { 1994 mDeviceInventory.onMakeHearingAidDeviceUnavailableNow( 1995 (String) msg.obj); 1996 } 1997 break; 1998 case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: { 1999 final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; 2000 final Pair<Integer, Boolean> codecAndChanged = mBtHelper.getCodecWithFallback( 2001 btInfo.mDevice, btInfo.mProfile, btInfo.mIsLeOutput, 2002 "MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE"); 2003 synchronized (mDeviceStateLock) { 2004 muteCheckDelayMs += mDeviceInventory.onBluetoothDeviceConfigChange(btInfo, 2005 codecAndChanged.first, codecAndChanged.second, 2006 BtHelper.EVENT_DEVICE_CONFIG_CHANGE); 2007 } 2008 } break; 2009 case MSG_BROADCAST_AUDIO_BECOMING_NOISY: 2010 onSendBecomingNoisyIntent(); 2011 break; 2012 case MSG_II_SET_HEARING_AID_VOLUME: 2013 synchronized (mDeviceStateLock) { 2014 mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2, 2015 mDeviceInventory.isHearingAidConnected()); 2016 } 2017 break; 2018 case MSG_II_SET_LE_AUDIO_OUT_VOLUME: { 2019 final BleVolumeInfo info = (BleVolumeInfo) msg.obj; 2020 synchronized (mDeviceStateLock) { 2021 mBtHelper.setLeAudioVolume(info.mIndex, info.mMaxIndex, info.mStreamType); 2022 } 2023 } break; 2024 case MSG_I_SET_AVRCP_ABSOLUTE_VOLUME: 2025 synchronized (mDeviceStateLock) { 2026 mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); 2027 } 2028 break; 2029 case MSG_L_SET_MODE_OWNER: 2030 case MSG_L_SET_MODE_OWNER_SIGNAL: 2031 synchronized (mSetModeLock) { 2032 synchronized (mDeviceStateLock) { 2033 mAudioModeOwner = (AudioModeInfo) msg.obj; 2034 if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) { 2035 onUpdateCommunicationRouteClient( 2036 bluetoothScoRequestOwnerAttributionSource(), 2037 "setNewModeOwner"); 2038 } 2039 } 2040 } 2041 if (msg.what == MSG_L_SET_MODE_OWNER_SIGNAL) { 2042 mAudioService.decrementAudioModeResetCount(); 2043 } 2044 break; 2045 2046 case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT: 2047 CommunicationDeviceInfo deviceInfo = (CommunicationDeviceInfo) msg.obj; 2048 synchronized (mSetModeLock) { 2049 synchronized (mDeviceStateLock) { 2050 onSetCommunicationDeviceForClient(deviceInfo); 2051 } 2052 } 2053 synchronized (mCommunicationDeviceLock) { 2054 if (mCommunicationDeviceUpdateCount > 0) { 2055 mCommunicationDeviceUpdateCount--; 2056 } else { 2057 Log.e(TAG, "mCommunicationDeviceUpdateCount already 0 in" 2058 + " MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT"); 2059 } 2060 mCommunicationDeviceLock.notify(); 2061 } 2062 break; 2063 2064 case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT: 2065 synchronized (mSetModeLock) { 2066 synchronized (mDeviceStateLock) { 2067 UpdateCommRouteClientInfo info = (UpdateCommRouteClientInfo) msg.obj; 2068 onUpdateCommunicationRouteClient( 2069 info.attributionSource, info.eventSource); 2070 } 2071 } 2072 break; 2073 2074 case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED: 2075 synchronized (mSetModeLock) { 2076 synchronized (mDeviceStateLock) { 2077 onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj); 2078 } 2079 } 2080 break; 2081 2082 case MSG_L_RECEIVED_BT_EVENT: 2083 synchronized (mSetModeLock) { 2084 synchronized (mDeviceStateLock) { 2085 onReceiveBtEvent((Intent) msg.obj); 2086 } 2087 } 2088 break; 2089 2090 case MSG_TOGGLE_HDMI: 2091 synchronized (mDeviceStateLock) { 2092 mDeviceInventory.onToggleHdmi(); 2093 } 2094 break; 2095 case MSG_I_BT_SERVICE_DISCONNECTED_PROFILE: 2096 synchronized (mSetModeLock) { 2097 synchronized (mDeviceStateLock) { 2098 mBtHelper.onBtProfileDisconnected(msg.arg1); 2099 mDeviceInventory.onBtProfileDisconnected(msg.arg1); 2100 } 2101 } 2102 break; 2103 case MSG_IL_BT_SERVICE_CONNECTED_PROFILE: 2104 synchronized (mSetModeLock) { 2105 synchronized (mDeviceStateLock) { 2106 mBtHelper.onBtProfileConnected(msg.arg1, (BluetoothProfile) msg.obj); 2107 } 2108 } 2109 break; 2110 case MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT: { 2111 final BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj; 2112 if (btInfo.mDevice == null) break; 2113 AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( 2114 "msg: MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT " + btInfo)).printLog(TAG)); 2115 synchronized (mDeviceStateLock) { 2116 mDeviceInventory.setBluetoothActiveDevice(btInfo); 2117 } 2118 } break; 2119 case MSG_CHECK_MUTE_MUSIC: 2120 checkMessagesMuteMusic(0); 2121 break; 2122 case MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED: { 2123 final BluetoothDevice btDevice = (BluetoothDevice) msg.obj; 2124 BtHelper.onNotifyPreferredAudioProfileApplied(btDevice); 2125 } break; 2126 case MSG_PERSIST_AUDIO_DEVICE_SETTINGS: 2127 onPersistAudioDeviceSettings(); 2128 break; 2129 2130 case MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE: { 2131 synchronized (mDeviceStateLock) { 2132 onCheckCommunicationRouteClientState(msg.arg1, msg.arg2 == 1); 2133 } 2134 } break; 2135 2136 case MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES: 2137 synchronized (mSetModeLock) { 2138 synchronized (mDeviceStateLock) { 2139 mDeviceInventory.onUpdateLeAudioGroupAddresses(msg.arg1); 2140 } 2141 } break; 2142 2143 case MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY: 2144 synchronized (mSetModeLock) { 2145 synchronized (mDeviceStateLock) { 2146 mDeviceInventory.onSynchronizeAdiDevicesInInventory( 2147 (AdiDeviceState) msg.obj); 2148 } 2149 } break; 2150 2151 case MSG_IL_UPDATED_ADI_DEVICE_STATE: 2152 mAudioService.onUpdatedAdiDeviceState((AdiDeviceState) msg.obj, msg.arg1 == 1); 2153 break; 2154 2155 default: 2156 Log.wtf(TAG, "Invalid message " + msg.what); 2157 } 2158 2159 // Give some time to Bluetooth service to post a connection message 2160 // in case of active device switch 2161 if (MESSAGES_MUTE_MUSIC.contains(msg.what)) { 2162 sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, muteCheckDelayMs); 2163 } 2164 2165 if (isMessageHandledUnderWakelock(msg.what)) { 2166 try { 2167 mBrokerEventWakeLock.release(); 2168 } catch (Exception e) { 2169 Log.e(TAG, "Exception releasing wakelock", e); 2170 } 2171 } 2172 } 2173 } 2174 2175 // List of all messages. If a message has be handled under wakelock, add it to 2176 // the isMessageHandledUnderWakelock(int) method 2177 // Naming of msg indicates arguments, using JNI argument grammar 2178 // (e.g. II indicates two int args, IL indicates int and Obj arg) 2179 private static final int MSG_RESTORE_DEVICES = 1; 2180 private static final int MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE = 2; 2181 private static final int MSG_I_BROADCAST_BT_CONNECTION_STATE = 3; 2182 private static final int MSG_IIL_SET_FORCE_USE = 4; 2183 private static final int MSG_L_SET_FORCE_BT_A2DP_USE = 5; 2184 private static final int MSG_TOGGLE_HDMI = 6; 2185 private static final int MSG_L_SET_BT_ACTIVE_DEVICE = 7; 2186 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9; 2187 private static final int MSG_IL_BTA2DP_TIMEOUT = 10; 2188 2189 // process change of A2DP device configuration, obj is BluetoothDevice 2190 private static final int MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE = 11; 2191 2192 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 12; 2193 private static final int MSG_REPORT_NEW_ROUTES = 13; 2194 private static final int MSG_II_SET_HEARING_AID_VOLUME = 14; 2195 private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15; 2196 private static final int MSG_L_SET_MODE_OWNER = 16; 2197 private static final int MSG_L_SET_MODE_OWNER_SIGNAL = 17; 2198 2199 private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22; 2200 private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23; 2201 2202 // process external command to (dis)connect an A2DP device, obj is BtDeviceConnectionInfo 2203 private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 29; 2204 2205 // process external command to (dis)connect a hearing aid device 2206 private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 31; 2207 2208 private static final int MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED = 34; 2209 private static final int MSG_CHECK_MUTE_MUSIC = 35; 2210 private static final int MSG_REPORT_NEW_ROUTES_A2DP = 36; 2211 2212 private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42; 2213 private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43; 2214 2215 private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45; 2216 // 2217 // process set volume for Le Audio, obj is BleVolumeInfo 2218 private static final int MSG_II_SET_LE_AUDIO_OUT_VOLUME = 46; 2219 2220 private static final int MSG_IIL_BTLEAUDIO_TIMEOUT = 49; 2221 2222 private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52; 2223 2224 private static final int MSG_PERSIST_AUDIO_DEVICE_SETTINGS = 54; 2225 2226 private static final int MSG_L_RECEIVED_BT_EVENT = 55; 2227 2228 private static final int MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE = 56; 2229 private static final int MSG_I_UPDATE_LE_AUDIO_GROUP_ADDRESSES = 57; 2230 private static final int MSG_L_SYNCHRONIZE_ADI_DEVICES_IN_INVENTORY = 58; 2231 private static final int MSG_IL_UPDATED_ADI_DEVICE_STATE = 59; 2232 private static final int MSG_L_SET_FORCE_BT_A2DP_USE_NO_MUTE = 60; 2233 private static final int MSG_IL_BT_HEARING_AID_TIMEOUT = 61; 2234 isMessageHandledUnderWakelock(int msgId)2235 private static boolean isMessageHandledUnderWakelock(int msgId) { 2236 switch(msgId) { 2237 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 2238 case MSG_L_SET_BT_ACTIVE_DEVICE: 2239 case MSG_IL_BTA2DP_TIMEOUT: 2240 case MSG_IIL_BTLEAUDIO_TIMEOUT: 2241 case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: 2242 case MSG_TOGGLE_HDMI: 2243 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: 2244 case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: 2245 case MSG_CHECK_MUTE_MUSIC: 2246 case MSG_IL_BT_HEARING_AID_TIMEOUT: 2247 return true; 2248 default: 2249 return false; 2250 } 2251 } 2252 2253 // Message helper methods 2254 2255 // sendMsg() flags 2256 /** If the msg is already queued, replace it with this one. */ 2257 private static final int SENDMSG_REPLACE = 0; 2258 /** If the msg is already queued, ignore this one and leave the old. */ 2259 private static final int SENDMSG_NOOP = 1; 2260 /** If the msg is already queued, queue this one and leave the old. */ 2261 private static final int SENDMSG_QUEUE = 2; 2262 sendMsg(int msg, int existingMsgPolicy, int delay)2263 private void sendMsg(int msg, int existingMsgPolicy, int delay) { 2264 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, delay); 2265 } 2266 sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay)2267 private void sendILMsg(int msg, int existingMsgPolicy, int arg, Object obj, int delay) { 2268 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, delay); 2269 } 2270 sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay)2271 private void sendLMsg(int msg, int existingMsgPolicy, Object obj, int delay) { 2272 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, delay); 2273 } 2274 sendMsgNoDelay(int msg, int existingMsgPolicy)2275 private void sendMsgNoDelay(int msg, int existingMsgPolicy) { 2276 sendIILMsg(msg, existingMsgPolicy, 0, 0, null, 0); 2277 } 2278 sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg)2279 private void sendIMsgNoDelay(int msg, int existingMsgPolicy, int arg) { 2280 sendIILMsg(msg, existingMsgPolicy, arg, 0, null, 0); 2281 } 2282 sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2)2283 private void sendIIMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2) { 2284 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, null, 0); 2285 } 2286 sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj)2287 private void sendILMsgNoDelay(int msg, int existingMsgPolicy, int arg, Object obj) { 2288 sendIILMsg(msg, existingMsgPolicy, arg, 0, obj, 0); 2289 } 2290 sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj)2291 private void sendLMsgNoDelay(int msg, int existingMsgPolicy, Object obj) { 2292 sendIILMsg(msg, existingMsgPolicy, 0, 0, obj, 0); 2293 } 2294 sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj)2295 private void sendIILMsgNoDelay(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj) { 2296 sendIILMsg(msg, existingMsgPolicy, arg1, arg2, obj, 0); 2297 } 2298 sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)2299 private void sendIILMsg(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, 2300 int delay) { 2301 if (existingMsgPolicy == SENDMSG_REPLACE) { 2302 mBrokerHandler.removeMessages(msg); 2303 } else if (existingMsgPolicy == SENDMSG_NOOP && mBrokerHandler.hasMessages(msg)) { 2304 return; 2305 } 2306 2307 if (isMessageHandledUnderWakelock(msg)) { 2308 final long identity = Binder.clearCallingIdentity(); 2309 try { 2310 mBrokerEventWakeLock.acquire(BROKER_WAKELOCK_TIMEOUT_MS); 2311 } catch (Exception e) { 2312 Log.e(TAG, "Exception acquiring wakelock", e); 2313 } finally { 2314 Binder.restoreCallingIdentity(identity); 2315 } 2316 } 2317 2318 if (MESSAGES_MUTE_MUSIC.contains(msg)) { 2319 checkMessagesMuteMusic(msg); 2320 } 2321 2322 synchronized (sLastDeviceConnectionMsgTimeLock) { 2323 long time = SystemClock.uptimeMillis() + delay; 2324 2325 switch (msg) { 2326 case MSG_L_SET_BT_ACTIVE_DEVICE: 2327 case MSG_L_SET_WIRED_DEVICE_CONNECTION_STATE: 2328 case MSG_IL_BTA2DP_TIMEOUT: 2329 case MSG_IIL_BTLEAUDIO_TIMEOUT: 2330 case MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE: 2331 case MSG_IL_BT_HEARING_AID_TIMEOUT: 2332 if (sLastDeviceConnectMsgTime >= time) { 2333 // add a little delay to make sure messages are ordered as expected 2334 time = sLastDeviceConnectMsgTime + 30; 2335 } 2336 sLastDeviceConnectMsgTime = time; 2337 break; 2338 default: 2339 break; 2340 } 2341 mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), 2342 time); 2343 } 2344 } 2345 removeMsgForCheckClientState(int uid)2346 private void removeMsgForCheckClientState(int uid) { 2347 CommunicationRouteClient crc = getCommunicationRouteClientForUid(uid); 2348 if (crc != null) { 2349 mBrokerHandler.removeEqualMessages(MSG_CHECK_COMMUNICATION_ROUTE_CLIENT_STATE, crc); 2350 } 2351 } 2352 sendMsgForCheckClientState(int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay)2353 private void sendMsgForCheckClientState(int msg, int existingMsgPolicy, 2354 int arg1, int arg2, Object obj, int delay) { 2355 if ((existingMsgPolicy == SENDMSG_REPLACE) && (obj != null)) { 2356 mBrokerHandler.removeEqualMessages(msg, obj); 2357 } 2358 2359 long time = SystemClock.uptimeMillis() + delay; 2360 mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time); 2361 } 2362 2363 /** List of messages for which music is muted while processing is pending */ 2364 private static final Set<Integer> MESSAGES_MUTE_MUSIC; 2365 static { 2366 MESSAGES_MUTE_MUSIC = new HashSet<>(); 2367 MESSAGES_MUTE_MUSIC.add(MSG_L_SET_BT_ACTIVE_DEVICE); 2368 MESSAGES_MUTE_MUSIC.add(MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE); 2369 MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT); 2370 MESSAGES_MUTE_MUSIC.add(MSG_L_SET_FORCE_BT_A2DP_USE); 2371 } 2372 2373 private AtomicBoolean mMusicMuted = new AtomicBoolean(false); 2374 hasIntersection(Set<T> a, Set<T> b)2375 private static <T> boolean hasIntersection(Set<T> a, Set<T> b) { 2376 for (T e : a) { 2377 if (b.contains(e)) return true; 2378 } 2379 return false; 2380 } 2381 messageMutesMusic(int message)2382 boolean messageMutesMusic(int message) { 2383 if (message == 0) { 2384 return false; 2385 } 2386 // Do not mute on bluetooth event if music is playing on a wired headset. 2387 if ((message == MSG_L_SET_BT_ACTIVE_DEVICE 2388 || message == MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT 2389 || message == MSG_L_BLUETOOTH_DEVICE_CONFIG_CHANGE) 2390 && AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) 2391 && hasIntersection(mDeviceInventory.DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET, 2392 mAudioService.getDeviceSetForStream(AudioSystem.STREAM_MUSIC))) { 2393 return false; 2394 } 2395 return true; 2396 } 2397 2398 /** Mutes or unmutes music according to pending A2DP messages */ checkMessagesMuteMusic(int message)2399 private void checkMessagesMuteMusic(int message) { 2400 boolean mute = messageMutesMusic(message); 2401 if (!mute) { 2402 for (int msg : MESSAGES_MUTE_MUSIC) { 2403 if (mBrokerHandler.hasMessages(msg)) { 2404 if (messageMutesMusic(msg)) { 2405 mute = true; 2406 break; 2407 } 2408 } 2409 } 2410 } 2411 2412 if (mute != mMusicMuted.getAndSet(mute)) { 2413 mAudioService.setMusicMute(mute); 2414 } 2415 } 2416 2417 // List of applications requesting a specific route for communication. 2418 @GuardedBy("mDeviceStateLock") 2419 private final @NonNull LinkedList<CommunicationRouteClient> mCommunicationRouteClients = 2420 new LinkedList<CommunicationRouteClient>(); 2421 2422 private class CommunicationRouteClient implements IBinder.DeathRecipient { 2423 private final IBinder mCb; 2424 @NonNull private final AttributionSource mAttributionSource; 2425 private final boolean mIsPrivileged; 2426 @NonNull private AudioDeviceAttributes mDevice; 2427 private boolean mPlaybackActive; 2428 private boolean mRecordingActive; 2429 2430 private boolean mDisabled; 2431 CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource, @NonNull AudioDeviceAttributes device, boolean isPrivileged)2432 CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource, 2433 @NonNull AudioDeviceAttributes device, boolean isPrivileged) { 2434 mCb = cb; 2435 mAttributionSource = attributionSource; 2436 mDevice = device; 2437 mIsPrivileged = isPrivileged; 2438 mPlaybackActive = mAudioService.isPlaybackActiveForUid(attributionSource.getUid()); 2439 mRecordingActive = mAudioService.isRecordingActiveForUid(attributionSource.getUid()); 2440 mDisabled = false; 2441 } 2442 registerDeathRecipient()2443 public boolean registerDeathRecipient() { 2444 boolean status = false; 2445 try { 2446 mCb.linkToDeath(this, 0); 2447 status = true; 2448 } catch (RemoteException e) { 2449 Log.w(TAG, "CommunicationRouteClient could not link to " + mCb + " binder death"); 2450 } 2451 return status; 2452 } 2453 unregisterDeathRecipient()2454 public void unregisterDeathRecipient() { 2455 try { 2456 mCb.unlinkToDeath(this, 0); 2457 } catch (NoSuchElementException e) { 2458 Log.w(TAG, "CommunicationRouteClient could not unlink to " + mCb + " binder death"); 2459 } 2460 } 2461 2462 @Override binderDied()2463 public void binderDied() { 2464 postCommunicationRouteClientDied(this); 2465 } 2466 getBinder()2467 IBinder getBinder() { 2468 return mCb; 2469 } 2470 getAttributionSource()2471 @NonNull AttributionSource getAttributionSource() { 2472 return mAttributionSource; 2473 } 2474 getUid()2475 int getUid() { 2476 return mAttributionSource.getUid(); 2477 } 2478 isPrivileged()2479 boolean isPrivileged() { 2480 return mIsPrivileged; 2481 } 2482 setDevice(@onNull AudioDeviceAttributes device)2483 void setDevice(@NonNull AudioDeviceAttributes device) { 2484 mDevice = device; 2485 } getDevice()2486 @NonNull AudioDeviceAttributes getDevice() { 2487 return mDevice; 2488 } 2489 setPlaybackActive(boolean active)2490 public void setPlaybackActive(boolean active) { 2491 mPlaybackActive = active; 2492 } 2493 setRecordingActive(boolean active)2494 public void setRecordingActive(boolean active) { 2495 mRecordingActive = active; 2496 } 2497 isActive()2498 public boolean isActive() { 2499 return !mDisabled && (mIsPrivileged || mRecordingActive || mPlaybackActive); 2500 } 2501 setDisabled(boolean disabled)2502 public void setDisabled(boolean disabled) { 2503 mDisabled = disabled; 2504 } isDisabled()2505 public boolean isDisabled() { 2506 return mDisabled; 2507 } 2508 2509 @Override toString()2510 public String toString() { 2511 return "[CommunicationRouteClient: mAttributionSource: " + mAttributionSource 2512 + " mDevice: " + mDevice.toString() 2513 + " mIsPrivileged: " + mIsPrivileged 2514 + " mPlaybackActive: " + mPlaybackActive 2515 + " mRecordingActive: " + mRecordingActive 2516 + " mDisabled: " + mDisabled + "]"; 2517 } 2518 } 2519 2520 // @GuardedBy("mSetModeLock") 2521 @GuardedBy("mDeviceStateLock") onCommunicationRouteClientDied(CommunicationRouteClient client)2522 private void onCommunicationRouteClientDied(CommunicationRouteClient client) { 2523 if (client == null) { 2524 return; 2525 } 2526 Log.w(TAG, "Communication client died"); 2527 setCommunicationRouteForClient(client.getBinder(), client.getAttributionSource(), 2528 null, BtHelper.SCO_MODE_UNDEFINED, client.isPrivileged(), 2529 "onCommunicationRouteClientDied"); 2530 } 2531 2532 /** 2533 * Determines which preferred device for phone strategy should be sent to audio policy manager 2534 * as a function of current SCO audio activation state and active communication route requests. 2535 * SCO audio state has the highest priority as it can result from external activation by 2536 * telephony service. 2537 * @return selected forced usage for communication. 2538 */ 2539 @GuardedBy("mDeviceStateLock") preferredCommunicationDevice()2540 @Nullable private AudioDeviceAttributes preferredCommunicationDevice() { 2541 boolean btSCoOn = mBtHelper.isBluetoothScoOn(); 2542 synchronized (mBluetoothAudioStateLock) { 2543 btSCoOn = (btSCoOn || mScoManagedByAudio) && mBluetoothScoOn; 2544 } 2545 2546 if (btSCoOn) { 2547 // Use the SCO device known to BtHelper so that it matches exactly 2548 // what has been communicated to audio policy manager. The device 2549 // returned by requestedCommunicationDevice() can be a placeholder SCO device if legacy 2550 // APIs are used to start SCO audio. 2551 AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice(); 2552 if (device != null) { 2553 return device; 2554 } 2555 } 2556 AudioDeviceAttributes device = requestedCommunicationDevice(); 2557 if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { 2558 // Do not indicate BT SCO selection if SCO is requested but SCO is not ON 2559 return null; 2560 } 2561 return device; 2562 } 2563 2564 /** 2565 * Configures audio policy manager and audio HAL according to active communication route. 2566 * Always called from message Handler. 2567 */ 2568 // @GuardedBy("mSetModeLock") 2569 @GuardedBy("mDeviceStateLock") updateCommunicationRoute(String eventSource)2570 private void updateCommunicationRoute(String eventSource) { 2571 AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice(); 2572 if (AudioService.DEBUG_COMM_RTE) { 2573 Log.v(TAG, "updateCommunicationRoute, preferredCommunicationDevice: " 2574 + preferredCommunicationDevice + " eventSource: " + eventSource); 2575 } 2576 AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( 2577 "updateCommunicationRoute, preferredCommunicationDevice: " 2578 + preferredCommunicationDevice + " eventSource: " + eventSource))); 2579 2580 if (preferredCommunicationDevice == null) { 2581 AudioDeviceAttributes defaultDevice = getDefaultCommunicationDevice(); 2582 if (defaultDevice != null) { 2583 mDeviceInventory.setPreferredDevicesForStrategyInt( 2584 mCommunicationStrategyId, Arrays.asList(defaultDevice)); 2585 mDeviceInventory.setPreferredDevicesForStrategyInt( 2586 mAccessibilityStrategyId, Arrays.asList(defaultDevice)); 2587 } else { 2588 mDeviceInventory.removePreferredDevicesForStrategyInt(mCommunicationStrategyId); 2589 mDeviceInventory.removePreferredDevicesForStrategyInt(mAccessibilityStrategyId); 2590 } 2591 mDeviceInventory.applyConnectedDevicesRoles(); 2592 mDeviceInventory.reapplyExternalDevicesRoles(); 2593 } else { 2594 mDeviceInventory.setPreferredDevicesForStrategyInt( 2595 mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice)); 2596 mDeviceInventory.setPreferredDevicesForStrategyInt( 2597 mAccessibilityStrategyId, Arrays.asList(preferredCommunicationDevice)); 2598 } 2599 onUpdatePhoneStrategyDevice(preferredCommunicationDevice); 2600 } 2601 2602 // Pairs of input and output devices for duplex communication devices (headsets) 2603 private final HashMap<Integer, Integer> mDuplexCommunicationDevices = new HashMap<>( 2604 Map.of(DEVICE_OUT_BLE_HEADSET, DEVICE_IN_BLE_HEADSET, 2605 DEVICE_OUT_WIRED_HEADSET, DEVICE_IN_WIRED_HEADSET, 2606 DEVICE_OUT_USB_HEADSET, DEVICE_IN_USB_HEADSET, 2607 DEVICE_OUT_BLUETOOTH_SCO, DEVICE_IN_BLUETOOTH_SCO_HEADSET, 2608 DEVICE_OUT_BLUETOOTH_SCO_HEADSET, DEVICE_IN_BLUETOOTH_SCO_HEADSET, 2609 DEVICE_OUT_BLUETOOTH_SCO_CARKIT, DEVICE_IN_BLUETOOTH_SCO_HEADSET 2610 )); 2611 /** 2612 * Scan communication route clients and disable them if their selected device is not connected 2613 * or re-enable them if a device of the same type as their connected device is connected 2614 */ 2615 // @GuardedBy("mSetModeLock") 2616 @GuardedBy("mDeviceStateLock") checkCommunicationRouteClientsDevices()2617 private void checkCommunicationRouteClientsDevices() { 2618 for (CommunicationRouteClient crc : mCommunicationRouteClients) { 2619 int deviceType = crc.getDevice().getInternalType(); 2620 // Skip non detachable devices 2621 if (deviceType == DEVICE_OUT_EARPIECE || deviceType == DEVICE_OUT_SPEAKER 2622 || deviceType == DEVICE_OUT_BUS) { 2623 continue; 2624 } 2625 2626 // outDeviceSet is the expected connected output device types for the requested device 2627 Set<Integer> outDeviceSet = null; 2628 // inDeviceSet is the expected input device for outDeviceSet. Null for non 2629 // duplex devices 2630 Set<Integer> inDeviceSet = null; 2631 // Special case for SCO because several device types are equivalent 2632 if (isBluetoothScoOutDevice(deviceType)) { 2633 outDeviceSet = DEVICE_OUT_ALL_SCO_SET; 2634 inDeviceSet = DEVICE_IN_ALL_SCO_SET; 2635 } else { 2636 outDeviceSet = new HashSet<>(); 2637 outDeviceSet.add(deviceType); 2638 if (mDuplexCommunicationDevices.containsKey(deviceType)) { 2639 inDeviceSet = new HashSet<>(); 2640 inDeviceSet.add(mDuplexCommunicationDevices.get(deviceType)); 2641 } 2642 } 2643 2644 AudioDeviceAttributes outAda = 2645 mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(outDeviceSet); 2646 AudioDeviceAttributes inAda = (inDeviceSet == null) ? null 2647 : mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(inDeviceSet); 2648 2649 // A device is fully connected if the output device is connect and if not duplex 2650 // or an input device with the same address is connected 2651 boolean fullyConnected = outAda != null && (inDeviceSet == null 2652 || (inAda != null && inAda.getAddress().equals(outAda.getAddress()))); 2653 2654 if (fullyConnected) { 2655 crc.setDevice(outAda); 2656 if (crc.isDisabled()) { 2657 crc.setDisabled(false); 2658 if (AudioService.DEBUG_COMM_RTE) { 2659 Log.v(TAG, 2660 "checkCommunicationRouteClientsDevices, enabling client: " + crc); 2661 } 2662 } 2663 } else if (!crc.isDisabled()) { 2664 crc.setDisabled(true); 2665 if (AudioService.DEBUG_COMM_RTE) { 2666 Log.v(TAG, "checkCommunicationRouteClientsDevices, disabling client: " + crc); 2667 } 2668 } 2669 } 2670 } 2671 2672 /** 2673 * Select new communication device from communication route client at the top of the stack 2674 * and restore communication route including restarting SCO audio if needed. 2675 */ 2676 // @GuardedBy("mSetModeLock") 2677 @GuardedBy("mDeviceStateLock") onUpdateCommunicationRouteClient( @ullable AttributionSource previousBtScoRequesterAS, String eventSource)2678 private void onUpdateCommunicationRouteClient( 2679 @Nullable AttributionSource previousBtScoRequesterAS, String eventSource) { 2680 2681 CommunicationRouteClient crc = topCommunicationRouteClient(); 2682 if (AudioService.DEBUG_COMM_RTE) { 2683 Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc 2684 + " previous BT SCO Requester UID: " 2685 + safeUidFromAttributionSource(previousBtScoRequesterAS) 2686 + " eventSource: " + eventSource); 2687 } 2688 if (crc != null) { 2689 setCommunicationRouteForClient(crc.getBinder(), crc.getAttributionSource(), 2690 crc.getDevice(), BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource); 2691 } else { 2692 boolean wasScoRequested = previousBtScoRequesterAS != null; 2693 if (!isBluetoothScoRequested() && wasScoRequested) { 2694 if (mScoManagedByAudio) { 2695 if (shouldStartScoForAttributionSource(previousBtScoRequesterAS)) { 2696 mBtHelper.stopBluetoothSco(eventSource); 2697 } 2698 setBluetoothScoOn(false, eventSource); 2699 } else { 2700 mBtHelper.stopBluetoothSco(eventSource); 2701 } 2702 } 2703 updateCommunicationRoute(eventSource); 2704 } 2705 } 2706 2707 // @GuardedBy("mSetModeLock") 2708 @GuardedBy("mDeviceStateLock") onUpdatePhoneStrategyDevice(AudioDeviceAttributes device)2709 private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) { 2710 boolean wasSpeakerphoneActive = isSpeakerphoneActive(); 2711 mPreferredCommunicationDevice = device; 2712 updateActiveCommunicationDevice(); 2713 if (wasSpeakerphoneActive != isSpeakerphoneActive()) { 2714 try { 2715 mContext.sendBroadcastAsUser( 2716 new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED) 2717 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), 2718 UserHandle.ALL); 2719 } catch (Exception e) { 2720 Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e); 2721 } 2722 } 2723 dispatchCommunicationDevice(); 2724 mAudioService.postUpdateRingerModeServiceInt(); 2725 } 2726 2727 @GuardedBy("mDeviceStateLock") removeCommunicationRouteClient( IBinder cb, boolean unregister)2728 private CommunicationRouteClient removeCommunicationRouteClient( 2729 IBinder cb, boolean unregister) { 2730 for (CommunicationRouteClient cl : mCommunicationRouteClients) { 2731 if (cl.getBinder() == cb) { 2732 if (unregister) { 2733 cl.unregisterDeathRecipient(); 2734 } 2735 removeMsgForCheckClientState(cl.getUid()); 2736 mCommunicationRouteClients.remove(cl); 2737 return cl; 2738 } 2739 } 2740 return null; 2741 } 2742 2743 @GuardedBy("mDeviceStateLock") addCommunicationRouteClient( IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, boolean isPrivileged)2744 private CommunicationRouteClient addCommunicationRouteClient( 2745 IBinder cb, @NonNull AttributionSource attributionSource, AudioDeviceAttributes device, 2746 boolean isPrivileged) { 2747 // always insert new request at first position 2748 removeCommunicationRouteClient(cb, true); 2749 CommunicationRouteClient client = 2750 new CommunicationRouteClient(cb, attributionSource, device, isPrivileged); 2751 if (client.registerDeathRecipient()) { 2752 mCommunicationRouteClients.add(0, client); 2753 if (!client.isActive()) { 2754 // initialize the inactive client's state as active and check it after 6 seconds 2755 setForceCommunicationClientStateAndDelayedCheck( 2756 client, 2757 !mAudioService.isPlaybackActiveForUid(client.getUid()), 2758 !mAudioService.isRecordingActiveForUid(client.getUid())); 2759 } 2760 return client; 2761 } 2762 return null; 2763 } 2764 2765 @GuardedBy("mDeviceStateLock") getCommunicationRouteClientForUid(int uid)2766 private CommunicationRouteClient getCommunicationRouteClientForUid(int uid) { 2767 for (CommunicationRouteClient cl : mCommunicationRouteClients) { 2768 if (cl.getUid() == uid) { 2769 return cl; 2770 } 2771 } 2772 return null; 2773 } 2774 2775 @GuardedBy("mDeviceStateLock") 2776 // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio 2777 // policy routing rules select the default communication device. 2778 // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE 2779 // Audiodevice explicitly. communnicationDeviceLeAudioCompatOn()2780 private boolean communnicationDeviceLeAudioCompatOn() { 2781 return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION 2782 && !(CompatChanges.isChangeEnabled( 2783 USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid) 2784 || mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID); 2785 } 2786 2787 @GuardedBy("mDeviceStateLock") 2788 // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio 2789 // policy routing rules select the default communication device. 2790 // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain 2791 // backwards compatibility communnicationDeviceHaCompatOn()2792 private boolean communnicationDeviceHaCompatOn() { 2793 return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION 2794 && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID); 2795 } 2796 2797 @GuardedBy("mDeviceStateLock") getDefaultCommunicationDevice()2798 AudioDeviceAttributes getDefaultCommunicationDevice() { 2799 AudioDeviceAttributes device = null; 2800 // If both LE and Hearing Aid are active (thie should not happen), 2801 // priority to Hearing Aid. 2802 if (communnicationDeviceHaCompatOn()) { 2803 device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID); 2804 } 2805 if (device == null && communnicationDeviceLeAudioCompatOn()) { 2806 device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET); 2807 } 2808 return device; 2809 } 2810 updateCommunicationRouteClientsActivity( List<AudioPlaybackConfiguration> playbackConfigs, List<AudioRecordingConfiguration> recordConfigs)2811 void updateCommunicationRouteClientsActivity( 2812 List<AudioPlaybackConfiguration> playbackConfigs, 2813 List<AudioRecordingConfiguration> recordConfigs) { 2814 synchronized (mSetModeLock) { 2815 synchronized (mDeviceStateLock) { 2816 for (CommunicationRouteClient crc : mCommunicationRouteClients) { 2817 boolean wasActive = crc.isActive(); 2818 boolean updateClientState = false; 2819 if (playbackConfigs != null) { 2820 crc.setPlaybackActive(false); 2821 for (AudioPlaybackConfiguration config : playbackConfigs) { 2822 if (config.getClientUid() == crc.getUid() 2823 && config.isActive()) { 2824 crc.setPlaybackActive(true); 2825 updateClientState = true; 2826 break; 2827 } 2828 } 2829 } 2830 if (recordConfigs != null) { 2831 crc.setRecordingActive(false); 2832 for (AudioRecordingConfiguration config : recordConfigs) { 2833 if (config.getClientUid() == crc.getUid() 2834 && !config.isClientSilenced()) { 2835 crc.setRecordingActive(true); 2836 updateClientState = true; 2837 break; 2838 } 2839 } 2840 } 2841 if (updateClientState) { 2842 removeMsgForCheckClientState(crc.getUid()); 2843 updateCommunicationRouteClientState(crc, wasActive); 2844 } else { 2845 if (wasActive) { 2846 setForceCommunicationClientStateAndDelayedCheck( 2847 crc, 2848 playbackConfigs != null /* forcePlaybackActive */, 2849 recordConfigs != null /* forceRecordingActive */); 2850 } 2851 } 2852 } 2853 } 2854 } 2855 } 2856 getDeviceIdentityAddresses(AudioDeviceAttributes device)2857 List<String> getDeviceIdentityAddresses(AudioDeviceAttributes device) { 2858 synchronized (mDeviceStateLock) { 2859 return mDeviceInventory.getDeviceIdentityAddresses(device); 2860 } 2861 } 2862 dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(AudioDeviceInfo info)2863 void dispatchPreferredMixerAttributesChangedCausedByDeviceRemoved(AudioDeviceInfo info) { 2864 // Currently, only media usage will be allowed to set preferred mixer attributes 2865 mAudioService.dispatchPreferredMixerAttributesChanged( 2866 new AudioAttributes.Builder() 2867 .setUsage(AudioAttributes.USAGE_MEDIA).build(), 2868 info.getId(), 2869 null /*mixerAttributes*/); 2870 } 2871 2872 /** 2873 * post a message to persist the audio device settings. 2874 * Message is delayed by 1s on purpose in case of successive changes in quick succession (at 2875 * init time for instance) 2876 * Note this method is made public to work around a Mockito bug where it needs to be public 2877 * in order to be mocked by a test a the same package 2878 * (see https://code.google.com/archive/p/mockito/issues/127) 2879 */ postPersistAudioDeviceSettings()2880 public void postPersistAudioDeviceSettings() { 2881 sendMsg(MSG_PERSIST_AUDIO_DEVICE_SETTINGS, SENDMSG_REPLACE, /*delay*/ 1000); 2882 } 2883 onPersistAudioDeviceSettings()2884 void onPersistAudioDeviceSettings() { 2885 final String deviceSettings = mDeviceInventory.getDeviceSettings(); 2886 Log.v(TAG, "onPersistAudioDeviceSettings AdiDeviceState: " + deviceSettings); 2887 String currentSettings = readDeviceSettings(); 2888 if (deviceSettings.equals(currentSettings)) { 2889 return; 2890 } 2891 final SettingsAdapter settingsAdapter = mAudioService.getSettings(); 2892 if (settingsAdapter == null) { 2893 Log.e(TAG, "No settings adapter when saving AdiDeviceState: " + deviceSettings); 2894 return; 2895 } 2896 try { 2897 boolean res = settingsAdapter.putSecureStringForUser(mAudioService.getContentResolver(), 2898 Settings.Secure.AUDIO_DEVICE_INVENTORY, 2899 deviceSettings, UserHandle.USER_CURRENT); 2900 if (!res) { 2901 Log.e(TAG, "error saving AdiDeviceState: " + deviceSettings); 2902 } 2903 } catch (IllegalArgumentException e) { 2904 Log.e(TAG, "error saving AdiDeviceState: " + deviceSettings, e); 2905 } 2906 } 2907 readDeviceSettings()2908 private String readDeviceSettings() { 2909 final SettingsAdapter settingsAdapter = mAudioService.getSettings(); 2910 final ContentResolver contentResolver = mAudioService.getContentResolver(); 2911 if (settingsAdapter == null || contentResolver == null) { 2912 // should not happen, throw Exception for stack trace 2913 Log.e(TAG, "No settings adapter or content resolver to read device settings", 2914 new Exception("readDeviceSettings_NPE")); 2915 return ""; 2916 } 2917 return settingsAdapter.getSecureStringForUser(contentResolver, 2918 Settings.Secure.AUDIO_DEVICE_INVENTORY, UserHandle.USER_CURRENT); 2919 } 2920 onReadAudioDeviceSettings()2921 void onReadAudioDeviceSettings() { 2922 final SettingsAdapter settingsAdapter = mAudioService.getSettings(); 2923 final ContentResolver contentResolver = mAudioService.getContentResolver(); 2924 String settings = readDeviceSettings(); 2925 if (settings == null) { 2926 Log.i(TAG, "reading AdiDeviceState from legacy key" 2927 + Settings.Secure.SPATIAL_AUDIO_ENABLED); 2928 // legacy string format for key SPATIAL_AUDIO_ENABLED has the same order of fields like 2929 // the strings for key AUDIO_DEVICE_INVENTORY. This will ensure to construct valid 2930 // device settings when calling {@link #setDeviceSettings()} 2931 settings = settingsAdapter.getSecureStringForUser(contentResolver, 2932 Settings.Secure.SPATIAL_AUDIO_ENABLED, UserHandle.USER_CURRENT); 2933 if (settings == null) { 2934 Log.i(TAG, "no AdiDeviceState stored with legacy key"); 2935 } else if (!settings.equals("")) { 2936 // Delete old key value and update the new key 2937 if (!settingsAdapter.putSecureStringForUser(contentResolver, 2938 Settings.Secure.SPATIAL_AUDIO_ENABLED, 2939 /*value=*/"", 2940 UserHandle.USER_CURRENT)) { 2941 Log.w(TAG, "cannot erase the legacy AdiDeviceState with key " 2942 + Settings.Secure.SPATIAL_AUDIO_ENABLED); 2943 } 2944 if (!settingsAdapter.putSecureStringForUser(contentResolver, 2945 Settings.Secure.AUDIO_DEVICE_INVENTORY, 2946 settings, 2947 UserHandle.USER_CURRENT)) { 2948 Log.e(TAG, "error updating the new AdiDeviceState with key " 2949 + Settings.Secure.AUDIO_DEVICE_INVENTORY); 2950 } 2951 } 2952 } 2953 2954 if (settings != null && !settings.equals("")) { 2955 setDeviceSettings(settings); 2956 } 2957 } 2958 setDeviceSettings(String settings)2959 void setDeviceSettings(String settings) { 2960 mDeviceInventory.setDeviceSettings(settings); 2961 } 2962 2963 /** Test only method. */ getDeviceSettings()2964 String getDeviceSettings() { 2965 return mDeviceInventory.getDeviceSettings(); 2966 } 2967 getImmutableDeviceInventory()2968 Collection<AdiDeviceState> getImmutableDeviceInventory() { 2969 return mDeviceInventory.getImmutableDeviceInventory(); 2970 } 2971 addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState, boolean syncInventory)2972 void addOrUpdateDeviceSAStateInInventory(AdiDeviceState deviceState, boolean syncInventory) { 2973 mDeviceInventory.addOrUpdateDeviceSAStateInInventory(deviceState, syncInventory); 2974 } 2975 addOrUpdateBtAudioDeviceCategoryInInventory( AdiDeviceState deviceState, boolean syncInventory)2976 void addOrUpdateBtAudioDeviceCategoryInInventory( 2977 AdiDeviceState deviceState, boolean syncInventory) { 2978 mDeviceInventory.addOrUpdateAudioDeviceCategoryInInventory(deviceState, syncInventory); 2979 } 2980 2981 @Nullable findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada, int canonicalType)2982 AdiDeviceState findDeviceStateForAudioDeviceAttributes(AudioDeviceAttributes ada, 2983 int canonicalType) { 2984 return mDeviceInventory.findDeviceStateForAudioDeviceAttributes(ada, canonicalType); 2985 } 2986 2987 @Nullable findBtDeviceStateForAddress(String address, int deviceType)2988 AdiDeviceState findBtDeviceStateForAddress(String address, int deviceType) { 2989 return mDeviceInventory.findBtDeviceStateForAddress(address, deviceType); 2990 } 2991 addAudioDeviceWithCategoryInInventoryIfNeeded(@onNull String address, @AudioDeviceCategory int btAudioDeviceCategory)2992 void addAudioDeviceWithCategoryInInventoryIfNeeded(@NonNull String address, 2993 @AudioDeviceCategory int btAudioDeviceCategory) { 2994 mDeviceInventory.addAudioDeviceWithCategoryInInventoryIfNeeded(address, 2995 btAudioDeviceCategory); 2996 } 2997 2998 @AudioDeviceCategory getAndUpdateBtAdiDeviceStateCategoryForAddress(@onNull String address)2999 int getAndUpdateBtAdiDeviceStateCategoryForAddress(@NonNull String address) { 3000 return mDeviceInventory.getAndUpdateBtAdiDeviceStateCategoryForAddress(address); 3001 } 3002 isBluetoothAudioDeviceCategoryFixed(@onNull String address)3003 boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) { 3004 return mDeviceInventory.isBluetoothAudioDeviceCategoryFixed(address); 3005 } 3006 isSADevice(AdiDeviceState deviceState)3007 /*package*/ boolean isSADevice(AdiDeviceState deviceState) { 3008 return mAudioService.isSADevice(deviceState); 3009 } 3010 3011 //------------------------------------------------ 3012 // for testing purposes only clearDeviceInventory()3013 void clearDeviceInventory() { 3014 mDeviceInventory.clearDeviceInventory(); 3015 } 3016 3017 } 3018