blob: fda2f89275356717533146196841c7f74db52db3 [file] [log] [blame]
Mike Lockwood2263dd12014-05-14 09:51:30 -07001/*
2 * Copyright (C) 2014 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
Mathew Inwood4dc66d32018-08-01 15:07:20 +010019import android.annotation.UnsupportedAppUsage;
Mike Lockwood2263dd12014-05-14 09:51:30 -070020import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.ServiceConnection;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060024import android.os.Binder;
Mike Lockwood2263dd12014-05-14 09:51:30 -070025import android.os.IBinder;
26import android.os.RemoteException;
27import android.util.Log;
28
29import java.util.ArrayList;
30import java.util.List;
31
32/**
33 * This class provides the public APIs to control the Bluetooth A2DP Sink
34 * profile.
35 *
Jack Hea355e5e2017-08-22 16:06:54 -070036 * <p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
Mike Lockwood2263dd12014-05-14 09:51:30 -070037 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
38 * the BluetoothA2dpSink proxy object.
39 *
40 * @hide
41 */
42public final class BluetoothA2dpSink implements BluetoothProfile {
43 private static final String TAG = "BluetoothA2dpSink";
44 private static final boolean DBG = true;
45 private static final boolean VDBG = false;
46
47 /**
48 * Intent used to broadcast the change in connection state of the A2DP Sink
49 * profile.
50 *
51 * <p>This intent will have 3 extras:
52 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070053 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
54 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
55 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -070056 * </ul>
57 *
58 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
59 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
60 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
61 *
62 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
63 * receive.
64 */
65 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070066 "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -070067
68 /**
69 * Intent used to broadcast the change in the Playing state of the A2DP Sink
70 * profile.
71 *
72 * <p>This intent will have 3 extras:
73 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070074 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
75 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
76 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -070077 * </ul>
78 *
79 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
80 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
81 *
82 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
83 * receive.
84 */
85 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070086 "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -070087
88 /**
89 * A2DP sink device is streaming music. This state can be one of
90 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
91 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
92 */
Jack Hea355e5e2017-08-22 16:06:54 -070093 public static final int STATE_PLAYING = 10;
Mike Lockwood2263dd12014-05-14 09:51:30 -070094
95 /**
96 * A2DP sink device is NOT streaming music. This state can be one of
97 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
98 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
99 */
Jack Hea355e5e2017-08-22 16:06:54 -0700100 public static final int STATE_NOT_PLAYING = 11;
Mike Lockwood2263dd12014-05-14 09:51:30 -0700101
102 /**
103 * Intent used to broadcast the change in the Playing state of the A2DP Sink
104 * profile.
105 *
106 * <p>This intent will have 3 extras:
107 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700108 * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
109 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -0700110 * </ul>
111 *
112 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
113 * receive.
114 */
115 public static final String ACTION_AUDIO_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700116 "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700117
118 /**
119 * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
120 *
121 * This extra represents the current audio configuration of the A2DP source device.
122 * {@see BluetoothAudioConfig}
123 */
Jack He2992cd02017-08-22 21:21:23 -0700124 public static final String EXTRA_AUDIO_CONFIG =
125 "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700126
127 private Context mContext;
128 private ServiceListener mServiceListener;
Jack He16eeac32017-08-17 12:11:18 -0700129 private volatile IBluetoothA2dpSink mService;
Mike Lockwood2263dd12014-05-14 09:51:30 -0700130 private BluetoothAdapter mAdapter;
131
Jack He2992cd02017-08-22 21:21:23 -0700132 private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
Mike Lockwood2263dd12014-05-14 09:51:30 -0700133 new IBluetoothStateChangeCallback.Stub() {
134 public void onBluetoothStateChange(boolean up) {
135 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
136 if (!up) {
Jack Hea355e5e2017-08-22 16:06:54 -0700137 if (VDBG) Log.d(TAG, "Unbinding service...");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700138 synchronized (mConnection) {
139 try {
140 mService = null;
141 mContext.unbindService(mConnection);
142 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700143 Log.e(TAG, "", re);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700144 }
145 }
146 } else {
147 synchronized (mConnection) {
148 try {
149 if (mService == null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700150 if (VDBG) Log.d(TAG, "Binding service...");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700151 doBind();
152 }
153 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700154 Log.e(TAG, "", re);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700155 }
156 }
157 }
158 }
Jack Hea355e5e2017-08-22 16:06:54 -0700159 };
160
Mike Lockwood2263dd12014-05-14 09:51:30 -0700161 /**
162 * Create a BluetoothA2dp proxy object for interacting with the local
163 * Bluetooth A2DP service.
Mike Lockwood2263dd12014-05-14 09:51:30 -0700164 */
165 /*package*/ BluetoothA2dpSink(Context context, ServiceListener l) {
166 mContext = context;
167 mServiceListener = l;
168 mAdapter = BluetoothAdapter.getDefaultAdapter();
169 IBluetoothManager mgr = mAdapter.getBluetoothManager();
170 if (mgr != null) {
171 try {
172 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
173 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700174 Log.e(TAG, "", e);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700175 }
176 }
177
178 doBind();
179 }
180
181 boolean doBind() {
182 Intent intent = new Intent(IBluetoothA2dpSink.class.getName());
183 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
184 intent.setComponent(comp);
185 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
Jeff Sharkeyad357d12018-02-02 13:25:31 -0700186 mContext.getUser())) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700187 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
188 return false;
189 }
190 return true;
191 }
192
193 /*package*/ void close() {
194 mServiceListener = null;
195 IBluetoothManager mgr = mAdapter.getBluetoothManager();
196 if (mgr != null) {
197 try {
198 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
199 } catch (Exception e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700200 Log.e(TAG, "", e);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700201 }
202 }
203
204 synchronized (mConnection) {
205 if (mService != null) {
206 try {
207 mService = null;
208 mContext.unbindService(mConnection);
209 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700210 Log.e(TAG, "", re);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700211 }
212 }
213 }
214 }
215
Jack He2992cd02017-08-22 21:21:23 -0700216 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700217 public void finalize() {
218 close();
219 }
Jack Hea355e5e2017-08-22 16:06:54 -0700220
Mike Lockwood2263dd12014-05-14 09:51:30 -0700221 /**
222 * Initiate connection to a profile of the remote bluetooth device.
223 *
224 * <p> Currently, the system supports only 1 connection to the
225 * A2DP profile. The API will automatically disconnect connected
226 * devices before connecting.
227 *
228 * <p> This API returns false in scenarios like the profile on the
229 * device is already connected or Bluetooth is not turned on.
230 * When this API returns true, it is guaranteed that
231 * connection state intent for the profile will be broadcasted with
232 * the state. Users can get the connection state of the profile
233 * from this intent.
234 *
235 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
236 * permission.
237 *
238 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700239 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700240 * @hide
241 */
242 public boolean connect(BluetoothDevice device) {
243 if (DBG) log("connect(" + device + ")");
Jack He16eeac32017-08-17 12:11:18 -0700244 final IBluetoothA2dpSink service = mService;
245 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700246 try {
Jack He16eeac32017-08-17 12:11:18 -0700247 return service.connect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700248 } catch (RemoteException e) {
249 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
250 return false;
251 }
252 }
Jack He16eeac32017-08-17 12:11:18 -0700253 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700254 return false;
255 }
256
257 /**
258 * Initiate disconnection from a profile
259 *
260 * <p> This API will return false in scenarios like the profile on the
261 * Bluetooth device is not in connected state etc. When this API returns,
262 * true, it is guaranteed that the connection state change
263 * intent will be broadcasted with the state. Users can get the
264 * disconnection state of the profile from this intent.
265 *
266 * <p> If the disconnection is initiated by a remote device, the state
267 * will transition from {@link #STATE_CONNECTED} to
268 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
269 * host (local) device the state will transition from
270 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
271 * state {@link #STATE_DISCONNECTED}. The transition to
272 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
273 * two scenarios.
274 *
275 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
276 * permission.
277 *
278 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700279 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700280 * @hide
281 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100282 @UnsupportedAppUsage
Mike Lockwood2263dd12014-05-14 09:51:30 -0700283 public boolean disconnect(BluetoothDevice device) {
284 if (DBG) log("disconnect(" + device + ")");
Jack He16eeac32017-08-17 12:11:18 -0700285 final IBluetoothA2dpSink service = mService;
286 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700287 try {
Jack He16eeac32017-08-17 12:11:18 -0700288 return service.disconnect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700289 } catch (RemoteException e) {
290 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
291 return false;
292 }
293 }
Jack He16eeac32017-08-17 12:11:18 -0700294 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700295 return false;
296 }
297
298 /**
299 * {@inheritDoc}
300 */
Jack He2992cd02017-08-22 21:21:23 -0700301 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700302 public List<BluetoothDevice> getConnectedDevices() {
303 if (VDBG) log("getConnectedDevices()");
Jack He16eeac32017-08-17 12:11:18 -0700304 final IBluetoothA2dpSink service = mService;
305 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700306 try {
Jack He16eeac32017-08-17 12:11:18 -0700307 return service.getConnectedDevices();
Mike Lockwood2263dd12014-05-14 09:51:30 -0700308 } catch (RemoteException e) {
309 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
310 return new ArrayList<BluetoothDevice>();
311 }
312 }
Jack He16eeac32017-08-17 12:11:18 -0700313 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700314 return new ArrayList<BluetoothDevice>();
315 }
316
317 /**
318 * {@inheritDoc}
319 */
Jack He2992cd02017-08-22 21:21:23 -0700320 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700321 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
322 if (VDBG) log("getDevicesMatchingStates()");
Jack He16eeac32017-08-17 12:11:18 -0700323 final IBluetoothA2dpSink service = mService;
324 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700325 try {
Jack He16eeac32017-08-17 12:11:18 -0700326 return service.getDevicesMatchingConnectionStates(states);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700327 } catch (RemoteException e) {
328 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
329 return new ArrayList<BluetoothDevice>();
330 }
331 }
Jack He16eeac32017-08-17 12:11:18 -0700332 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700333 return new ArrayList<BluetoothDevice>();
334 }
335
336 /**
337 * {@inheritDoc}
338 */
Jack He2992cd02017-08-22 21:21:23 -0700339 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700340 public int getConnectionState(BluetoothDevice device) {
341 if (VDBG) log("getState(" + device + ")");
Jack He16eeac32017-08-17 12:11:18 -0700342 final IBluetoothA2dpSink service = mService;
343 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700344 try {
Jack He16eeac32017-08-17 12:11:18 -0700345 return service.getConnectionState(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700346 } catch (RemoteException e) {
347 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
348 return BluetoothProfile.STATE_DISCONNECTED;
349 }
350 }
Jack He16eeac32017-08-17 12:11:18 -0700351 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700352 return BluetoothProfile.STATE_DISCONNECTED;
353 }
354
355 /**
356 * Get the current audio configuration for the A2DP source device,
357 * or null if the device has no audio configuration
358 *
359 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
360 *
361 * @param device Remote bluetooth device.
362 * @return audio configuration for the device, or null
363 *
364 * {@see BluetoothAudioConfig}
365 */
Jack Hea355e5e2017-08-22 16:06:54 -0700366 public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700367 if (VDBG) log("getAudioConfig(" + device + ")");
Jack He16eeac32017-08-17 12:11:18 -0700368 final IBluetoothA2dpSink service = mService;
369 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700370 try {
Jack He16eeac32017-08-17 12:11:18 -0700371 return service.getAudioConfig(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700372 } catch (RemoteException e) {
373 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
374 return null;
375 }
376 }
Jack He16eeac32017-08-17 12:11:18 -0700377 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700378 return null;
379 }
380
381 /**
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700382 * Set priority of the profile
383 *
384 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700385 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700386 * {@link #PRIORITY_OFF},
387 *
388 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
389 * permission.
390 *
391 * @param device Paired bluetooth device
392 * @param priority
393 * @return true if priority is set, false on error
394 * @hide
395 */
396 public boolean setPriority(BluetoothDevice device, int priority) {
397 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Jack He16eeac32017-08-17 12:11:18 -0700398 final IBluetoothA2dpSink service = mService;
399 if (service != null && isEnabled() && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700400 if (priority != BluetoothProfile.PRIORITY_OFF
401 && priority != BluetoothProfile.PRIORITY_ON) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700402 return false;
403 }
404 try {
Jack He16eeac32017-08-17 12:11:18 -0700405 return service.setPriority(device, priority);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700406 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700407 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
408 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700409 }
410 }
Jack He16eeac32017-08-17 12:11:18 -0700411 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700412 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700413 }
414
415 /**
416 * Get the priority of the profile.
417 *
418 * <p> The priority can be any of:
419 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
420 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
421 *
422 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
423 *
424 * @param device Bluetooth device
425 * @return priority of the device
426 * @hide
427 */
428 public int getPriority(BluetoothDevice device) {
429 if (VDBG) log("getPriority(" + device + ")");
Jack He16eeac32017-08-17 12:11:18 -0700430 final IBluetoothA2dpSink service = mService;
431 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700432 try {
Jack He16eeac32017-08-17 12:11:18 -0700433 return service.getPriority(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700434 } catch (RemoteException e) {
435 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
436 return BluetoothProfile.PRIORITY_OFF;
437 }
438 }
Jack He16eeac32017-08-17 12:11:18 -0700439 if (service == null) Log.w(TAG, "Proxy not attached to service");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700440 return BluetoothProfile.PRIORITY_OFF;
441 }
442
443 /**
444 * Check if A2DP profile is streaming music.
445 *
446 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
447 *
448 * @param device BluetoothDevice device
449 */
450 public boolean isA2dpPlaying(BluetoothDevice device) {
Jack He16eeac32017-08-17 12:11:18 -0700451 final IBluetoothA2dpSink service = mService;
452 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700453 try {
Jack He16eeac32017-08-17 12:11:18 -0700454 return service.isA2dpPlaying(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700455 } catch (RemoteException e) {
456 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
457 return false;
458 }
459 }
Jack He16eeac32017-08-17 12:11:18 -0700460 if (service == null) Log.w(TAG, "Proxy not attached to service");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700461 return false;
462 }
463
464 /**
Mike Lockwood2263dd12014-05-14 09:51:30 -0700465 * Helper for converting a state to a string.
466 *
467 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700468 *
Mike Lockwood2263dd12014-05-14 09:51:30 -0700469 * @hide
470 */
471 public static String stateToString(int state) {
472 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700473 case STATE_DISCONNECTED:
474 return "disconnected";
475 case STATE_CONNECTING:
476 return "connecting";
477 case STATE_CONNECTED:
478 return "connected";
479 case STATE_DISCONNECTING:
480 return "disconnecting";
481 case STATE_PLAYING:
482 return "playing";
483 case STATE_NOT_PLAYING:
484 return "not playing";
485 default:
486 return "<unknown state " + state + ">";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700487 }
488 }
489
490 private final ServiceConnection mConnection = new ServiceConnection() {
491 public void onServiceConnected(ComponentName className, IBinder service) {
492 if (DBG) Log.d(TAG, "Proxy object connected");
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600493 mService = IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
Mike Lockwood2263dd12014-05-14 09:51:30 -0700494 if (mServiceListener != null) {
495 mServiceListener.onServiceConnected(BluetoothProfile.A2DP_SINK,
496 BluetoothA2dpSink.this);
497 }
498 }
Jack Hea355e5e2017-08-22 16:06:54 -0700499
Mike Lockwood2263dd12014-05-14 09:51:30 -0700500 public void onServiceDisconnected(ComponentName className) {
501 if (DBG) Log.d(TAG, "Proxy object disconnected");
502 mService = null;
503 if (mServiceListener != null) {
504 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP_SINK);
505 }
506 }
507 };
508
509 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700510 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Mike Lockwood2263dd12014-05-14 09:51:30 -0700511 }
512
Jack He16eeac32017-08-17 12:11:18 -0700513 private static boolean isValidDevice(BluetoothDevice device) {
514 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Mike Lockwood2263dd12014-05-14 09:51:30 -0700515 }
516
517 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700518 Log.d(TAG, msg);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700519 }
520}