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