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