blob: 35a21a4eaf9fb2127f923a3b30055d9f7651dcbb [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 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700303 * Initiate connection to a profile of the remote bluetooth device.
304 *
305 * <p> Currently, the system supports only 1 connection to the
306 * A2DP profile. The API will automatically disconnect connected
307 * devices before connecting.
308 *
309 * <p> This API returns false in scenarios like the profile on the
310 * device is already connected or Bluetooth is not turned on.
311 * When this API returns true, it is guaranteed that
312 * connection state intent for the profile will be broadcasted with
313 * the state. Users can get the connection state of the profile
314 * from this intent.
315 *
316 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
317 * permission.
318 *
319 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700320 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700321 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700323 public boolean connect(BluetoothDevice device) {
324 if (DBG) log("connect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700325 try {
326 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700327 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700328 return mService.connect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700329 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700330 if (mService == null) Log.w(TAG, "Proxy not attached to service");
331 return false;
332 } catch (RemoteException e) {
333 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
334 return false;
335 } finally {
336 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
338 }
339
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700340 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700341 * Initiate disconnection from a profile
342 *
343 * <p> This API will return false in scenarios like the profile on the
344 * Bluetooth device is not in connected state etc. When this API returns,
345 * true, it is guaranteed that the connection state change
346 * intent will be broadcasted with the state. Users can get the
347 * disconnection state of the profile from this intent.
348 *
349 * <p> If the disconnection is initiated by a remote device, the state
350 * will transition from {@link #STATE_CONNECTED} to
351 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
352 * host (local) device the state will transition from
353 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
354 * state {@link #STATE_DISCONNECTED}. The transition to
355 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
356 * two scenarios.
357 *
358 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
359 * permission.
360 *
361 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700362 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700363 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700365 public boolean disconnect(BluetoothDevice device) {
366 if (DBG) log("disconnect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700367 try {
368 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700369 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700370 return mService.disconnect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700371 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700372 if (mService == null) Log.w(TAG, "Proxy not attached to service");
373 return false;
374 } catch (RemoteException e) {
375 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
376 return false;
377 } finally {
378 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
380 }
381
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700382 /**
383 * {@inheritDoc}
384 */
Jack He2992cd02017-08-22 21:21:23 -0700385 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700386 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700387 if (VDBG) log("getConnectedDevices()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700388 try {
389 mServiceLock.readLock().lock();
390 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700391 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700392 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700393 if (mService == null) Log.w(TAG, "Proxy not attached to service");
394 return new ArrayList<BluetoothDevice>();
395 } catch (RemoteException e) {
396 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
397 return new ArrayList<BluetoothDevice>();
398 } finally {
399 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700400 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700401 }
402
403 /**
404 * {@inheritDoc}
405 */
Jack He2992cd02017-08-22 21:21:23 -0700406 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700407 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700408 if (VDBG) log("getDevicesMatchingStates()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700409 try {
410 mServiceLock.readLock().lock();
411 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700412 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700413 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700414 if (mService == null) Log.w(TAG, "Proxy not attached to service");
415 return new ArrayList<BluetoothDevice>();
416 } catch (RemoteException e) {
417 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
418 return new ArrayList<BluetoothDevice>();
419 } finally {
420 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700421 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700422 }
423
424 /**
425 * {@inheritDoc}
426 */
Jack He2992cd02017-08-22 21:21:23 -0700427 @Override
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700428 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700429 if (VDBG) log("getState(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700430 try {
431 mServiceLock.readLock().lock();
432 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700433 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700434 return mService.getConnectionState(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700435 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700436 if (mService == null) Log.w(TAG, "Proxy not attached to service");
437 return BluetoothProfile.STATE_DISCONNECTED;
438 } catch (RemoteException e) {
439 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
440 return BluetoothProfile.STATE_DISCONNECTED;
441 } finally {
442 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700443 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700444 }
445
446 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800447 * Select a connected device as active.
448 *
449 * The active device selection is per profile. An active device's
450 * purpose is profile-specific. For example, A2DP audio streaming
451 * is to the active A2DP Sink device. If a remote device is not
452 * connected, it cannot be selected as active.
453 *
454 * <p> This API returns false in scenarios like the profile on the
455 * device is not connected or Bluetooth is not turned on.
456 * When this API returns true, it is guaranteed that the
457 * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
458 * with the active device.
459 *
460 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
461 * permission.
462 *
463 * @param device the remote Bluetooth device. Could be null to clear
464 * the active device and stop streaming audio to a Bluetooth device.
465 * @return false on immediate error, true otherwise
466 * @hide
467 */
468 public boolean setActiveDevice(@Nullable BluetoothDevice device) {
469 if (DBG) log("setActiveDevice(" + device + ")");
470 try {
471 mServiceLock.readLock().lock();
472 if (mService != null && isEnabled()
473 && ((device == null) || isValidDevice(device))) {
474 return mService.setActiveDevice(device);
475 }
476 if (mService == null) Log.w(TAG, "Proxy not attached to service");
477 return false;
478 } catch (RemoteException e) {
479 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
480 return false;
481 } finally {
482 mServiceLock.readLock().unlock();
483 }
484 }
485
486 /**
487 * Get the connected device that is active.
488 *
489 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
490 * permission.
491 *
492 * @return the connected device that is active or null if no device
493 * is active
494 * @hide
495 */
496 @RequiresPermission(Manifest.permission.BLUETOOTH)
497 @Nullable
498 public BluetoothDevice getActiveDevice() {
499 if (VDBG) log("getActiveDevice()");
500 try {
501 mServiceLock.readLock().lock();
502 if (mService != null && isEnabled()) {
503 return mService.getActiveDevice();
504 }
505 if (mService == null) Log.w(TAG, "Proxy not attached to service");
506 return null;
507 } catch (RemoteException e) {
508 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
509 return null;
510 } finally {
511 mServiceLock.readLock().unlock();
512 }
513 }
514
515 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700516 * Set priority of the profile
517 *
518 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700519 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700520 * {@link #PRIORITY_OFF},
521 *
522 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
523 * permission.
524 *
525 * @param device Paired bluetooth device
526 * @param priority
527 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700528 * @hide
529 */
530 public boolean setPriority(BluetoothDevice device, int priority) {
531 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700532 try {
533 mServiceLock.readLock().lock();
534 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700535 && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700536 if (priority != BluetoothProfile.PRIORITY_OFF
537 && priority != BluetoothProfile.PRIORITY_ON) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700538 return false;
539 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700540 return mService.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700541 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700542 if (mService == null) Log.w(TAG, "Proxy not attached to service");
543 return false;
544 } catch (RemoteException e) {
545 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
546 return false;
547 } finally {
548 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700549 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700550 }
551
552 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700553 * Get the priority of the profile.
554 *
555 * <p> The priority can be any of:
556 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
557 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
558 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700559 * @param device Bluetooth device
560 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700561 * @hide
562 */
Tor Norbye2d497522015-04-23 17:10:21 -0700563 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700564 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700565 if (VDBG) log("getPriority(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700566 try {
567 mServiceLock.readLock().lock();
568 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700569 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700570 return mService.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700571 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700572 if (mService == null) Log.w(TAG, "Proxy not attached to service");
573 return BluetoothProfile.PRIORITY_OFF;
574 } catch (RemoteException e) {
575 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
576 return BluetoothProfile.PRIORITY_OFF;
577 } finally {
578 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700579 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700580 }
581
582 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700583 * Checks if Avrcp device supports the absolute volume feature.
584 *
585 * @return true if device supports absolute volume
586 * @hide
587 */
588 public boolean isAvrcpAbsoluteVolumeSupported() {
589 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
Calvin Ond7d16b92016-06-20 15:59:48 -0700590 try {
591 mServiceLock.readLock().lock();
592 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700593 return mService.isAvrcpAbsoluteVolumeSupported();
John Du5a0cf7a2013-07-19 11:30:34 -0700594 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700595 if (mService == null) Log.w(TAG, "Proxy not attached to service");
596 return false;
597 } catch (RemoteException e) {
598 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
599 return false;
600 } finally {
601 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700602 }
John Du5a0cf7a2013-07-19 11:30:34 -0700603 }
604
605 /**
RoboErik4197cb62015-01-21 15:45:32 -0800606 * Tells remote device to adjust volume. Only if absolute volume is
607 * supported. Uses the following values:
608 * <ul>
609 * <li>{@link AudioManager#ADJUST_LOWER}</li>
610 * <li>{@link AudioManager#ADJUST_RAISE}</li>
611 * <li>{@link AudioManager#ADJUST_MUTE}</li>
612 * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
613 * </ul>
John Du5a0cf7a2013-07-19 11:30:34 -0700614 *
RoboErik4197cb62015-01-21 15:45:32 -0800615 * @param direction One of the supported adjust values.
John Du5a0cf7a2013-07-19 11:30:34 -0700616 * @hide
617 */
618 public void adjustAvrcpAbsoluteVolume(int direction) {
619 if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700620 try {
621 mServiceLock.readLock().lock();
622 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700623 mService.adjustAvrcpAbsoluteVolume(direction);
John Du5a0cf7a2013-07-19 11:30:34 -0700624 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700625 if (mService == null) Log.w(TAG, "Proxy not attached to service");
626 } catch (RemoteException e) {
627 Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
628 } finally {
629 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700630 }
John Du5a0cf7a2013-07-19 11:30:34 -0700631 }
632
633 /**
634 * Tells remote device to set an absolute volume. Only if absolute volume is supported
635 *
636 * @param volume Absolute volume to be set on AVRCP side
637 * @hide
638 */
639 public void setAvrcpAbsoluteVolume(int volume) {
640 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700641 try {
642 mServiceLock.readLock().lock();
643 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700644 mService.setAvrcpAbsoluteVolume(volume);
John Du5a0cf7a2013-07-19 11:30:34 -0700645 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700646 if (mService == null) Log.w(TAG, "Proxy not attached to service");
647 } catch (RemoteException e) {
648 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
649 } finally {
650 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700651 }
John Du5a0cf7a2013-07-19 11:30:34 -0700652 }
653
654 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700655 * Check if A2DP profile is streaming music.
656 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800657 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700658 *
659 * @param device BluetoothDevice device
660 */
661 public boolean isA2dpPlaying(BluetoothDevice device) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700662 try {
663 mServiceLock.readLock().lock();
664 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700665 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700666 return mService.isA2dpPlaying(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700667 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700668 if (mService == null) Log.w(TAG, "Proxy not attached to service");
669 return false;
670 } catch (RemoteException e) {
671 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
672 return false;
673 } finally {
674 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700675 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700676 }
677
678 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700679 * This function checks if the remote device is an AVCRP
680 * target and thus whether we should send volume keys
681 * changes or not.
Jack Hea355e5e2017-08-22 16:06:54 -0700682 *
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700683 * @hide
684 */
685 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
686 if (isEnabled() && isValidDevice(device)) {
687 ParcelUuid[] uuids = device.getUuids();
688 if (uuids == null) return false;
689
Jack Hea355e5e2017-08-22 16:06:54 -0700690 for (ParcelUuid uuid : uuids) {
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700691 if (BluetoothUuid.isAvrcpTarget(uuid)) {
692 return true;
693 }
694 }
695 }
696 return false;
697 }
698
Matthew Xiea0c68032011-06-25 21:47:07 -0700699 /**
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800700 * Gets the current codec status (configuration and capability).
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800701 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800702 * @return the current codec status
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800703 * @hide
704 */
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800705 public BluetoothCodecStatus getCodecStatus() {
706 if (DBG) Log.d(TAG, "getCodecStatus");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800707 try {
708 mServiceLock.readLock().lock();
709 if (mService != null && isEnabled()) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800710 return mService.getCodecStatus();
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800711 }
712 if (mService == null) {
713 Log.w(TAG, "Proxy not attached to service");
714 }
715 return null;
716 } catch (RemoteException e) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800717 Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800718 return null;
719 } finally {
720 mServiceLock.readLock().unlock();
721 }
722 }
723
724 /**
725 * Sets the codec configuration preference.
726 *
727 * @param codecConfig the codec configuration preference
728 * @hide
729 */
730 public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
731 if (DBG) Log.d(TAG, "setCodecConfigPreference");
732 try {
733 mServiceLock.readLock().lock();
734 if (mService != null && isEnabled()) {
735 mService.setCodecConfigPreference(codecConfig);
736 }
737 if (mService == null) Log.w(TAG, "Proxy not attached to service");
738 return;
739 } catch (RemoteException e) {
740 Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
741 return;
742 } finally {
743 mServiceLock.readLock().unlock();
744 }
745 }
746
747 /**
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800748 * Enables the optional codecs.
749 *
750 * @hide
751 */
752 public void enableOptionalCodecs() {
753 if (DBG) Log.d(TAG, "enableOptionalCodecs");
754 enableDisableOptionalCodecs(true);
755 }
756
757 /**
758 * Disables the optional codecs.
759 *
760 * @hide
761 */
762 public void disableOptionalCodecs() {
763 if (DBG) Log.d(TAG, "disableOptionalCodecs");
764 enableDisableOptionalCodecs(false);
765 }
766
767 /**
768 * Enables or disables the optional codecs.
769 *
770 * @param enable if true, enable the optional codecs, other disable them
771 */
772 private void enableDisableOptionalCodecs(boolean enable) {
773 try {
774 mServiceLock.readLock().lock();
775 if (mService != null && isEnabled()) {
776 if (enable) {
777 mService.enableOptionalCodecs();
778 } else {
779 mService.disableOptionalCodecs();
780 }
781 }
782 if (mService == null) Log.w(TAG, "Proxy not attached to service");
783 return;
784 } catch (RemoteException e) {
785 Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
786 return;
787 } finally {
788 mServiceLock.readLock().unlock();
789 }
790 }
791
792 /**
Antony Sargentf5772c62017-04-26 16:37:53 -0700793 * Returns whether this device supports optional codecs.
794 *
795 * @param device The device to check
796 * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700797 * OPTIONAL_CODECS_SUPPORTED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700798 * @hide
799 */
800 public int supportsOptionalCodecs(BluetoothDevice device) {
801 try {
802 mServiceLock.readLock().lock();
803 if (mService != null && isEnabled() && isValidDevice(device)) {
804 return mService.supportsOptionalCodecs(device);
805 }
806 if (mService == null) Log.w(TAG, "Proxy not attached to service");
807 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
808 } catch (RemoteException e) {
809 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
810 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
811 } finally {
812 mServiceLock.readLock().unlock();
813 }
814 }
815
816 /**
817 * Returns whether this device should have optional codecs enabled.
818 *
819 * @param device The device in question.
820 * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700821 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700822 * @hide
823 */
824 public int getOptionalCodecsEnabled(BluetoothDevice device) {
825 try {
826 mServiceLock.readLock().lock();
827 if (mService != null && isEnabled() && isValidDevice(device)) {
828 return mService.getOptionalCodecsEnabled(device);
829 }
830 if (mService == null) Log.w(TAG, "Proxy not attached to service");
831 return OPTIONAL_CODECS_PREF_UNKNOWN;
832 } catch (RemoteException e) {
833 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
834 return OPTIONAL_CODECS_PREF_UNKNOWN;
835 } finally {
836 mServiceLock.readLock().unlock();
837 }
838 }
839
840 /**
841 * Sets a persistent preference for whether a given device should have optional codecs enabled.
842 *
843 * @param device The device to set this preference for.
844 * @param value Whether the optional codecs should be enabled for this device. This should be
Jack Hea355e5e2017-08-22 16:06:54 -0700845 * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
846 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700847 * @hide
848 */
849 public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
850 try {
Jack He2992cd02017-08-22 21:21:23 -0700851 if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
852 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
853 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
Antony Sargentf5772c62017-04-26 16:37:53 -0700854 Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
855 return;
856 }
857 mServiceLock.readLock().lock();
858 if (mService != null && isEnabled()
859 && isValidDevice(device)) {
860 mService.setOptionalCodecsEnabled(device, value);
861 }
862 if (mService == null) Log.w(TAG, "Proxy not attached to service");
863 return;
864 } catch (RemoteException e) {
865 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
866 return;
867 } finally {
868 mServiceLock.readLock().unlock();
869 }
870 }
871
872 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700873 * Helper for converting a state to a string.
874 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700876 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 * @hide
878 */
879 public static String stateToString(int state) {
880 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700881 case STATE_DISCONNECTED:
882 return "disconnected";
883 case STATE_CONNECTING:
884 return "connecting";
885 case STATE_CONNECTED:
886 return "connected";
887 case STATE_DISCONNECTING:
888 return "disconnecting";
889 case STATE_PLAYING:
890 return "playing";
891 case STATE_NOT_PLAYING:
892 return "not playing";
893 default:
894 return "<unknown state " + state + ">";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
896 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800897
Matthew Xie9b693992013-10-10 11:21:40 -0700898 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800899 public void onServiceConnected(ComponentName className, IBinder service) {
900 if (DBG) Log.d(TAG, "Proxy object connected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700901 try {
902 mServiceLock.writeLock().lock();
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600903 mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
Calvin Ond7d16b92016-06-20 15:59:48 -0700904 } finally {
905 mServiceLock.writeLock().unlock();
906 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800907
908 if (mServiceListener != null) {
909 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
910 }
911 }
Jack Hea355e5e2017-08-22 16:06:54 -0700912
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800913 public void onServiceDisconnected(ComponentName className) {
914 if (DBG) Log.d(TAG, "Proxy object disconnected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700915 try {
916 mServiceLock.writeLock().lock();
917 mService = null;
918 } finally {
919 mServiceLock.writeLock().unlock();
920 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800921 if (mServiceListener != null) {
922 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
923 }
924 }
925 };
926
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700927 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700928 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
929 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700930 }
931
932 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700933 if (device == null) return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700934
Jack Hea355e5e2017-08-22 16:06:54 -0700935 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
936 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700937 }
938
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800939 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700940 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942}