blob: 7b709acd911c8b09acfd8757419844f040ee33f2 [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
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080021import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.Context;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080023import android.content.Intent;
24import android.content.ServiceConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070026import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070027import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.Log;
29
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070030import java.util.ArrayList;
31import java.util.List;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
34/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070035 * This class provides the public APIs to control the Bluetooth A2DP
36 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070038 *<p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
39 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
40 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070042 * <p> Android only supports one connected Bluetooth A2dp device at a time.
43 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070045public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080047 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070048 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070050 /**
51 * Intent used to broadcast the change in connection state of the A2DP
52 * profile.
53 *
54 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080055 * <ul>
56 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
57 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
58 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
59 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070060 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080061 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070062 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
63 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
64 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080065 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
66 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 */
68 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070069 public static final String ACTION_CONNECTION_STATE_CHANGED =
70 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070072 /**
73 * Intent used to broadcast the change in the Playing state of the A2DP
74 * profile.
75 *
76 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080077 * <ul>
78 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
79 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080080 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080081 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070082 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080083 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070084 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
85 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080086 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
87 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070088 */
89 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
90 public static final String ACTION_PLAYING_STATE_CHANGED =
91 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070093 /**
94 * A2DP sink device is streaming music. This state can be one of
95 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
96 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
97 */
98 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -070099
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700100 /**
101 * A2DP sink device is NOT streaming music. This state can be one of
102 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
103 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
104 */
105 public static final int STATE_NOT_PLAYING = 11;
106
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800107 private Context mContext;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700108 private ServiceListener mServiceListener;
109 private IBluetoothA2dp mService;
110 private BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
fredc0f420372012-04-12 00:02:00 -0700112 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
113 new IBluetoothStateChangeCallback.Stub() {
114 public void onBluetoothStateChange(boolean up) {
115 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
116 if (!up) {
Matthew Xie563e4142012-10-09 22:10:37 -0700117 if (VDBG) Log.d(TAG,"Unbinding service...");
fredc0f420372012-04-12 00:02:00 -0700118 synchronized (mConnection) {
119 try {
120 mService = null;
121 mContext.unbindService(mConnection);
122 } catch (Exception re) {
123 Log.e(TAG,"",re);
124 }
125 }
126 } else {
127 synchronized (mConnection) {
128 try {
129 if (mService == null) {
Matthew Xie563e4142012-10-09 22:10:37 -0700130 if (VDBG) Log.d(TAG,"Binding service...");
Dianne Hackborn221ea892013-08-04 16:50:16 -0700131 doBind();
fredc0f420372012-04-12 00:02:00 -0700132 }
133 } catch (Exception re) {
134 Log.e(TAG,"",re);
135 }
136 }
137 }
138 }
139 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 /**
141 * Create a BluetoothA2dp proxy object for interacting with the local
142 * Bluetooth A2DP service.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700143 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 */
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800145 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
146 mContext = context;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700147 mServiceListener = l;
148 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700149 IBluetoothManager mgr = mAdapter.getBluetoothManager();
150 if (mgr != null) {
151 try {
152 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
153 } catch (RemoteException e) {
154 Log.e(TAG,"",e);
155 }
156 }
157
Dianne Hackborn221ea892013-08-04 16:50:16 -0700158 doBind();
159 }
160
161 boolean doBind() {
162 Intent intent = new Intent(IBluetoothA2dp.class.getName());
163 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
164 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700165 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
166 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700167 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
168 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700170 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 }
172
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800173 /*package*/ void close() {
174 mServiceListener = null;
fredc0f420372012-04-12 00:02:00 -0700175 IBluetoothManager mgr = mAdapter.getBluetoothManager();
176 if (mgr != null) {
177 try {
178 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
179 } catch (Exception e) {
180 Log.e(TAG,"",e);
181 }
182 }
183
184 synchronized (mConnection) {
185 if (mService != null) {
186 try {
187 mService = null;
188 mContext.unbindService(mConnection);
189 } catch (Exception re) {
190 Log.e(TAG,"",re);
191 }
192 }
193 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800194 }
195
fredc0f420372012-04-12 00:02:00 -0700196 public void finalize() {
197 close();
198 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700199 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700200 * Initiate connection to a profile of the remote bluetooth device.
201 *
202 * <p> Currently, the system supports only 1 connection to the
203 * A2DP profile. The API will automatically disconnect connected
204 * devices before connecting.
205 *
206 * <p> This API returns false in scenarios like the profile on the
207 * device is already connected or Bluetooth is not turned on.
208 * When this API returns true, it is guaranteed that
209 * connection state intent for the profile will be broadcasted with
210 * the state. Users can get the connection state of the profile
211 * from this intent.
212 *
213 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
214 * permission.
215 *
216 * @param device Remote Bluetooth Device
217 * @return false on immediate error,
218 * true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700219 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700221 public boolean connect(BluetoothDevice device) {
222 if (DBG) log("connect(" + device + ")");
223 if (mService != null && isEnabled() &&
224 isValidDevice(device)) {
225 try {
226 return mService.connect(device);
227 } catch (RemoteException e) {
228 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
229 return false;
230 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700232 if (mService == null) Log.w(TAG, "Proxy not attached to service");
233 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 }
235
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700236 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700237 * Initiate disconnection from a profile
238 *
239 * <p> This API will return false in scenarios like the profile on the
240 * Bluetooth device is not in connected state etc. When this API returns,
241 * true, it is guaranteed that the connection state change
242 * intent will be broadcasted with the state. Users can get the
243 * disconnection state of the profile from this intent.
244 *
245 * <p> If the disconnection is initiated by a remote device, the state
246 * will transition from {@link #STATE_CONNECTED} to
247 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
248 * host (local) device the state will transition from
249 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
250 * state {@link #STATE_DISCONNECTED}. The transition to
251 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
252 * two scenarios.
253 *
254 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
255 * permission.
256 *
257 * @param device Remote Bluetooth Device
258 * @return false on immediate error,
259 * true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700260 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700262 public boolean disconnect(BluetoothDevice device) {
263 if (DBG) log("disconnect(" + device + ")");
264 if (mService != null && isEnabled() &&
265 isValidDevice(device)) {
266 try {
267 return mService.disconnect(device);
268 } catch (RemoteException e) {
269 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
270 return false;
271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700273 if (mService == null) Log.w(TAG, "Proxy not attached to service");
274 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 }
276
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700277 /**
278 * {@inheritDoc}
279 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700280 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700281 if (VDBG) log("getConnectedDevices()");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700282 if (mService != null && isEnabled()) {
283 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700284 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700285 } catch (RemoteException e) {
286 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700287 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700288 }
289 }
290 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700291 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700292 }
293
294 /**
295 * {@inheritDoc}
296 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700297 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700298 if (VDBG) log("getDevicesMatchingStates()");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700299 if (mService != null && isEnabled()) {
300 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700301 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700302 } catch (RemoteException e) {
303 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700304 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700305 }
306 }
307 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700308 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700309 }
310
311 /**
312 * {@inheritDoc}
313 */
314 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700315 if (VDBG) log("getState(" + device + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700316 if (mService != null && isEnabled()
317 && isValidDevice(device)) {
318 try {
319 return mService.getConnectionState(device);
320 } catch (RemoteException e) {
321 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
322 return BluetoothProfile.STATE_DISCONNECTED;
323 }
324 }
325 if (mService == null) Log.w(TAG, "Proxy not attached to service");
326 return BluetoothProfile.STATE_DISCONNECTED;
327 }
328
329 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700330 * Set priority of the profile
331 *
332 * <p> The device should already be paired.
fredc0f420372012-04-12 00:02:00 -0700333 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700334 * {@link #PRIORITY_OFF},
335 *
336 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
337 * permission.
338 *
339 * @param device Paired bluetooth device
340 * @param priority
341 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700342 * @hide
343 */
344 public boolean setPriority(BluetoothDevice device, int priority) {
345 if (DBG) log("setPriority(" + device + ", " + priority + ")");
346 if (mService != null && isEnabled()
347 && isValidDevice(device)) {
348 if (priority != BluetoothProfile.PRIORITY_OFF &&
Ganesh Ganapathi Batta6f6c54512012-07-31 16:08:17 -0700349 priority != BluetoothProfile.PRIORITY_ON){
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700350 return false;
351 }
352 try {
353 return mService.setPriority(device, priority);
354 } catch (RemoteException e) {
355 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
356 return false;
357 }
358 }
359 if (mService == null) Log.w(TAG, "Proxy not attached to service");
360 return false;
361 }
362
363 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700364 * Get the priority of the profile.
365 *
366 * <p> The priority can be any of:
367 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
368 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
369 *
370 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
371 *
372 * @param device Bluetooth device
373 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700374 * @hide
375 */
376 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700377 if (VDBG) log("getPriority(" + device + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700378 if (mService != null && isEnabled()
379 && isValidDevice(device)) {
380 try {
381 return mService.getPriority(device);
382 } catch (RemoteException e) {
383 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
384 return BluetoothProfile.PRIORITY_OFF;
385 }
386 }
387 if (mService == null) Log.w(TAG, "Proxy not attached to service");
388 return BluetoothProfile.PRIORITY_OFF;
389 }
390
391 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700392 * Checks if Avrcp device supports the absolute volume feature.
393 *
394 * @return true if device supports absolute volume
395 * @hide
396 */
397 public boolean isAvrcpAbsoluteVolumeSupported() {
398 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
399 if (mService != null && isEnabled()) {
400 try {
401 return mService.isAvrcpAbsoluteVolumeSupported();
402 } catch (RemoteException e) {
403 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
404 return false;
405 }
406 }
407 if (mService == null) Log.w(TAG, "Proxy not attached to service");
408 return false;
409 }
410
411 /**
412 * Tells remote device to adjust volume. Only if absolute volume is supported.
413 *
414 * @param direction 1 to increase volume, or -1 to decrease volume
415 * @hide
416 */
417 public void adjustAvrcpAbsoluteVolume(int direction) {
418 if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
419 if (mService != null && isEnabled()) {
420 try {
421 mService.adjustAvrcpAbsoluteVolume(direction);
422 return;
423 } catch (RemoteException e) {
424 Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
425 return;
426 }
427 }
428 if (mService == null) Log.w(TAG, "Proxy not attached to service");
429 }
430
431 /**
432 * Tells remote device to set an absolute volume. Only if absolute volume is supported
433 *
434 * @param volume Absolute volume to be set on AVRCP side
435 * @hide
436 */
437 public void setAvrcpAbsoluteVolume(int volume) {
438 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
439 if (mService != null && isEnabled()) {
440 try {
441 mService.setAvrcpAbsoluteVolume(volume);
442 return;
443 } catch (RemoteException e) {
444 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
445 return;
446 }
447 }
448 if (mService == null) Log.w(TAG, "Proxy not attached to service");
449 }
450
451 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700452 * Check if A2DP profile is streaming music.
453 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800454 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700455 *
456 * @param device BluetoothDevice device
457 */
458 public boolean isA2dpPlaying(BluetoothDevice device) {
459 if (mService != null && isEnabled()
460 && isValidDevice(device)) {
461 try {
462 return mService.isA2dpPlaying(device);
463 } catch (RemoteException e) {
464 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
465 return false;
466 }
467 }
468 if (mService == null) Log.w(TAG, "Proxy not attached to service");
469 return false;
470 }
471
472 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700473 * This function checks if the remote device is an AVCRP
474 * target and thus whether we should send volume keys
475 * changes or not.
476 * @hide
477 */
478 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
479 if (isEnabled() && isValidDevice(device)) {
480 ParcelUuid[] uuids = device.getUuids();
481 if (uuids == null) return false;
482
483 for (ParcelUuid uuid: uuids) {
484 if (BluetoothUuid.isAvrcpTarget(uuid)) {
485 return true;
486 }
487 }
488 }
489 return false;
490 }
491
Matthew Xiea0c68032011-06-25 21:47:07 -0700492 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700493 * Helper for converting a state to a string.
494 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 * For debug use only - strings are not internationalized.
496 * @hide
497 */
498 public static String stateToString(int state) {
499 switch (state) {
500 case STATE_DISCONNECTED:
501 return "disconnected";
502 case STATE_CONNECTING:
503 return "connecting";
504 case STATE_CONNECTED:
505 return "connected";
506 case STATE_DISCONNECTING:
507 return "disconnecting";
508 case STATE_PLAYING:
509 return "playing";
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700510 case STATE_NOT_PLAYING:
511 return "not playing";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 default:
513 return "<unknown state " + state + ">";
514 }
515 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800516
Matthew Xie9b693992013-10-10 11:21:40 -0700517 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800518 public void onServiceConnected(ComponentName className, IBinder service) {
519 if (DBG) Log.d(TAG, "Proxy object connected");
520 mService = IBluetoothA2dp.Stub.asInterface(service);
521
522 if (mServiceListener != null) {
523 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
524 }
525 }
526 public void onServiceDisconnected(ComponentName className) {
527 if (DBG) Log.d(TAG, "Proxy object disconnected");
528 mService = null;
529 if (mServiceListener != null) {
530 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
531 }
532 }
533 };
534
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700535 private boolean isEnabled() {
536 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
537 return false;
538 }
539
540 private boolean isValidDevice(BluetoothDevice device) {
541 if (device == null) return false;
542
543 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
544 return false;
545 }
546
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800547 private static void log(String msg) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700548 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550}