1 /* 2 * Copyright (C) 2023 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 17 package com.android.server.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.bluetooth.BluetoothA2dp; 22 import android.bluetooth.BluetoothAdapter; 23 import android.bluetooth.BluetoothDevice; 24 import android.bluetooth.BluetoothHearingAid; 25 import android.bluetooth.BluetoothLeAudio; 26 import android.bluetooth.BluetoothProfile; 27 import android.content.Context; 28 29 import java.util.Objects; 30 31 /* package */ class BluetoothProfileMonitor { 32 33 /* package */ static final long GROUP_ID_NO_GROUP = -1L; 34 35 @NonNull 36 private final ProfileListener mProfileListener = new ProfileListener(); 37 38 @NonNull 39 private final Context mContext; 40 @NonNull 41 private final BluetoothAdapter mBluetoothAdapter; 42 43 @Nullable 44 private BluetoothA2dp mA2dpProfile; 45 @Nullable 46 private BluetoothHearingAid mHearingAidProfile; 47 @Nullable 48 private BluetoothLeAudio mLeAudioProfile; 49 BluetoothProfileMonitor(@onNull Context context, @NonNull BluetoothAdapter bluetoothAdapter)50 BluetoothProfileMonitor(@NonNull Context context, 51 @NonNull BluetoothAdapter bluetoothAdapter) { 52 mContext = Objects.requireNonNull(context); 53 mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter); 54 } 55 start()56 /* package */ void start() { 57 mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); 58 mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID); 59 mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.LE_AUDIO); 60 } 61 isProfileSupported(int profile, @NonNull BluetoothDevice device)62 /* package */ boolean isProfileSupported(int profile, @NonNull BluetoothDevice device) { 63 BluetoothProfile bluetoothProfile; 64 65 synchronized (this) { 66 switch (profile) { 67 case BluetoothProfile.A2DP: 68 bluetoothProfile = mA2dpProfile; 69 break; 70 case BluetoothProfile.LE_AUDIO: 71 bluetoothProfile = mLeAudioProfile; 72 break; 73 case BluetoothProfile.HEARING_AID: 74 bluetoothProfile = mHearingAidProfile; 75 break; 76 default: 77 throw new IllegalArgumentException(profile 78 + " is not supported as Bluetooth profile"); 79 } 80 } 81 82 if (bluetoothProfile == null) { 83 return false; 84 } 85 86 return bluetoothProfile.getConnectedDevices().contains(device); 87 } 88 getGroupId(int profile, @NonNull BluetoothDevice device)89 /* package */ long getGroupId(int profile, @NonNull BluetoothDevice device) { 90 synchronized (this) { 91 switch (profile) { 92 case BluetoothProfile.A2DP: 93 return GROUP_ID_NO_GROUP; 94 case BluetoothProfile.LE_AUDIO: 95 return mLeAudioProfile == null ? GROUP_ID_NO_GROUP : mLeAudioProfile.getGroupId( 96 device); 97 case BluetoothProfile.HEARING_AID: 98 return mHearingAidProfile == null 99 ? GROUP_ID_NO_GROUP : mHearingAidProfile.getHiSyncId(device); 100 default: 101 throw new IllegalArgumentException(profile 102 + " is not supported as Bluetooth profile"); 103 } 104 } 105 } 106 107 private final class ProfileListener implements BluetoothProfile.ServiceListener { 108 @Override onServiceConnected(int profile, BluetoothProfile proxy)109 public void onServiceConnected(int profile, BluetoothProfile proxy) { 110 synchronized (BluetoothProfileMonitor.this) { 111 switch (profile) { 112 case BluetoothProfile.A2DP: 113 mA2dpProfile = (BluetoothA2dp) proxy; 114 break; 115 case BluetoothProfile.HEARING_AID: 116 mHearingAidProfile = (BluetoothHearingAid) proxy; 117 break; 118 case BluetoothProfile.LE_AUDIO: 119 mLeAudioProfile = (BluetoothLeAudio) proxy; 120 break; 121 } 122 } 123 } 124 125 @Override onServiceDisconnected(int profile)126 public void onServiceDisconnected(int profile) { 127 synchronized (BluetoothProfileMonitor.this) { 128 switch (profile) { 129 case BluetoothProfile.A2DP: 130 mA2dpProfile = null; 131 break; 132 case BluetoothProfile.HEARING_AID: 133 mHearingAidProfile = null; 134 break; 135 case BluetoothProfile.LE_AUDIO: 136 mLeAudioProfile = null; 137 break; 138 } 139 } 140 } 141 } 142 } 143