1 /* 2 * Copyright (C) 2017 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.car; 17 18 19 import android.bluetooth.BluetoothProfile; 20 import android.bluetooth.BluetoothA2dpSink; 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothHeadsetClient; 24 import android.bluetooth.BluetoothMapClient; 25 import android.bluetooth.BluetoothPbapClient; 26 import android.car.ICarBluetoothUserService; 27 import android.util.Log; 28 29 import java.util.Arrays; 30 import java.util.List; 31 32 33 public class CarBluetoothUserService extends ICarBluetoothUserService.Stub { 34 private static final boolean DBG = true; 35 private static final String TAG = "CarBluetoothUsrSvc"; 36 private BluetoothAdapter mBluetoothAdapter = null; 37 private final PerUserCarService mService; 38 // Profile Proxies. 39 private BluetoothA2dpSink mBluetoothA2dpSink = null; 40 private BluetoothHeadsetClient mBluetoothHeadsetClient = null; 41 private BluetoothPbapClient mBluetoothPbapClient = null; 42 private BluetoothMapClient mBluetoothMapClient = null; 43 private List<Integer> mProfilesToConnect; 44 CarBluetoothUserService(PerUserCarService service)45 public CarBluetoothUserService(PerUserCarService service) { 46 mService = service; 47 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 48 mProfilesToConnect = Arrays.asList( 49 BluetoothProfile.HEADSET_CLIENT, 50 BluetoothProfile.PBAP_CLIENT, 51 BluetoothProfile.A2DP_SINK, 52 BluetoothProfile.MAP_CLIENT); 53 } 54 55 /** 56 * Setup connections to the profile proxy object to talk to the Bluetooth profile services 57 */ 58 @Override setupBluetoothConnectionProxy()59 public void setupBluetoothConnectionProxy() { 60 if (DBG) { 61 Log.d(TAG, "setupProfileProxy()"); 62 } 63 if (mBluetoothAdapter == null) { 64 Log.d(TAG, "Null BT Adapter"); 65 return; 66 } 67 for (Integer profile : mProfilesToConnect) { 68 mBluetoothAdapter.getProfileProxy(mService.getApplicationContext(), mProfileListener, 69 profile); 70 } 71 } 72 73 /** 74 * Close connections to the profile proxy object 75 */ 76 @Override closeBluetoothConnectionProxy()77 public void closeBluetoothConnectionProxy() { 78 if (mBluetoothAdapter == null) { 79 return; 80 } 81 if (DBG) { 82 Log.d(TAG, "closeProfileProxy()"); 83 } 84 // Close those profile proxy objects for profiles that have not yet disconnected 85 if (mBluetoothA2dpSink != null) { 86 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP_SINK, mBluetoothA2dpSink); 87 } 88 if (mBluetoothHeadsetClient != null) { 89 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET_CLIENT, 90 mBluetoothHeadsetClient); 91 } 92 if (mBluetoothPbapClient != null) { 93 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PBAP_CLIENT, mBluetoothPbapClient); 94 } 95 if (mBluetoothMapClient != null) { 96 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.MAP_CLIENT, mBluetoothMapClient); 97 } 98 } 99 100 /** 101 * Check if a proxy is available for the given profile to talk to the Profile's bluetooth 102 * service. 103 * @param profile - Bluetooth profile to check for 104 * @return - true if proxy available, false if not. 105 */ 106 @Override isBluetoothConnectionProxyAvailable(int profile)107 public boolean isBluetoothConnectionProxyAvailable(int profile) { 108 switch (profile) { 109 case BluetoothProfile.A2DP_SINK: 110 if (mBluetoothA2dpSink != null) { 111 return true; 112 } 113 break; 114 case BluetoothProfile.HEADSET_CLIENT: 115 if (mBluetoothHeadsetClient != null) { 116 return true; 117 } 118 break; 119 case BluetoothProfile.PBAP_CLIENT: 120 if (mBluetoothPbapClient != null) { 121 return true; 122 } 123 break; 124 case BluetoothProfile.MAP_CLIENT: 125 if (mBluetoothMapClient != null) { 126 return true; 127 } 128 break; 129 } 130 return false; 131 } 132 133 @Override bluetoothConnectToProfile(int profile, BluetoothDevice device)134 public void bluetoothConnectToProfile(int profile, BluetoothDevice device) { 135 if (!isBluetoothConnectionProxyAvailable(profile)) { 136 Log.e(TAG, "Cannot connect to Profile. Proxy Unavailable"); 137 return; 138 } 139 if (DBG) { 140 Log.d(TAG, "Trying to connect to " + device.getName() + " Profile: " + profile); 141 } 142 switch (profile) { 143 case BluetoothProfile.A2DP_SINK: 144 mBluetoothA2dpSink.connect(device); 145 break; 146 147 case BluetoothProfile.HEADSET_CLIENT: 148 mBluetoothHeadsetClient.connect(device); 149 break; 150 151 case BluetoothProfile.MAP_CLIENT: 152 mBluetoothMapClient.connect(device); 153 break; 154 155 case BluetoothProfile.PBAP_CLIENT: 156 mBluetoothPbapClient.connect(device); 157 break; 158 159 default: 160 Log.d(TAG, "Unknown profile"); 161 break; 162 } 163 return; 164 } 165 166 /** 167 * Set the priority of the given Bluetooth profile for the given remote device 168 * @param profile - Bluetooth profile 169 * @param device - remote Bluetooth device 170 * @param priority - priority to set 171 */ 172 @Override setProfilePriority(int profile, BluetoothDevice device, int priority)173 public void setProfilePriority(int profile, BluetoothDevice device, int priority) { 174 if (!isBluetoothConnectionProxyAvailable(profile)) { 175 Log.e(TAG, "Cannot connect to Profile. Proxy Unavailable"); 176 return; 177 } 178 switch (profile) { 179 case BluetoothProfile.A2DP_SINK: 180 mBluetoothA2dpSink.setPriority(device, priority); 181 break; 182 case BluetoothProfile.HEADSET_CLIENT: 183 mBluetoothHeadsetClient.setPriority(device, priority); 184 break; 185 case BluetoothProfile.MAP_CLIENT: 186 mBluetoothMapClient.setPriority(device, priority); 187 break; 188 case BluetoothProfile.PBAP_CLIENT: 189 mBluetoothPbapClient.setPriority(device, priority); 190 break; 191 default: 192 Log.d(TAG, "Unknown Profile"); 193 break; 194 } 195 } 196 /** 197 * All the BluetoothProfile.ServiceListeners to get the Profile Proxy objects 198 */ 199 private BluetoothProfile.ServiceListener mProfileListener = 200 new BluetoothProfile.ServiceListener() { 201 public void onServiceConnected(int profile, BluetoothProfile proxy) { 202 if (DBG) { 203 Log.d(TAG, "OnServiceConnected profile: " + profile); 204 } 205 switch (profile) { 206 case BluetoothProfile.A2DP_SINK: 207 mBluetoothA2dpSink = (BluetoothA2dpSink) proxy; 208 break; 209 210 case BluetoothProfile.HEADSET_CLIENT: 211 mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy; 212 break; 213 214 case BluetoothProfile.PBAP_CLIENT: 215 mBluetoothPbapClient = (BluetoothPbapClient) proxy; 216 break; 217 218 case BluetoothProfile.MAP_CLIENT: 219 mBluetoothMapClient = (BluetoothMapClient) proxy; 220 break; 221 222 default: 223 if (DBG) { 224 Log.d(TAG, "Unhandled profile"); 225 } 226 break; 227 } 228 } 229 230 public void onServiceDisconnected(int profile) { 231 if (DBG) { 232 Log.d(TAG, "onServiceDisconnected profile: " + profile); 233 } 234 switch (profile) { 235 case BluetoothProfile.A2DP_SINK: 236 mBluetoothA2dpSink = null; 237 break; 238 239 case BluetoothProfile.HEADSET_CLIENT: 240 mBluetoothHeadsetClient = null; 241 break; 242 243 case BluetoothProfile.PBAP_CLIENT: 244 mBluetoothPbapClient = null; 245 break; 246 247 case BluetoothProfile.MAP_CLIENT: 248 mBluetoothMapClient = null; 249 break; 250 251 default: 252 if (DBG) { 253 Log.d(TAG, "Unhandled profile"); 254 } 255 break; 256 } 257 } 258 }; 259 } 260