blob: 13beb9b5d913dc8b76c23d2be993a8dfdb993fbd [file] [log] [blame]
Ram Periathiruvadiacb60242017-04-13 16:19:09 -07001/*
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 */
16package com.android.car;
17
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070018import android.bluetooth.BluetoothA2dpSink;
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothDevice;
21import android.bluetooth.BluetoothHeadsetClient;
22import android.bluetooth.BluetoothMapClient;
Joseph Pirozzo99aeba92018-02-05 14:48:49 -080023import android.bluetooth.BluetoothPan;
Justin Paupore7b17ea62018-12-28 20:27:33 -080024import android.bluetooth.BluetoothPbapClient;
25import android.bluetooth.BluetoothProfile;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070026import android.car.ICarBluetoothUserService;
Felipe Leme83a3de92020-12-09 16:04:51 -080027import android.util.IndentingPrintWriter;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070028import android.util.Log;
Felipe Leme83a3de92020-12-09 16:04:51 -080029import android.util.Slog;
Sal Savage703c46f2019-04-15 08:39:25 -070030import android.util.SparseBooleanArray;
31
Joseph Pirozzoee3f7132021-03-08 13:05:18 -080032import com.android.car.bluetooth.FastPairProvider;
33
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070034import java.util.Arrays;
35import java.util.List;
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000036import java.util.Objects;
Sal Savage703c46f2019-04-15 08:39:25 -070037import java.util.concurrent.TimeUnit;
38import java.util.concurrent.locks.Condition;
39import java.util.concurrent.locks.ReentrantLock;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070040
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070041public class CarBluetoothUserService extends ICarBluetoothUserService.Stub {
Felipe Leme83a3de92020-12-09 16:04:51 -080042
Mayank Garg72c71d22021-02-03 23:54:45 -080043 private static final String TAG = CarLog.tagFor(CarBluetoothUserService.class);
Felipe Leme83a3de92020-12-09 16:04:51 -080044
45 private static final int PROXY_OPERATION_TIMEOUT_MS = 8_000;
Sal Savage703c46f2019-04-15 08:39:25 -070046
47 // Profiles we support
48 private static final List<Integer> sProfilesToConnect = Arrays.asList(
49 BluetoothProfile.HEADSET_CLIENT,
50 BluetoothProfile.PBAP_CLIENT,
51 BluetoothProfile.A2DP_SINK,
52 BluetoothProfile.MAP_CLIENT,
53 BluetoothProfile.PAN
54 );
55
Felipe Leme83a3de92020-12-09 16:04:51 -080056 private final PerUserCarService mService;
57 private final BluetoothAdapter mBluetoothAdapter;
58
Sal Savage703c46f2019-04-15 08:39:25 -070059 // Profile Proxies Objects to pair with above list. Access to these proxy objects will all be
Sal Savageeb0f5012019-07-18 09:37:38 -070060 // guarded by the below mBluetoothProxyLock
Felipe Leme83a3de92020-12-09 16:04:51 -080061 private BluetoothA2dpSink mBluetoothA2dpSink;
62 private BluetoothHeadsetClient mBluetoothHeadsetClient;
63 private BluetoothPbapClient mBluetoothPbapClient;
64 private BluetoothMapClient mBluetoothMapClient;
65 private BluetoothPan mBluetoothPan;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070066
Sal Savageeb0f5012019-07-18 09:37:38 -070067 // Concurrency variables for waitForProxies. Used so we can best effort block with a timeout
68 // while waiting for services to be bound to the proxy objects.
69 private final ReentrantLock mBluetoothProxyLock;
Sal Savage703c46f2019-04-15 08:39:25 -070070 private final Condition mConditionAllProxiesConnected;
Joseph Pirozzoee3f7132021-03-08 13:05:18 -080071 private final FastPairProvider mFastPairProvider;
Sal Savage703c46f2019-04-15 08:39:25 -070072 private SparseBooleanArray mBluetoothProfileStatus;
73 private int mConnectedProfiles;
Sal Savage703c46f2019-04-15 08:39:25 -070074
75 /**
76 * Create a CarBluetoothUserService instance.
77 *
Gregory Clarkcebacef2019-07-09 16:27:36 -070078 * @param service - A reference to a PerUserCarService, so we can use its context to receive
Sal Savage703c46f2019-04-15 08:39:25 -070079 * updates as a particular user.
80 */
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070081 public CarBluetoothUserService(PerUserCarService service) {
82 mService = service;
Sal Savage703c46f2019-04-15 08:39:25 -070083 mConnectedProfiles = 0;
84 mBluetoothProfileStatus = new SparseBooleanArray();
85 for (int profile : sProfilesToConnect) {
86 mBluetoothProfileStatus.put(profile, false);
87 }
Sal Savageeb0f5012019-07-18 09:37:38 -070088 mBluetoothProxyLock = new ReentrantLock();
89 mConditionAllProxiesConnected = mBluetoothProxyLock.newCondition();
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070090 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Daulet Zhanguzin4ded6782020-01-03 15:47:10 +000091 Objects.requireNonNull(mBluetoothAdapter, "Bluetooth adapter cannot be null");
Joseph Pirozzoee3f7132021-03-08 13:05:18 -080092 mFastPairProvider = new FastPairProvider(service);
Ram Periathiruvadiacb60242017-04-13 16:19:09 -070093 }
94
95 /**
Sal Savage703c46f2019-04-15 08:39:25 -070096 * Setup connections to the profile proxy objects that talk to the Bluetooth profile services.
97 *
Sal Savageeb0f5012019-07-18 09:37:38 -070098 * Proxy references are held by the Bluetooth Framework on our behalf. We will be notified each
99 * time the underlying service connects for each proxy we create. Notifications stop when we
100 * close the proxy. As such, each time this is called we clean up any existing proxies before
101 * creating new ones.
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700102 */
103 @Override
Sal Savage703c46f2019-04-15 08:39:25 -0700104 public void setupBluetoothConnectionProxies() {
105 logd("Initiate connections to profile proxies");
Sal Savage703c46f2019-04-15 08:39:25 -0700106
Sal Savageeb0f5012019-07-18 09:37:38 -0700107 // Clear existing proxy objects
108 closeBluetoothConnectionProxies();
Sal Savage703c46f2019-04-15 08:39:25 -0700109
Sal Savageeb0f5012019-07-18 09:37:38 -0700110 // Create proxy for each supported profile. Objects arrive later in the profile listener.
111 // Operations on the proxies expect them to be connected. Functions below should call
112 // waitForProxies() to best effort wait for them to be up if Bluetooth is enabled.
113 for (int profile : sProfilesToConnect) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800114 logd("Creating proxy for %s", Utils.getProfileName(profile));
Sal Savageeb0f5012019-07-18 09:37:38 -0700115 mBluetoothAdapter.getProfileProxy(mService.getApplicationContext(),
116 mProfileListener, profile);
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700117 }
Joseph Pirozzoee3f7132021-03-08 13:05:18 -0800118 mFastPairProvider.start();
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700119 }
120
121 /**
Sal Savage703c46f2019-04-15 08:39:25 -0700122 * Close connections to the profile proxy objects
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700123 */
124 @Override
Sal Savageeb0f5012019-07-18 09:37:38 -0700125 public void closeBluetoothConnectionProxies() {
126 logd("Clean up profile proxy objects");
127 mBluetoothProxyLock.lock();
Sal Savage703c46f2019-04-15 08:39:25 -0700128 try {
Sal Savageeb0f5012019-07-18 09:37:38 -0700129 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP_SINK, mBluetoothA2dpSink);
130 mBluetoothA2dpSink = null;
131 mBluetoothProfileStatus.put(BluetoothProfile.A2DP_SINK, false);
Sal Savage703c46f2019-04-15 08:39:25 -0700132
Sal Savageeb0f5012019-07-18 09:37:38 -0700133 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET_CLIENT,
134 mBluetoothHeadsetClient);
135 mBluetoothHeadsetClient = null;
136 mBluetoothProfileStatus.put(BluetoothProfile.HEADSET_CLIENT, false);
Sal Savage703c46f2019-04-15 08:39:25 -0700137
Sal Savageeb0f5012019-07-18 09:37:38 -0700138 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PBAP_CLIENT, mBluetoothPbapClient);
139 mBluetoothPbapClient = null;
140 mBluetoothProfileStatus.put(BluetoothProfile.PBAP_CLIENT, false);
141
142 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.MAP_CLIENT, mBluetoothMapClient);
143 mBluetoothMapClient = null;
144 mBluetoothProfileStatus.put(BluetoothProfile.MAP_CLIENT, false);
145
146 mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothPan);
147 mBluetoothPan = null;
148 mBluetoothProfileStatus.put(BluetoothProfile.PAN, false);
149
150 mConnectedProfiles = 0;
Sal Savage703c46f2019-04-15 08:39:25 -0700151 } finally {
Sal Savageeb0f5012019-07-18 09:37:38 -0700152 mBluetoothProxyLock.unlock();
Joseph Pirozzo99aeba92018-02-05 14:48:49 -0800153 }
Joseph Pirozzoee3f7132021-03-08 13:05:18 -0800154 mFastPairProvider.stop();
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700155 }
156
157 /**
Sal Savage703c46f2019-04-15 08:39:25 -0700158 * Listen for and collect Bluetooth profile proxy connections and disconnections.
159 */
160 private BluetoothProfile.ServiceListener mProfileListener =
161 new BluetoothProfile.ServiceListener() {
162 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800163 logd("onServiceConnected profile: %s", Utils.getProfileName(profile));
Sal Savage703c46f2019-04-15 08:39:25 -0700164
165 // Grab the profile proxy object and update the status book keeping in one step so the
166 // book keeping and proxy objects never disagree
Sal Savageeb0f5012019-07-18 09:37:38 -0700167 mBluetoothProxyLock.lock();
168 try {
Sal Savage703c46f2019-04-15 08:39:25 -0700169 switch (profile) {
170 case BluetoothProfile.A2DP_SINK:
171 mBluetoothA2dpSink = (BluetoothA2dpSink) proxy;
172 break;
173 case BluetoothProfile.HEADSET_CLIENT:
174 mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
175 break;
176 case BluetoothProfile.PBAP_CLIENT:
177 mBluetoothPbapClient = (BluetoothPbapClient) proxy;
178 break;
179 case BluetoothProfile.MAP_CLIENT:
180 mBluetoothMapClient = (BluetoothMapClient) proxy;
181 break;
182 case BluetoothProfile.PAN:
183 mBluetoothPan = (BluetoothPan) proxy;
184 break;
185 default:
Felipe Leme83a3de92020-12-09 16:04:51 -0800186 logd("Unhandled profile connected: %s", Utils.getProfileName(profile));
Sal Savage703c46f2019-04-15 08:39:25 -0700187 break;
188 }
189
Sal Savageeb0f5012019-07-18 09:37:38 -0700190 if (!mBluetoothProfileStatus.get(profile, false)) {
191 mBluetoothProfileStatus.put(profile, true);
192 mConnectedProfiles++;
193 if (mConnectedProfiles == sProfilesToConnect.size()) {
194 logd("All profiles have connected");
195 mConditionAllProxiesConnected.signal();
Sal Savage703c46f2019-04-15 08:39:25 -0700196 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700197 } else {
Felipe Leme83a3de92020-12-09 16:04:51 -0800198 Slog.w(TAG, "Received duplicate service connection event for: "
Sal Savageeb0f5012019-07-18 09:37:38 -0700199 + Utils.getProfileName(profile));
Sal Savage703c46f2019-04-15 08:39:25 -0700200 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700201 } finally {
202 mBluetoothProxyLock.unlock();
Sal Savage703c46f2019-04-15 08:39:25 -0700203 }
204 }
205
206 public void onServiceDisconnected(int profile) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800207 logd("onServiceDisconnected profile: %s", Utils.getProfileName(profile));
Sal Savageeb0f5012019-07-18 09:37:38 -0700208 mBluetoothProxyLock.lock();
209 try {
210 if (mBluetoothProfileStatus.get(profile, false)) {
211 mBluetoothProfileStatus.put(profile, false);
212 mConnectedProfiles--;
213 } else {
Felipe Leme83a3de92020-12-09 16:04:51 -0800214 Slog.w(TAG, "Received duplicate service disconnection event for: "
Sal Savageeb0f5012019-07-18 09:37:38 -0700215 + Utils.getProfileName(profile));
Sal Savage703c46f2019-04-15 08:39:25 -0700216 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700217 } finally {
218 mBluetoothProxyLock.unlock();
Sal Savage703c46f2019-04-15 08:39:25 -0700219 }
220 }
221 };
222
223 /**
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700224 * Check if a proxy is available for the given profile to talk to the Profile's bluetooth
225 * service.
Sal Savageeb0f5012019-07-18 09:37:38 -0700226 *
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700227 * @param profile - Bluetooth profile to check for
228 * @return - true if proxy available, false if not.
229 */
230 @Override
231 public boolean isBluetoothConnectionProxyAvailable(int profile) {
Sal Savageeb0f5012019-07-18 09:37:38 -0700232 if (!mBluetoothAdapter.isEnabled()) return false;
Sal Savage703c46f2019-04-15 08:39:25 -0700233 boolean proxyConnected = false;
Sal Savageeb0f5012019-07-18 09:37:38 -0700234 mBluetoothProxyLock.lock();
Sal Savage703c46f2019-04-15 08:39:25 -0700235 try {
236 proxyConnected = mBluetoothProfileStatus.get(profile, false);
237 } finally {
Sal Savageeb0f5012019-07-18 09:37:38 -0700238 mBluetoothProxyLock.unlock();
Sal Savage703c46f2019-04-15 08:39:25 -0700239 }
240 return proxyConnected;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700241 }
242
Sal Savageeb0f5012019-07-18 09:37:38 -0700243 /**
244 * Wait for the proxy objects to be up for all profiles, with a timeout.
245 *
246 * @param timeout Amount of time in milliseconds to wait for giving up on the wait operation
247 * @return True if the condition was satisfied within the timeout, False otherwise
248 */
249 private boolean waitForProxies(int timeout /* ms */) {
250 logd("waitForProxies()");
251 // If bluetooth isn't on then the operation waiting on proxies was never meant to actually
252 // work regardless if Bluetooth comes on within the timeout period or not. Return false.
253 if (!mBluetoothAdapter.isEnabled()) return false;
254 try {
255 while (mConnectedProfiles != sProfilesToConnect.size()) {
256 if (!mConditionAllProxiesConnected.await(
257 timeout, TimeUnit.MILLISECONDS)) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800258 Slog.e(TAG, "Timeout while waiting for proxies, Connected: "
259 + mConnectedProfiles + "/" + sProfilesToConnect.size());
Sal Savageeb0f5012019-07-18 09:37:38 -0700260 return false;
261 }
262 }
263 } catch (InterruptedException e) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800264 Slog.w(TAG, "waitForProxies: interrupted", e);
265 Thread.currentThread().interrupt();
Sal Savageeb0f5012019-07-18 09:37:38 -0700266 return false;
267 }
268 return true;
269 }
270
271 /**
272 * Connect a given remote device on a specific Bluetooth profile
273 *
274 * @param profile BluetoothProfile.* based profile ID
275 * @param device The device you wish to connect
276 */
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700277 @Override
Sal Savage619b04b2019-05-10 10:45:27 -0700278 public boolean bluetoothConnectToProfile(int profile, BluetoothDevice device) {
Justin Paupore7b17ea62018-12-28 20:27:33 -0800279 if (device == null) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800280 Slog.e(TAG, "Cannot connect to profile on null device");
Sal Savage619b04b2019-05-10 10:45:27 -0700281 return false;
Justin Paupore7b17ea62018-12-28 20:27:33 -0800282 }
Felipe Leme83a3de92020-12-09 16:04:51 -0800283 logd("Trying to connect to %s (%s) Profile: %s", device.getName(), device.getAddress(),
284 Utils.getProfileName(profile));
Sal Savageeb0f5012019-07-18 09:37:38 -0700285 mBluetoothProxyLock.lock();
286 try {
Sal Savagec2b779f2021-06-28 13:17:06 -0700287 if (!isBluetoothConnectionProxyAvailable(profile)) {
288 if (!waitForProxies(PROXY_OPERATION_TIMEOUT_MS)
289 && !isBluetoothConnectionProxyAvailable(profile)) {
290 Slog.e(TAG, "Cannot connect to Profile. Proxy Unavailable");
291 return false;
292 }
Sal Savage2d87f352019-03-29 11:34:30 -0700293 }
294 switch (profile) {
295 case BluetoothProfile.A2DP_SINK:
Sal Savage619b04b2019-05-10 10:45:27 -0700296 return mBluetoothA2dpSink.connect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700297 case BluetoothProfile.HEADSET_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700298 return mBluetoothHeadsetClient.connect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700299 case BluetoothProfile.MAP_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700300 return mBluetoothMapClient.connect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700301 case BluetoothProfile.PBAP_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700302 return mBluetoothPbapClient.connect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700303 case BluetoothProfile.PAN:
Sal Savage619b04b2019-05-10 10:45:27 -0700304 return mBluetoothPan.connect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700305 default:
Felipe Leme83a3de92020-12-09 16:04:51 -0800306 Slog.w(TAG, "Unknown Profile: " + Utils.getProfileName(profile));
Sal Savage2d87f352019-03-29 11:34:30 -0700307 break;
308 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700309 } finally {
310 mBluetoothProxyLock.unlock();
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700311 }
Sal Savage619b04b2019-05-10 10:45:27 -0700312 return false;
Justin Paupore7b17ea62018-12-28 20:27:33 -0800313 }
314
Sal Savageeb0f5012019-07-18 09:37:38 -0700315 /**
316 * Disonnect a given remote device from a specific Bluetooth profile
317 *
318 * @param profile BluetoothProfile.* based profile ID
319 * @param device The device you wish to disconnect
320 */
Justin Paupore7b17ea62018-12-28 20:27:33 -0800321 @Override
Sal Savage619b04b2019-05-10 10:45:27 -0700322 public boolean bluetoothDisconnectFromProfile(int profile, BluetoothDevice device) {
Justin Paupore7b17ea62018-12-28 20:27:33 -0800323 if (device == null) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800324 Slog.e(TAG, "Cannot disconnect from profile on null device");
Sal Savage619b04b2019-05-10 10:45:27 -0700325 return false;
Justin Paupore7b17ea62018-12-28 20:27:33 -0800326 }
Felipe Leme83a3de92020-12-09 16:04:51 -0800327 logd("Trying to disconnect from %s (%s) Profile: %s", device.getName(), device.getAddress(),
328 Utils.getProfileName(profile));
Sal Savageeb0f5012019-07-18 09:37:38 -0700329 mBluetoothProxyLock.lock();
330 try {
Sal Savagec2b779f2021-06-28 13:17:06 -0700331 if (!isBluetoothConnectionProxyAvailable(profile)) {
332 if (!waitForProxies(PROXY_OPERATION_TIMEOUT_MS)
333 && !isBluetoothConnectionProxyAvailable(profile)) {
334 Slog.e(TAG, "Cannot disconnect from Profile. Proxy Unavailable");
335 return false;
336 }
Sal Savage2d87f352019-03-29 11:34:30 -0700337 }
338 switch (profile) {
339 case BluetoothProfile.A2DP_SINK:
Sal Savage619b04b2019-05-10 10:45:27 -0700340 return mBluetoothA2dpSink.disconnect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700341 case BluetoothProfile.HEADSET_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700342 return mBluetoothHeadsetClient.disconnect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700343 case BluetoothProfile.MAP_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700344 return mBluetoothMapClient.disconnect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700345 case BluetoothProfile.PBAP_CLIENT:
Sal Savage619b04b2019-05-10 10:45:27 -0700346 return mBluetoothPbapClient.disconnect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700347 case BluetoothProfile.PAN:
Sal Savage619b04b2019-05-10 10:45:27 -0700348 return mBluetoothPan.disconnect(device);
Sal Savage2d87f352019-03-29 11:34:30 -0700349 default:
Felipe Leme83a3de92020-12-09 16:04:51 -0800350 Slog.w(TAG, "Unknown Profile: " + Utils.getProfileName(profile));
Sal Savage2d87f352019-03-29 11:34:30 -0700351 break;
352 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700353 } finally {
354 mBluetoothProxyLock.unlock();
Justin Paupore7b17ea62018-12-28 20:27:33 -0800355 }
Sal Savage619b04b2019-05-10 10:45:27 -0700356 return false;
Justin Paupore7b17ea62018-12-28 20:27:33 -0800357 }
358
359 /**
360 * Get the priority of the given Bluetooth profile for the given remote device
Sal Savageeb0f5012019-07-18 09:37:38 -0700361 *
Justin Paupore7b17ea62018-12-28 20:27:33 -0800362 * @param profile - Bluetooth profile
363 * @param device - remote Bluetooth device
364 */
365 @Override
366 public int getProfilePriority(int profile, BluetoothDevice device) {
Justin Paupore7b17ea62018-12-28 20:27:33 -0800367 if (device == null) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800368 Slog.e(TAG, "Cannot get " + Utils.getProfileName(profile)
Sal Savage703c46f2019-04-15 08:39:25 -0700369 + " profile priority on null device");
Justin Paupore7b17ea62018-12-28 20:27:33 -0800370 return BluetoothProfile.PRIORITY_UNDEFINED;
371 }
372 int priority;
Sal Savageeb0f5012019-07-18 09:37:38 -0700373 mBluetoothProxyLock.lock();
374 try {
Sal Savagec2b779f2021-06-28 13:17:06 -0700375 if (!isBluetoothConnectionProxyAvailable(profile)) {
376 if (!waitForProxies(PROXY_OPERATION_TIMEOUT_MS)
377 && !isBluetoothConnectionProxyAvailable(profile)) {
378 Slog.e(TAG, "Cannot get " + Utils.getProfileName(profile)
379 + " profile priority. Proxy Unavailable");
380 return BluetoothProfile.PRIORITY_UNDEFINED;
381 }
Sal Savage2d87f352019-03-29 11:34:30 -0700382 }
383 switch (profile) {
384 case BluetoothProfile.A2DP_SINK:
385 priority = mBluetoothA2dpSink.getPriority(device);
386 break;
387 case BluetoothProfile.HEADSET_CLIENT:
388 priority = mBluetoothHeadsetClient.getPriority(device);
389 break;
390 case BluetoothProfile.MAP_CLIENT:
391 priority = mBluetoothMapClient.getPriority(device);
392 break;
393 case BluetoothProfile.PBAP_CLIENT:
394 priority = mBluetoothPbapClient.getPriority(device);
395 break;
396 default:
Felipe Leme83a3de92020-12-09 16:04:51 -0800397 Slog.w(TAG, "Unknown Profile: " + Utils.getProfileName(profile));
Sal Savage703c46f2019-04-15 08:39:25 -0700398 priority = BluetoothProfile.PRIORITY_UNDEFINED;
399 break;
Sal Savage2d87f352019-03-29 11:34:30 -0700400 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700401 } finally {
402 mBluetoothProxyLock.unlock();
Justin Paupore7b17ea62018-12-28 20:27:33 -0800403 }
Felipe Leme83a3de92020-12-09 16:04:51 -0800404 logd("%s priority for %s (%s) = %d", Utils.getProfileName(profile), device.getName(),
405 device.getAddress(), priority);
Justin Paupore7b17ea62018-12-28 20:27:33 -0800406 return priority;
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700407 }
408
409 /**
Ram Periathiruvadibe7ea0fe2017-05-31 23:31:40 -0700410 * Set the priority of the given Bluetooth profile for the given remote device
Sal Savageeb0f5012019-07-18 09:37:38 -0700411 *
Ram Periathiruvadibe7ea0fe2017-05-31 23:31:40 -0700412 * @param profile - Bluetooth profile
413 * @param device - remote Bluetooth device
414 * @param priority - priority to set
415 */
416 @Override
417 public void setProfilePriority(int profile, BluetoothDevice device, int priority) {
Justin Paupore7b17ea62018-12-28 20:27:33 -0800418 if (device == null) {
Felipe Leme83a3de92020-12-09 16:04:51 -0800419 Slog.e(TAG, "Cannot set " + Utils.getProfileName(profile)
Sal Savage703c46f2019-04-15 08:39:25 -0700420 + " profile priority on null device");
Justin Paupore7b17ea62018-12-28 20:27:33 -0800421 return;
422 }
Felipe Leme83a3de92020-12-09 16:04:51 -0800423 logd("Setting %s priority for %s (%s) to %d", Utils.getProfileName(profile),
424 device.getName(), device.getAddress(), priority);
Sal Savageeb0f5012019-07-18 09:37:38 -0700425 mBluetoothProxyLock.lock();
426 try {
Sal Savagec2b779f2021-06-28 13:17:06 -0700427 if (!isBluetoothConnectionProxyAvailable(profile)) {
428 if (!waitForProxies(PROXY_OPERATION_TIMEOUT_MS)
429 && !isBluetoothConnectionProxyAvailable(profile)) {
430 Slog.e(TAG, "Cannot set " + Utils.getProfileName(profile)
431 + " profile priority. Proxy Unavailable");
432 return;
433 }
Sal Savage2d87f352019-03-29 11:34:30 -0700434 }
435 switch (profile) {
436 case BluetoothProfile.A2DP_SINK:
437 mBluetoothA2dpSink.setPriority(device, priority);
438 break;
439 case BluetoothProfile.HEADSET_CLIENT:
440 mBluetoothHeadsetClient.setPriority(device, priority);
441 break;
442 case BluetoothProfile.MAP_CLIENT:
443 mBluetoothMapClient.setPriority(device, priority);
444 break;
445 case BluetoothProfile.PBAP_CLIENT:
446 mBluetoothPbapClient.setPriority(device, priority);
447 break;
448 default:
Felipe Leme83a3de92020-12-09 16:04:51 -0800449 Slog.w(TAG, "Unknown Profile: " + Utils.getProfileName(profile));
Sal Savage2d87f352019-03-29 11:34:30 -0700450 break;
451 }
Sal Savageeb0f5012019-07-18 09:37:38 -0700452 } finally {
453 mBluetoothProxyLock.unlock();
Ram Periathiruvadibe7ea0fe2017-05-31 23:31:40 -0700454 }
455 }
Sal Savage2d87f352019-03-29 11:34:30 -0700456
Felipe Leme83a3de92020-12-09 16:04:51 -0800457 void dump(IndentingPrintWriter pw) {
458 pw.printf("Supported profiles: %s\n", sProfilesToConnect);
459 pw.printf("Number of connected profiles: %d\n", mConnectedProfiles);
460 pw.printf("Profiles status: %s\n", mBluetoothProfileStatus);
461 pw.printf("Proxy operation timeout: %d ms\n", PROXY_OPERATION_TIMEOUT_MS);
462 pw.printf("BluetoothAdapter: %s\n", mBluetoothAdapter);
463 pw.printf("BluetoothA2dpSink: %s\n", mBluetoothA2dpSink);
464 pw.printf("BluetoothHeadsetClient: %s\n", mBluetoothHeadsetClient);
465 pw.printf("BluetoothPbapClient: %s\n", mBluetoothPbapClient);
466 pw.printf("BluetoothMapClient: %s\n", mBluetoothMapClient);
467 pw.printf("BluetoothPan: %s\n", mBluetoothPan);
Joseph Pirozzoee3f7132021-03-08 13:05:18 -0800468 mFastPairProvider.dump(pw);
Felipe Leme83a3de92020-12-09 16:04:51 -0800469 }
470
Ram Periathiruvadibe7ea0fe2017-05-31 23:31:40 -0700471 /**
Sal Savage703c46f2019-04-15 08:39:25 -0700472 * Log to debug if debug output is enabled
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700473 */
Felipe Leme83a3de92020-12-09 16:04:51 -0800474 private void logd(String message, Object... args) {
475 if (Log.isLoggable(TAG, Log.DEBUG)) {
476 Slog.d(TAG, String.format(message, args));
Sal Savage703c46f2019-04-15 08:39:25 -0700477 }
478 }
Ram Periathiruvadiacb60242017-04-13 16:19:09 -0700479}