blob: 419eda3a85e39b68f98313ff8593352766196775 [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;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060028import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070030import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070031import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.util.Log;
33
Calvin Ond7d16b92016-06-20 15:59:48 -070034import com.android.internal.annotations.GuardedBy;
35
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070036import java.util.ArrayList;
37import java.util.List;
Calvin Ond7d16b92016-06-20 15:59:48 -070038import java.util.concurrent.locks.ReentrantReadWriteLock;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070042 * This class provides the public APIs to control the Bluetooth A2DP
43 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 *
Jack Hea355e5e2017-08-22 16:06:54 -070045 * <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070046 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
47 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070049 * <p> Android only supports one connected Bluetooth A2dp device at a time.
50 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070052public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080054 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070055 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070057 /**
58 * Intent used to broadcast the change in connection state of the A2DP
59 * profile.
60 *
61 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080062 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070063 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
64 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
65 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080066 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070067 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080068 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070069 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
70 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
71 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080072 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
73 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 */
75 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070076 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070077 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070079 /**
80 * Intent used to broadcast the change in the Playing state of the A2DP
81 * profile.
82 *
83 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080084 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070085 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
86 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
87 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080088 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070089 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080090 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070091 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
92 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080093 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
94 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070095 */
96 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
97 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070098 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530100 /** @hide */
101 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102 public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700103 "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530104
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700105 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800106 * Intent used to broadcast the selection of a connected device as active.
107 *
108 * <p>This intent will have one extra:
109 * <ul>
110 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
111 * be null if no device is active. </li>
112 * </ul>
113 *
114 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
115 * receive.
116 *
117 * @hide
118 */
119 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
120 public static final String ACTION_ACTIVE_DEVICE_CHANGED =
121 "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
122
123 /**
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800124 * Intent used to broadcast the change in the Audio Codec state of the
125 * A2DP Source profile.
126 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800127 * <p>This intent will have 2 extras:
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800128 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700129 * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
130 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
131 * connected, otherwise it is not included.</li>
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800132 * </ul>
133 *
134 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
135 * receive.
136 *
137 * @hide
138 */
139 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
140 public static final String ACTION_CODEC_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700141 "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800142
143 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700144 * A2DP sink device is streaming music. This state can be one of
145 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
146 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
147 */
Jack Hea355e5e2017-08-22 16:06:54 -0700148 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -0700149
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700150 /**
151 * A2DP sink device is NOT streaming music. This state can be one of
152 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
153 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
154 */
Jack Hea355e5e2017-08-22 16:06:54 -0700155 public static final int STATE_NOT_PLAYING = 11;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700156
Antony Sargentf5772c62017-04-26 16:37:53 -0700157 /**
158 * We don't have a stored preference for whether or not the given A2DP sink device supports
159 * optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700160 *
161 * @hide
162 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700163 public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
164
165 /**
166 * The given A2DP sink device does not support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700167 *
168 * @hide
169 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700170 public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
171
172 /**
173 * The given A2DP sink device does support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700174 *
175 * @hide
176 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700177 public static final int OPTIONAL_CODECS_SUPPORTED = 1;
178
179 /**
180 * We don't have a stored preference for whether optional codecs should be enabled or disabled
181 * for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700182 *
183 * @hide
184 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700185 public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
186
187 /**
188 * Optional codecs should be disabled for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700189 *
190 * @hide
191 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700192 public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
193
194 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700195 * Optional codecs should be enabled for the given A2DP device.
196 *
197 * @hide
198 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700199 public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
200
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800201 private Context mContext;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700202 private ServiceListener mServiceListener;
Calvin Ond7d16b92016-06-20 15:59:48 -0700203 private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
Jack Hea355e5e2017-08-22 16:06:54 -0700204 @GuardedBy("mServiceLock")
205 private IBluetoothA2dp mService;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700206 private BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207
Jack He2992cd02017-08-22 21:21:23 -0700208 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
fredc0f420372012-04-12 00:02:00 -0700209 new IBluetoothStateChangeCallback.Stub() {
210 public void onBluetoothStateChange(boolean up) {
211 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
212 if (!up) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700213 if (VDBG) Log.d(TAG, "Unbinding service...");
214 try {
215 mServiceLock.writeLock().lock();
216 mService = null;
217 mContext.unbindService(mConnection);
218 } catch (Exception re) {
219 Log.e(TAG, "", re);
220 } finally {
221 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700222 }
223 } else {
Calvin Ond7d16b92016-06-20 15:59:48 -0700224 try {
225 mServiceLock.readLock().lock();
226 if (mService == null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700227 if (VDBG) Log.d(TAG, "Binding service...");
Calvin Ond7d16b92016-06-20 15:59:48 -0700228 doBind();
fredc0f420372012-04-12 00:02:00 -0700229 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700230 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700231 Log.e(TAG, "", re);
Calvin Ond7d16b92016-06-20 15:59:48 -0700232 } finally {
233 mServiceLock.readLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700234 }
235 }
236 }
Jack Hea355e5e2017-08-22 16:06:54 -0700237 };
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 /**
240 * Create a BluetoothA2dp proxy object for interacting with the local
241 * Bluetooth A2DP service.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 */
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800243 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
244 mContext = context;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700245 mServiceListener = l;
246 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700247 IBluetoothManager mgr = mAdapter.getBluetoothManager();
248 if (mgr != null) {
249 try {
250 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
251 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700252 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700253 }
254 }
255
Dianne Hackborn221ea892013-08-04 16:50:16 -0700256 doBind();
257 }
258
259 boolean doBind() {
260 Intent intent = new Intent(IBluetoothA2dp.class.getName());
261 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
262 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700263 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
264 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700265 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
266 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700268 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
270
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800271 /*package*/ void close() {
272 mServiceListener = null;
fredc0f420372012-04-12 00:02:00 -0700273 IBluetoothManager mgr = mAdapter.getBluetoothManager();
274 if (mgr != null) {
275 try {
276 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
277 } catch (Exception e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700278 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700279 }
280 }
281
Calvin Ond7d16b92016-06-20 15:59:48 -0700282 try {
283 mServiceLock.writeLock().lock();
fredc0f420372012-04-12 00:02:00 -0700284 if (mService != null) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700285 mService = null;
286 mContext.unbindService(mConnection);
fredc0f420372012-04-12 00:02:00 -0700287 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700288 } catch (Exception re) {
289 Log.e(TAG, "", re);
290 } finally {
291 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700292 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800293 }
294
Jack He2992cd02017-08-22 21:21:23 -0700295 @Override
fredc0f420372012-04-12 00:02:00 -0700296 public void finalize() {
Mathias Jeppsson2d2d8c22013-08-06 11:41:55 +0200297 // The empty finalize needs to be kept or the
298 // cts signature tests would fail.
fredc0f420372012-04-12 00:02:00 -0700299 }
Jack Hea355e5e2017-08-22 16:06:54 -0700300
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700301 /**
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800302 * Initiate connection to a profile of the remote Bluetooth device.
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700303 *
304 * <p> This API returns false in scenarios like the profile on the
305 * device is already connected or Bluetooth is not turned on.
306 * When this API returns true, it is guaranteed that
307 * connection state intent for the profile will be broadcasted with
308 * the state. Users can get the connection state of the profile
309 * from this intent.
310 *
311 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
312 * permission.
313 *
314 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700315 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700316 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700318 public boolean connect(BluetoothDevice device) {
319 if (DBG) log("connect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700320 try {
321 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700322 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700323 return mService.connect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700324 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700325 if (mService == null) Log.w(TAG, "Proxy not attached to service");
326 return false;
327 } catch (RemoteException e) {
328 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
329 return false;
330 } finally {
331 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 }
333 }
334
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700335 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700336 * Initiate disconnection from a profile
337 *
338 * <p> This API will return false in scenarios like the profile on the
339 * Bluetooth device is not in connected state etc. When this API returns,
340 * true, it is guaranteed that the connection state change
341 * intent will be broadcasted with the state. Users can get the
342 * disconnection state of the profile from this intent.
343 *
344 * <p> If the disconnection is initiated by a remote device, the state
345 * will transition from {@link #STATE_CONNECTED} to
346 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
347 * host (local) device the state will transition from
348 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
349 * state {@link #STATE_DISCONNECTED}. The transition to
350 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
351 * two scenarios.
352 *
353 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
354 * permission.
355 *
356 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700357 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700358 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700360 public boolean disconnect(BluetoothDevice device) {
361 if (DBG) log("disconnect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700362 try {
363 mServiceLock.readLock().lock();
Jack He2992cd02017-08-22 21:21:23 -0700364 if (mService != null && isEnabled() && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700365 return mService.disconnect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700366 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700367 if (mService == null) Log.w(TAG, "Proxy not attached to service");
368 return false;
369 } catch (RemoteException e) {
370 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
371 return false;
372 } finally {
373 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 }
375 }
376
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700377 /**
378 * {@inheritDoc}
379 */
Jack He2992cd02017-08-22 21:21:23 -0700380 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700381 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700382 if (VDBG) log("getConnectedDevices()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700383 try {
384 mServiceLock.readLock().lock();
385 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700386 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700387 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700388 if (mService == null) Log.w(TAG, "Proxy not attached to service");
389 return new ArrayList<BluetoothDevice>();
390 } catch (RemoteException e) {
391 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
392 return new ArrayList<BluetoothDevice>();
393 } finally {
394 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700395 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700396 }
397
398 /**
399 * {@inheritDoc}
400 */
Jack He2992cd02017-08-22 21:21:23 -0700401 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700402 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700403 if (VDBG) log("getDevicesMatchingStates()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700404 try {
405 mServiceLock.readLock().lock();
406 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700407 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700408 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700409 if (mService == null) Log.w(TAG, "Proxy not attached to service");
410 return new ArrayList<BluetoothDevice>();
411 } catch (RemoteException e) {
412 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
413 return new ArrayList<BluetoothDevice>();
414 } finally {
415 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700416 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700417 }
418
419 /**
420 * {@inheritDoc}
421 */
Jack He2992cd02017-08-22 21:21:23 -0700422 @Override
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700423 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700424 if (VDBG) log("getState(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700425 try {
426 mServiceLock.readLock().lock();
427 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700428 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700429 return mService.getConnectionState(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700430 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700431 if (mService == null) Log.w(TAG, "Proxy not attached to service");
432 return BluetoothProfile.STATE_DISCONNECTED;
433 } catch (RemoteException e) {
434 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
435 return BluetoothProfile.STATE_DISCONNECTED;
436 } finally {
437 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700438 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700439 }
440
441 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800442 * Select a connected device as active.
443 *
444 * The active device selection is per profile. An active device's
445 * purpose is profile-specific. For example, A2DP audio streaming
446 * is to the active A2DP Sink device. If a remote device is not
447 * connected, it cannot be selected as active.
448 *
449 * <p> This API returns false in scenarios like the profile on the
450 * device is not connected or Bluetooth is not turned on.
451 * When this API returns true, it is guaranteed that the
452 * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
453 * with the active device.
454 *
455 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
456 * permission.
457 *
458 * @param device the remote Bluetooth device. Could be null to clear
459 * the active device and stop streaming audio to a Bluetooth device.
460 * @return false on immediate error, true otherwise
461 * @hide
462 */
463 public boolean setActiveDevice(@Nullable BluetoothDevice device) {
464 if (DBG) log("setActiveDevice(" + device + ")");
465 try {
466 mServiceLock.readLock().lock();
467 if (mService != null && isEnabled()
468 && ((device == null) || isValidDevice(device))) {
469 return mService.setActiveDevice(device);
470 }
471 if (mService == null) Log.w(TAG, "Proxy not attached to service");
472 return false;
473 } catch (RemoteException e) {
474 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
475 return false;
476 } finally {
477 mServiceLock.readLock().unlock();
478 }
479 }
480
481 /**
482 * Get the connected device that is active.
483 *
484 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
485 * permission.
486 *
487 * @return the connected device that is active or null if no device
488 * is active
489 * @hide
490 */
491 @RequiresPermission(Manifest.permission.BLUETOOTH)
492 @Nullable
493 public BluetoothDevice getActiveDevice() {
494 if (VDBG) log("getActiveDevice()");
495 try {
496 mServiceLock.readLock().lock();
497 if (mService != null && isEnabled()) {
498 return mService.getActiveDevice();
499 }
500 if (mService == null) Log.w(TAG, "Proxy not attached to service");
501 return null;
502 } catch (RemoteException e) {
503 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
504 return null;
505 } finally {
506 mServiceLock.readLock().unlock();
507 }
508 }
509
510 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700511 * Set priority of the profile
512 *
513 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700514 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700515 * {@link #PRIORITY_OFF},
516 *
517 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
518 * permission.
519 *
520 * @param device Paired bluetooth device
521 * @param priority
522 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700523 * @hide
524 */
525 public boolean setPriority(BluetoothDevice device, int priority) {
526 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700527 try {
528 mServiceLock.readLock().lock();
529 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700530 && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700531 if (priority != BluetoothProfile.PRIORITY_OFF
532 && priority != BluetoothProfile.PRIORITY_ON) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700533 return false;
534 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700535 return mService.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700536 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700537 if (mService == null) Log.w(TAG, "Proxy not attached to service");
538 return false;
539 } catch (RemoteException e) {
540 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
541 return false;
542 } finally {
543 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700544 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700545 }
546
547 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700548 * Get the priority of the profile.
549 *
550 * <p> The priority can be any of:
551 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
552 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
553 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700554 * @param device Bluetooth device
555 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700556 * @hide
557 */
Tor Norbye2d497522015-04-23 17:10:21 -0700558 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700559 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700560 if (VDBG) log("getPriority(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700561 try {
562 mServiceLock.readLock().lock();
563 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700564 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700565 return mService.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700566 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700567 if (mService == null) Log.w(TAG, "Proxy not attached to service");
568 return BluetoothProfile.PRIORITY_OFF;
569 } catch (RemoteException e) {
570 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
571 return BluetoothProfile.PRIORITY_OFF;
572 } finally {
573 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700574 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700575 }
576
577 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700578 * Checks if Avrcp device supports the absolute volume feature.
579 *
580 * @return true if device supports absolute volume
581 * @hide
582 */
583 public boolean isAvrcpAbsoluteVolumeSupported() {
584 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
Calvin Ond7d16b92016-06-20 15:59:48 -0700585 try {
586 mServiceLock.readLock().lock();
587 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700588 return mService.isAvrcpAbsoluteVolumeSupported();
John Du5a0cf7a2013-07-19 11:30:34 -0700589 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700590 if (mService == null) Log.w(TAG, "Proxy not attached to service");
591 return false;
592 } catch (RemoteException e) {
593 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
594 return false;
595 } finally {
596 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700597 }
John Du5a0cf7a2013-07-19 11:30:34 -0700598 }
599
600 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700601 * Tells remote device to set an absolute volume. Only if absolute volume is supported
602 *
603 * @param volume Absolute volume to be set on AVRCP side
604 * @hide
605 */
606 public void setAvrcpAbsoluteVolume(int volume) {
607 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700608 try {
609 mServiceLock.readLock().lock();
610 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700611 mService.setAvrcpAbsoluteVolume(volume);
John Du5a0cf7a2013-07-19 11:30:34 -0700612 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700613 if (mService == null) Log.w(TAG, "Proxy not attached to service");
614 } catch (RemoteException e) {
615 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
616 } finally {
617 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700618 }
John Du5a0cf7a2013-07-19 11:30:34 -0700619 }
620
621 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700622 * Check if A2DP profile is streaming music.
623 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800624 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700625 *
626 * @param device BluetoothDevice device
627 */
628 public boolean isA2dpPlaying(BluetoothDevice device) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700629 try {
630 mServiceLock.readLock().lock();
631 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700632 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700633 return mService.isA2dpPlaying(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700634 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700635 if (mService == null) Log.w(TAG, "Proxy not attached to service");
636 return false;
637 } catch (RemoteException e) {
638 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
639 return false;
640 } finally {
641 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700642 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700643 }
644
645 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700646 * This function checks if the remote device is an AVCRP
647 * target and thus whether we should send volume keys
648 * changes or not.
Jack Hea355e5e2017-08-22 16:06:54 -0700649 *
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700650 * @hide
651 */
652 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
653 if (isEnabled() && isValidDevice(device)) {
654 ParcelUuid[] uuids = device.getUuids();
655 if (uuids == null) return false;
656
Jack Hea355e5e2017-08-22 16:06:54 -0700657 for (ParcelUuid uuid : uuids) {
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700658 if (BluetoothUuid.isAvrcpTarget(uuid)) {
659 return true;
660 }
661 }
662 }
663 return false;
664 }
665
Matthew Xiea0c68032011-06-25 21:47:07 -0700666 /**
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800667 * Gets the current codec status (configuration and capability).
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800668 *
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800669 * @param device the remote Bluetooth device. If null, use the current
670 * active A2DP Bluetooth device.
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800671 * @return the current codec status
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800672 * @hide
673 */
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800674 public BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
675 if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800676 try {
677 mServiceLock.readLock().lock();
678 if (mService != null && isEnabled()) {
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800679 return mService.getCodecStatus(device);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800680 }
681 if (mService == null) {
682 Log.w(TAG, "Proxy not attached to service");
683 }
684 return null;
685 } catch (RemoteException e) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800686 Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800687 return null;
688 } finally {
689 mServiceLock.readLock().unlock();
690 }
691 }
692
693 /**
694 * Sets the codec configuration preference.
695 *
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800696 * @param device the remote Bluetooth device. If null, use the current
697 * active A2DP Bluetooth device.
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800698 * @param codecConfig the codec configuration preference
699 * @hide
700 */
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800701 public void setCodecConfigPreference(BluetoothDevice device,
702 BluetoothCodecConfig codecConfig) {
703 if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800704 try {
705 mServiceLock.readLock().lock();
706 if (mService != null && isEnabled()) {
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800707 mService.setCodecConfigPreference(device, codecConfig);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800708 }
709 if (mService == null) Log.w(TAG, "Proxy not attached to service");
710 return;
711 } catch (RemoteException e) {
712 Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
713 return;
714 } finally {
715 mServiceLock.readLock().unlock();
716 }
717 }
718
719 /**
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800720 * Enables the optional codecs.
721 *
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800722 * @param device the remote Bluetooth device. If null, use the currect
723 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800724 * @hide
725 */
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800726 public void enableOptionalCodecs(BluetoothDevice device) {
727 if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
728 enableDisableOptionalCodecs(device, true);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800729 }
730
731 /**
732 * Disables the optional codecs.
733 *
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800734 * @param device the remote Bluetooth device. If null, use the currect
735 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800736 * @hide
737 */
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800738 public void disableOptionalCodecs(BluetoothDevice device) {
739 if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
740 enableDisableOptionalCodecs(device, false);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800741 }
742
743 /**
744 * Enables or disables the optional codecs.
745 *
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800746 * @param device the remote Bluetooth device. If null, use the currect
747 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800748 * @param enable if true, enable the optional codecs, other disable them
749 */
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800750 private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800751 try {
752 mServiceLock.readLock().lock();
753 if (mService != null && isEnabled()) {
754 if (enable) {
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800755 mService.enableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800756 } else {
Pavlin Radoslavov080a0e72018-01-03 19:38:39 -0800757 mService.disableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800758 }
759 }
760 if (mService == null) Log.w(TAG, "Proxy not attached to service");
761 return;
762 } catch (RemoteException e) {
763 Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
764 return;
765 } finally {
766 mServiceLock.readLock().unlock();
767 }
768 }
769
770 /**
Antony Sargentf5772c62017-04-26 16:37:53 -0700771 * Returns whether this device supports optional codecs.
772 *
773 * @param device The device to check
774 * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700775 * OPTIONAL_CODECS_SUPPORTED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700776 * @hide
777 */
778 public int supportsOptionalCodecs(BluetoothDevice device) {
779 try {
780 mServiceLock.readLock().lock();
781 if (mService != null && isEnabled() && isValidDevice(device)) {
782 return mService.supportsOptionalCodecs(device);
783 }
784 if (mService == null) Log.w(TAG, "Proxy not attached to service");
785 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
786 } catch (RemoteException e) {
787 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
788 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
789 } finally {
790 mServiceLock.readLock().unlock();
791 }
792 }
793
794 /**
795 * Returns whether this device should have optional codecs enabled.
796 *
797 * @param device The device in question.
798 * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700799 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700800 * @hide
801 */
802 public int getOptionalCodecsEnabled(BluetoothDevice device) {
803 try {
804 mServiceLock.readLock().lock();
805 if (mService != null && isEnabled() && isValidDevice(device)) {
806 return mService.getOptionalCodecsEnabled(device);
807 }
808 if (mService == null) Log.w(TAG, "Proxy not attached to service");
809 return OPTIONAL_CODECS_PREF_UNKNOWN;
810 } catch (RemoteException e) {
811 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
812 return OPTIONAL_CODECS_PREF_UNKNOWN;
813 } finally {
814 mServiceLock.readLock().unlock();
815 }
816 }
817
818 /**
819 * Sets a persistent preference for whether a given device should have optional codecs enabled.
820 *
821 * @param device The device to set this preference for.
822 * @param value Whether the optional codecs should be enabled for this device. This should be
Jack Hea355e5e2017-08-22 16:06:54 -0700823 * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
824 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700825 * @hide
826 */
827 public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
828 try {
Jack He2992cd02017-08-22 21:21:23 -0700829 if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
830 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
831 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
Antony Sargentf5772c62017-04-26 16:37:53 -0700832 Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
833 return;
834 }
835 mServiceLock.readLock().lock();
836 if (mService != null && isEnabled()
837 && isValidDevice(device)) {
838 mService.setOptionalCodecsEnabled(device, value);
839 }
840 if (mService == null) Log.w(TAG, "Proxy not attached to service");
841 return;
842 } catch (RemoteException e) {
843 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
844 return;
845 } finally {
846 mServiceLock.readLock().unlock();
847 }
848 }
849
850 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700851 * Helper for converting a state to a string.
852 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700854 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 * @hide
856 */
857 public static String stateToString(int state) {
858 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700859 case STATE_DISCONNECTED:
860 return "disconnected";
861 case STATE_CONNECTING:
862 return "connecting";
863 case STATE_CONNECTED:
864 return "connected";
865 case STATE_DISCONNECTING:
866 return "disconnecting";
867 case STATE_PLAYING:
868 return "playing";
869 case STATE_NOT_PLAYING:
870 return "not playing";
871 default:
872 return "<unknown state " + state + ">";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800875
Matthew Xie9b693992013-10-10 11:21:40 -0700876 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800877 public void onServiceConnected(ComponentName className, IBinder service) {
878 if (DBG) Log.d(TAG, "Proxy object connected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700879 try {
880 mServiceLock.writeLock().lock();
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600881 mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
Calvin Ond7d16b92016-06-20 15:59:48 -0700882 } finally {
883 mServiceLock.writeLock().unlock();
884 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800885
886 if (mServiceListener != null) {
887 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
888 }
889 }
Jack Hea355e5e2017-08-22 16:06:54 -0700890
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800891 public void onServiceDisconnected(ComponentName className) {
892 if (DBG) Log.d(TAG, "Proxy object disconnected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700893 try {
894 mServiceLock.writeLock().lock();
895 mService = null;
896 } finally {
897 mServiceLock.writeLock().unlock();
898 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800899 if (mServiceListener != null) {
900 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
901 }
902 }
903 };
904
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700905 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700906 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
907 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700908 }
909
910 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700911 if (device == null) return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700912
Jack Hea355e5e2017-08-22 16:06:54 -0700913 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
914 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700915 }
916
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800917 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700918 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920}