blob: b255a43cbe3066fb1e4c4d26f92243be2b236648 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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
17package android.bluetooth;
18
Tor Norbye2d497522015-04-23 17:10:21 -070019import android.Manifest;
Pavlin Radoslavov64a94352017-12-19 13:20:06 -080020import android.annotation.Nullable;
Tor Norbye2d497522015-04-23 17:10:21 -070021import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080024import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080026import android.content.Intent;
27import android.content.ServiceConnection;
RoboErik4197cb62015-01-21 15:45:32 -080028import android.media.AudioManager;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060029import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070031import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070032import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.Log;
34
Calvin Ond7d16b92016-06-20 15:59:48 -070035import com.android.internal.annotations.GuardedBy;
36
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070037import java.util.ArrayList;
38import java.util.List;
Calvin Ond7d16b92016-06-20 15:59:48 -070039import java.util.concurrent.locks.ReentrantReadWriteLock;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070043 * This class provides the public APIs to control the Bluetooth A2DP
44 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 *
Jack Hea355e5e2017-08-22 16:06:54 -070046 * <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070047 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
48 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070050 * <p> Android only supports one connected Bluetooth A2dp device at a time.
51 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070053public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080055 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070056 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070058 /**
59 * Intent used to broadcast the change in connection state of the A2DP
60 * profile.
61 *
62 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080063 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070064 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
65 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
66 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080067 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070068 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080069 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070070 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
71 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
72 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080073 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
74 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 */
76 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070077 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070078 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070080 /**
81 * Intent used to broadcast the change in the Playing state of the A2DP
82 * profile.
83 *
84 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080085 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070086 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
87 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
88 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080089 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070090 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080091 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070092 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
93 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080094 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
95 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070096 */
97 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
98 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070099 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530101 /** @hide */
102 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
103 public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700104 "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530105
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700106 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800107 * Intent used to broadcast the selection of a connected device as active.
108 *
109 * <p>This intent will have one extra:
110 * <ul>
111 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
112 * be null if no device is active. </li>
113 * </ul>
114 *
115 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
116 * receive.
117 *
118 * @hide
119 */
120 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
121 public static final String ACTION_ACTIVE_DEVICE_CHANGED =
122 "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
123
124 /**
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800125 * Intent used to broadcast the change in the Audio Codec state of the
126 * A2DP Source profile.
127 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800128 * <p>This intent will have 2 extras:
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800129 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700130 * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
131 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
132 * connected, otherwise it is not included.</li>
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800133 * </ul>
134 *
135 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
136 * receive.
137 *
138 * @hide
139 */
140 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
141 public static final String ACTION_CODEC_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700142 "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800143
144 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700145 * A2DP sink device is streaming music. This state can be one of
146 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
147 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
148 */
Jack Hea355e5e2017-08-22 16:06:54 -0700149 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -0700150
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700151 /**
152 * A2DP sink device is NOT streaming music. This state can be one of
153 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
154 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
155 */
Jack Hea355e5e2017-08-22 16:06:54 -0700156 public static final int STATE_NOT_PLAYING = 11;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700157
Antony Sargentf5772c62017-04-26 16:37:53 -0700158 /**
159 * We don't have a stored preference for whether or not the given A2DP sink device supports
160 * optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700161 *
162 * @hide
163 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700164 public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
165
166 /**
167 * The given A2DP sink device does not support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700168 *
169 * @hide
170 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700171 public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
172
173 /**
174 * The given A2DP sink device does support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700175 *
176 * @hide
177 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700178 public static final int OPTIONAL_CODECS_SUPPORTED = 1;
179
180 /**
181 * We don't have a stored preference for whether optional codecs should be enabled or disabled
182 * for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700183 *
184 * @hide
185 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700186 public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
187
188 /**
189 * Optional codecs should be disabled for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700190 *
191 * @hide
192 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700193 public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
194
195 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700196 * Optional codecs should be enabled for the given A2DP device.
197 *
198 * @hide
199 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700200 public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
201
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800202 private Context mContext;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700203 private ServiceListener mServiceListener;
Calvin Ond7d16b92016-06-20 15:59:48 -0700204 private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
Jack Hea355e5e2017-08-22 16:06:54 -0700205 @GuardedBy("mServiceLock")
206 private IBluetoothA2dp mService;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700207 private BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
Jack He2992cd02017-08-22 21:21:23 -0700209 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
fredc0f420372012-04-12 00:02:00 -0700210 new IBluetoothStateChangeCallback.Stub() {
211 public void onBluetoothStateChange(boolean up) {
212 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
213 if (!up) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700214 if (VDBG) Log.d(TAG, "Unbinding service...");
215 try {
216 mServiceLock.writeLock().lock();
217 mService = null;
218 mContext.unbindService(mConnection);
219 } catch (Exception re) {
220 Log.e(TAG, "", re);
221 } finally {
222 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700223 }
224 } else {
Calvin Ond7d16b92016-06-20 15:59:48 -0700225 try {
226 mServiceLock.readLock().lock();
227 if (mService == null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700228 if (VDBG) Log.d(TAG, "Binding service...");
Calvin Ond7d16b92016-06-20 15:59:48 -0700229 doBind();
fredc0f420372012-04-12 00:02:00 -0700230 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700231 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700232 Log.e(TAG, "", re);
Calvin Ond7d16b92016-06-20 15:59:48 -0700233 } finally {
234 mServiceLock.readLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700235 }
236 }
237 }
Jack Hea355e5e2017-08-22 16:06:54 -0700238 };
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 /**
241 * Create a BluetoothA2dp proxy object for interacting with the local
242 * Bluetooth A2DP service.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 */
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800244 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
245 mContext = context;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700246 mServiceListener = l;
247 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700248 IBluetoothManager mgr = mAdapter.getBluetoothManager();
249 if (mgr != null) {
250 try {
251 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
252 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700253 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700254 }
255 }
256
Dianne Hackborn221ea892013-08-04 16:50:16 -0700257 doBind();
258 }
259
260 boolean doBind() {
261 Intent intent = new Intent(IBluetoothA2dp.class.getName());
262 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
263 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700264 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
265 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700266 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
267 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700269 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 }
271
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800272 /*package*/ void close() {
273 mServiceListener = null;
fredc0f420372012-04-12 00:02:00 -0700274 IBluetoothManager mgr = mAdapter.getBluetoothManager();
275 if (mgr != null) {
276 try {
277 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
278 } catch (Exception e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700279 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700280 }
281 }
282
Calvin Ond7d16b92016-06-20 15:59:48 -0700283 try {
284 mServiceLock.writeLock().lock();
fredc0f420372012-04-12 00:02:00 -0700285 if (mService != null) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700286 mService = null;
287 mContext.unbindService(mConnection);
fredc0f420372012-04-12 00:02:00 -0700288 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700289 } catch (Exception re) {
290 Log.e(TAG, "", re);
291 } finally {
292 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700293 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800294 }
295
Jack He2992cd02017-08-22 21:21:23 -0700296 @Override
fredc0f420372012-04-12 00:02:00 -0700297 public void finalize() {
Mathias Jeppsson2d2d8c22013-08-06 11:41:55 +0200298 // The empty finalize needs to be kept or the
299 // cts signature tests would fail.
fredc0f420372012-04-12 00:02:00 -0700300 }
Jack Hea355e5e2017-08-22 16:06:54 -0700301
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700302 /**
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800303 * Initiate connection to a profile of the remote Bluetooth device.
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700304 *
305 * <p> This API returns false in scenarios like the profile on the
306 * device is already connected or Bluetooth is not turned on.
307 * When this API returns true, it is guaranteed that
308 * connection state intent for the profile will be broadcasted with
309 * the state. Users can get the connection state of the profile
310 * from this intent.
311 *
312 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
313 * permission.
314 *
315 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700316 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700317 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700319 public boolean connect(BluetoothDevice device) {
320 if (DBG) log("connect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700321 try {
322 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700323 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700324 return mService.connect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700325 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700326 if (mService == null) Log.w(TAG, "Proxy not attached to service");
327 return false;
328 } catch (RemoteException e) {
329 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
330 return false;
331 } finally {
332 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
334 }
335
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700336 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700337 * Initiate disconnection from a profile
338 *
339 * <p> This API will return false in scenarios like the profile on the
340 * Bluetooth device is not in connected state etc. When this API returns,
341 * true, it is guaranteed that the connection state change
342 * intent will be broadcasted with the state. Users can get the
343 * disconnection state of the profile from this intent.
344 *
345 * <p> If the disconnection is initiated by a remote device, the state
346 * will transition from {@link #STATE_CONNECTED} to
347 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
348 * host (local) device the state will transition from
349 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
350 * state {@link #STATE_DISCONNECTED}. The transition to
351 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
352 * two scenarios.
353 *
354 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
355 * permission.
356 *
357 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700358 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700359 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700361 public boolean disconnect(BluetoothDevice device) {
362 if (DBG) log("disconnect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700363 try {
364 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700365 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700366 return mService.disconnect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700367 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700368 if (mService == null) Log.w(TAG, "Proxy not attached to service");
369 return false;
370 } catch (RemoteException e) {
371 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
372 return false;
373 } finally {
374 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376 }
377
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700378 /**
379 * {@inheritDoc}
380 */
Jack He2992cd02017-08-22 21:21:23 -0700381 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700382 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700383 if (VDBG) log("getConnectedDevices()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700384 try {
385 mServiceLock.readLock().lock();
386 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700387 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700388 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700389 if (mService == null) Log.w(TAG, "Proxy not attached to service");
390 return new ArrayList<BluetoothDevice>();
391 } catch (RemoteException e) {
392 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
393 return new ArrayList<BluetoothDevice>();
394 } finally {
395 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700396 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700397 }
398
399 /**
400 * {@inheritDoc}
401 */
Jack He2992cd02017-08-22 21:21:23 -0700402 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700403 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700404 if (VDBG) log("getDevicesMatchingStates()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700405 try {
406 mServiceLock.readLock().lock();
407 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700408 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700409 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700410 if (mService == null) Log.w(TAG, "Proxy not attached to service");
411 return new ArrayList<BluetoothDevice>();
412 } catch (RemoteException e) {
413 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
414 return new ArrayList<BluetoothDevice>();
415 } finally {
416 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700417 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700418 }
419
420 /**
421 * {@inheritDoc}
422 */
Jack He2992cd02017-08-22 21:21:23 -0700423 @Override
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700424 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700425 if (VDBG) log("getState(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700426 try {
427 mServiceLock.readLock().lock();
428 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700429 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700430 return mService.getConnectionState(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700431 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700432 if (mService == null) Log.w(TAG, "Proxy not attached to service");
433 return BluetoothProfile.STATE_DISCONNECTED;
434 } catch (RemoteException e) {
435 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
436 return BluetoothProfile.STATE_DISCONNECTED;
437 } finally {
438 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700439 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700440 }
441
442 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800443 * Select a connected device as active.
444 *
445 * The active device selection is per profile. An active device's
446 * purpose is profile-specific. For example, A2DP audio streaming
447 * is to the active A2DP Sink device. If a remote device is not
448 * connected, it cannot be selected as active.
449 *
450 * <p> This API returns false in scenarios like the profile on the
451 * device is not connected or Bluetooth is not turned on.
452 * When this API returns true, it is guaranteed that the
453 * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
454 * with the active device.
455 *
456 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
457 * permission.
458 *
459 * @param device the remote Bluetooth device. Could be null to clear
460 * the active device and stop streaming audio to a Bluetooth device.
461 * @return false on immediate error, true otherwise
462 * @hide
463 */
464 public boolean setActiveDevice(@Nullable BluetoothDevice device) {
465 if (DBG) log("setActiveDevice(" + device + ")");
466 try {
467 mServiceLock.readLock().lock();
468 if (mService != null && isEnabled()
469 && ((device == null) || isValidDevice(device))) {
470 return mService.setActiveDevice(device);
471 }
472 if (mService == null) Log.w(TAG, "Proxy not attached to service");
473 return false;
474 } catch (RemoteException e) {
475 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
476 return false;
477 } finally {
478 mServiceLock.readLock().unlock();
479 }
480 }
481
482 /**
483 * Get the connected device that is active.
484 *
485 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
486 * permission.
487 *
488 * @return the connected device that is active or null if no device
489 * is active
490 * @hide
491 */
492 @RequiresPermission(Manifest.permission.BLUETOOTH)
493 @Nullable
494 public BluetoothDevice getActiveDevice() {
495 if (VDBG) log("getActiveDevice()");
496 try {
497 mServiceLock.readLock().lock();
498 if (mService != null && isEnabled()) {
499 return mService.getActiveDevice();
500 }
501 if (mService == null) Log.w(TAG, "Proxy not attached to service");
502 return null;
503 } catch (RemoteException e) {
504 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
505 return null;
506 } finally {
507 mServiceLock.readLock().unlock();
508 }
509 }
510
511 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700512 * Set priority of the profile
513 *
514 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700515 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700516 * {@link #PRIORITY_OFF},
517 *
518 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
519 * permission.
520 *
521 * @param device Paired bluetooth device
522 * @param priority
523 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700524 * @hide
525 */
526 public boolean setPriority(BluetoothDevice device, int priority) {
527 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700528 try {
529 mServiceLock.readLock().lock();
530 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700531 && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700532 if (priority != BluetoothProfile.PRIORITY_OFF
533 && priority != BluetoothProfile.PRIORITY_ON) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700534 return false;
535 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700536 return mService.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700537 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700538 if (mService == null) Log.w(TAG, "Proxy not attached to service");
539 return false;
540 } catch (RemoteException e) {
541 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
542 return false;
543 } finally {
544 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700545 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700546 }
547
548 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700549 * Get the priority of the profile.
550 *
551 * <p> The priority can be any of:
552 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
553 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
554 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700555 * @param device Bluetooth device
556 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700557 * @hide
558 */
Tor Norbye2d497522015-04-23 17:10:21 -0700559 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700560 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700561 if (VDBG) log("getPriority(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700562 try {
563 mServiceLock.readLock().lock();
564 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700565 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700566 return mService.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700567 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700568 if (mService == null) Log.w(TAG, "Proxy not attached to service");
569 return BluetoothProfile.PRIORITY_OFF;
570 } catch (RemoteException e) {
571 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
572 return BluetoothProfile.PRIORITY_OFF;
573 } finally {
574 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700575 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700576 }
577
578 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700579 * Checks if Avrcp device supports the absolute volume feature.
580 *
581 * @return true if device supports absolute volume
582 * @hide
583 */
584 public boolean isAvrcpAbsoluteVolumeSupported() {
585 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
Calvin Ond7d16b92016-06-20 15:59:48 -0700586 try {
587 mServiceLock.readLock().lock();
588 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700589 return mService.isAvrcpAbsoluteVolumeSupported();
John Du5a0cf7a2013-07-19 11:30:34 -0700590 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700591 if (mService == null) Log.w(TAG, "Proxy not attached to service");
592 return false;
593 } catch (RemoteException e) {
594 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
595 return false;
596 } finally {
597 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700598 }
John Du5a0cf7a2013-07-19 11:30:34 -0700599 }
600
601 /**
RoboErik4197cb62015-01-21 15:45:32 -0800602 * Tells remote device to adjust volume. Only if absolute volume is
603 * supported. Uses the following values:
604 * <ul>
605 * <li>{@link AudioManager#ADJUST_LOWER}</li>
606 * <li>{@link AudioManager#ADJUST_RAISE}</li>
607 * <li>{@link AudioManager#ADJUST_MUTE}</li>
608 * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
609 * </ul>
John Du5a0cf7a2013-07-19 11:30:34 -0700610 *
RoboErik4197cb62015-01-21 15:45:32 -0800611 * @param direction One of the supported adjust values.
John Du5a0cf7a2013-07-19 11:30:34 -0700612 * @hide
613 */
614 public void adjustAvrcpAbsoluteVolume(int direction) {
615 if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700616 try {
617 mServiceLock.readLock().lock();
618 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700619 mService.adjustAvrcpAbsoluteVolume(direction);
John Du5a0cf7a2013-07-19 11:30:34 -0700620 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700621 if (mService == null) Log.w(TAG, "Proxy not attached to service");
622 } catch (RemoteException e) {
623 Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
624 } finally {
625 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700626 }
John Du5a0cf7a2013-07-19 11:30:34 -0700627 }
628
629 /**
630 * Tells remote device to set an absolute volume. Only if absolute volume is supported
631 *
632 * @param volume Absolute volume to be set on AVRCP side
633 * @hide
634 */
635 public void setAvrcpAbsoluteVolume(int volume) {
636 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700637 try {
638 mServiceLock.readLock().lock();
639 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700640 mService.setAvrcpAbsoluteVolume(volume);
John Du5a0cf7a2013-07-19 11:30:34 -0700641 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700642 if (mService == null) Log.w(TAG, "Proxy not attached to service");
643 } catch (RemoteException e) {
644 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
645 } finally {
646 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700647 }
John Du5a0cf7a2013-07-19 11:30:34 -0700648 }
649
650 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700651 * Check if A2DP profile is streaming music.
652 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800653 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700654 *
655 * @param device BluetoothDevice device
656 */
657 public boolean isA2dpPlaying(BluetoothDevice device) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700658 try {
659 mServiceLock.readLock().lock();
660 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700661 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700662 return mService.isA2dpPlaying(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700663 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700664 if (mService == null) Log.w(TAG, "Proxy not attached to service");
665 return false;
666 } catch (RemoteException e) {
667 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
668 return false;
669 } finally {
670 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700671 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700672 }
673
674 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700675 * This function checks if the remote device is an AVCRP
676 * target and thus whether we should send volume keys
677 * changes or not.
Jack Hea355e5e2017-08-22 16:06:54 -0700678 *
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700679 * @hide
680 */
681 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
682 if (isEnabled() && isValidDevice(device)) {
683 ParcelUuid[] uuids = device.getUuids();
684 if (uuids == null) return false;
685
Jack Hea355e5e2017-08-22 16:06:54 -0700686 for (ParcelUuid uuid : uuids) {
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700687 if (BluetoothUuid.isAvrcpTarget(uuid)) {
688 return true;
689 }
690 }
691 }
692 return false;
693 }
694
Matthew Xiea0c68032011-06-25 21:47:07 -0700695 /**
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800696 * Gets the current codec status (configuration and capability).
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800697 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800698 * @param device the remote Bluetooth device. If null, use the current
699 * active A2DP Bluetooth device.
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800700 * @return the current codec status
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800701 * @hide
702 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800703 public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
704 if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800705 try {
706 mServiceLock.readLock().lock();
707 if (mService != null && isEnabled()) {
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800708 return mService.getCodecStatus(device);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800709 }
710 if (mService == null) {
711 Log.w(TAG, "Proxy not attached to service");
712 }
713 return null;
714 } catch (RemoteException e) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800715 Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800716 return null;
717 } finally {
718 mServiceLock.readLock().unlock();
719 }
720 }
721
722 /**
723 * Sets the codec configuration preference.
724 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800725 * @param device the remote Bluetooth device. If null, use the current
726 * active A2DP Bluetooth device.
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800727 * @param codecConfig the codec configuration preference
728 * @hide
729 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800730 public void setCodecConfigPreference(BluetoothDevice device,
731 BluetoothCodecConfig codecConfig) {
732 if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800733 try {
734 mServiceLock.readLock().lock();
735 if (mService != null && isEnabled()) {
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800736 mService.setCodecConfigPreference(device, codecConfig);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800737 }
738 if (mService == null) Log.w(TAG, "Proxy not attached to service");
739 return;
740 } catch (RemoteException e) {
741 Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
742 return;
743 } finally {
744 mServiceLock.readLock().unlock();
745 }
746 }
747
748 /**
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800749 * Enables the optional codecs.
750 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800751 * @param device the remote Bluetooth device. If null, use the currect
752 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800753 * @hide
754 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800755 public void enableOptionalCodecs(BluetoothDevice device) {
756 if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
757 enableDisableOptionalCodecs(device, true);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800758 }
759
760 /**
761 * Disables the optional codecs.
762 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800763 * @param device the remote Bluetooth device. If null, use the currect
764 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800765 * @hide
766 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800767 public void disableOptionalCodecs(BluetoothDevice device) {
768 if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
769 enableDisableOptionalCodecs(device, false);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800770 }
771
772 /**
773 * Enables or disables the optional codecs.
774 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800775 * @param device the remote Bluetooth device. If null, use the currect
776 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800777 * @param enable if true, enable the optional codecs, other disable them
778 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800779 private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800780 try {
781 mServiceLock.readLock().lock();
782 if (mService != null && isEnabled()) {
783 if (enable) {
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800784 mService.enableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800785 } else {
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800786 mService.disableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800787 }
788 }
789 if (mService == null) Log.w(TAG, "Proxy not attached to service");
790 return;
791 } catch (RemoteException e) {
792 Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
793 return;
794 } finally {
795 mServiceLock.readLock().unlock();
796 }
797 }
798
799 /**
Antony Sargentf5772c62017-04-26 16:37:53 -0700800 * Returns whether this device supports optional codecs.
801 *
802 * @param device The device to check
803 * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700804 * OPTIONAL_CODECS_SUPPORTED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700805 * @hide
806 */
807 public int supportsOptionalCodecs(BluetoothDevice device) {
808 try {
809 mServiceLock.readLock().lock();
810 if (mService != null && isEnabled() && isValidDevice(device)) {
811 return mService.supportsOptionalCodecs(device);
812 }
813 if (mService == null) Log.w(TAG, "Proxy not attached to service");
814 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
815 } catch (RemoteException e) {
816 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
817 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
818 } finally {
819 mServiceLock.readLock().unlock();
820 }
821 }
822
823 /**
824 * Returns whether this device should have optional codecs enabled.
825 *
826 * @param device The device in question.
827 * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700828 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700829 * @hide
830 */
831 public int getOptionalCodecsEnabled(BluetoothDevice device) {
832 try {
833 mServiceLock.readLock().lock();
834 if (mService != null && isEnabled() && isValidDevice(device)) {
835 return mService.getOptionalCodecsEnabled(device);
836 }
837 if (mService == null) Log.w(TAG, "Proxy not attached to service");
838 return OPTIONAL_CODECS_PREF_UNKNOWN;
839 } catch (RemoteException e) {
840 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
841 return OPTIONAL_CODECS_PREF_UNKNOWN;
842 } finally {
843 mServiceLock.readLock().unlock();
844 }
845 }
846
847 /**
848 * Sets a persistent preference for whether a given device should have optional codecs enabled.
849 *
850 * @param device The device to set this preference for.
851 * @param value Whether the optional codecs should be enabled for this device. This should be
Jack Hea355e5e2017-08-22 16:06:54 -0700852 * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
853 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700854 * @hide
855 */
856 public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
857 try {
Jack He2992cd02017-08-22 21:21:23 -0700858 if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
859 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
860 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
Antony Sargentf5772c62017-04-26 16:37:53 -0700861 Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
862 return;
863 }
864 mServiceLock.readLock().lock();
865 if (mService != null && isEnabled()
866 && isValidDevice(device)) {
867 mService.setOptionalCodecsEnabled(device, value);
868 }
869 if (mService == null) Log.w(TAG, "Proxy not attached to service");
870 return;
871 } catch (RemoteException e) {
872 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
873 return;
874 } finally {
875 mServiceLock.readLock().unlock();
876 }
877 }
878
879 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700880 * Helper for converting a state to a string.
881 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700883 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 * @hide
885 */
886 public static String stateToString(int state) {
887 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700888 case STATE_DISCONNECTED:
889 return "disconnected";
890 case STATE_CONNECTING:
891 return "connecting";
892 case STATE_CONNECTED:
893 return "connected";
894 case STATE_DISCONNECTING:
895 return "disconnecting";
896 case STATE_PLAYING:
897 return "playing";
898 case STATE_NOT_PLAYING:
899 return "not playing";
900 default:
901 return "<unknown state " + state + ">";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
903 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800904
Matthew Xie9b693992013-10-10 11:21:40 -0700905 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800906 public void onServiceConnected(ComponentName className, IBinder service) {
907 if (DBG) Log.d(TAG, "Proxy object connected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700908 try {
909 mServiceLock.writeLock().lock();
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600910 mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
Calvin Ond7d16b92016-06-20 15:59:48 -0700911 } finally {
912 mServiceLock.writeLock().unlock();
913 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800914
915 if (mServiceListener != null) {
916 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
917 }
918 }
Jack Hea355e5e2017-08-22 16:06:54 -0700919
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800920 public void onServiceDisconnected(ComponentName className) {
921 if (DBG) Log.d(TAG, "Proxy object disconnected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700922 try {
923 mServiceLock.writeLock().lock();
924 mService = null;
925 } finally {
926 mServiceLock.writeLock().unlock();
927 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800928 if (mServiceListener != null) {
929 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
930 }
931 }
932 };
933
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700934 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700935 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
936 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700937 }
938
939 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700940 if (device == null) return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700941
Jack Hea355e5e2017-08-22 16:06:54 -0700942 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
943 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700944 }
945
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800946 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700947 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800948 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949}