blob: c17834aa8e52bc241b8be7c8519b28d123e4559e [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
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -080019import android.Manifest;
20import android.annotation.RequiresPermission;
21import android.annotation.SystemApi;
Mathew Inwood4dc66d32018-08-01 15:07:20 +010022import android.annotation.UnsupportedAppUsage;
Mike Lockwood2263dd12014-05-14 09:51:30 -070023import android.content.Context;
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
Mike Lockwood2263dd12014-05-14 09:51:30 -0700127 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800128 private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
129 new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
130 "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) {
131 @Override
132 public IBluetoothA2dpSink getServiceInterface(IBinder service) {
133 return IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
Mike Lockwood2263dd12014-05-14 09:51:30 -0700134 }
Ugo Yud0115462019-03-26 21:38:08 +0800135 };
Jack Hea355e5e2017-08-22 16:06:54 -0700136
Mike Lockwood2263dd12014-05-14 09:51:30 -0700137 /**
138 * Create a BluetoothA2dp proxy object for interacting with the local
139 * Bluetooth A2DP service.
Mike Lockwood2263dd12014-05-14 09:51:30 -0700140 */
Ugo Yud0115462019-03-26 21:38:08 +0800141 /*package*/ BluetoothA2dpSink(Context context, ServiceListener listener) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700142 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800143 mProfileConnector.connect(context, listener);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700144 }
145
146 /*package*/ void close() {
Ugo Yud0115462019-03-26 21:38:08 +0800147 mProfileConnector.disconnect();
148 }
Mike Lockwood2263dd12014-05-14 09:51:30 -0700149
Ugo Yud0115462019-03-26 21:38:08 +0800150 private IBluetoothA2dpSink getService() {
151 return mProfileConnector.getService();
Mike Lockwood2263dd12014-05-14 09:51:30 -0700152 }
153
Jack He2992cd02017-08-22 21:21:23 -0700154 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700155 public void finalize() {
156 close();
157 }
Jack Hea355e5e2017-08-22 16:06:54 -0700158
Mike Lockwood2263dd12014-05-14 09:51:30 -0700159 /**
160 * Initiate connection to a profile of the remote bluetooth device.
161 *
162 * <p> Currently, the system supports only 1 connection to the
163 * A2DP profile. The API will automatically disconnect connected
164 * devices before connecting.
165 *
166 * <p> This API returns false in scenarios like the profile on the
167 * device is already connected or Bluetooth is not turned on.
168 * When this API returns true, it is guaranteed that
169 * connection state intent for the profile will be broadcasted with
170 * the state. Users can get the connection state of the profile
171 * from this intent.
172 *
173 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
174 * permission.
175 *
176 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700177 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700178 * @hide
179 */
180 public boolean connect(BluetoothDevice device) {
181 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800182 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700183 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700184 try {
Jack He16eeac32017-08-17 12:11:18 -0700185 return service.connect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700186 } catch (RemoteException e) {
187 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
188 return false;
189 }
190 }
Jack He16eeac32017-08-17 12:11:18 -0700191 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700192 return false;
193 }
194
195 /**
196 * Initiate disconnection from a profile
197 *
198 * <p> This API will return false in scenarios like the profile on the
199 * Bluetooth device is not in connected state etc. When this API returns,
200 * true, it is guaranteed that the connection state change
201 * intent will be broadcasted with the state. Users can get the
202 * disconnection state of the profile from this intent.
203 *
204 * <p> If the disconnection is initiated by a remote device, the state
205 * will transition from {@link #STATE_CONNECTED} to
206 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
207 * host (local) device the state will transition from
208 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
209 * state {@link #STATE_DISCONNECTED}. The transition to
210 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
211 * two scenarios.
212 *
213 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
214 * permission.
215 *
216 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700217 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700218 * @hide
219 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100220 @UnsupportedAppUsage
Mike Lockwood2263dd12014-05-14 09:51:30 -0700221 public boolean disconnect(BluetoothDevice device) {
222 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800223 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700224 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700225 try {
Jack He16eeac32017-08-17 12:11:18 -0700226 return service.disconnect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700227 } catch (RemoteException e) {
228 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
229 return false;
230 }
231 }
Jack He16eeac32017-08-17 12:11:18 -0700232 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700233 return false;
234 }
235
236 /**
237 * {@inheritDoc}
238 */
Jack He2992cd02017-08-22 21:21:23 -0700239 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700240 public List<BluetoothDevice> getConnectedDevices() {
241 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800242 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700243 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700244 try {
Jack He16eeac32017-08-17 12:11:18 -0700245 return service.getConnectedDevices();
Mike Lockwood2263dd12014-05-14 09:51:30 -0700246 } catch (RemoteException e) {
247 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
248 return new ArrayList<BluetoothDevice>();
249 }
250 }
Jack He16eeac32017-08-17 12:11:18 -0700251 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700252 return new ArrayList<BluetoothDevice>();
253 }
254
255 /**
256 * {@inheritDoc}
257 */
Jack He2992cd02017-08-22 21:21:23 -0700258 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700259 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
260 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800261 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700262 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700263 try {
Jack He16eeac32017-08-17 12:11:18 -0700264 return service.getDevicesMatchingConnectionStates(states);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700265 } catch (RemoteException e) {
266 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
267 return new ArrayList<BluetoothDevice>();
268 }
269 }
Jack He16eeac32017-08-17 12:11:18 -0700270 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700271 return new ArrayList<BluetoothDevice>();
272 }
273
274 /**
275 * {@inheritDoc}
276 */
Jack He2992cd02017-08-22 21:21:23 -0700277 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700278 public int getConnectionState(BluetoothDevice device) {
279 if (VDBG) log("getState(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800280 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700281 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700282 try {
Jack He16eeac32017-08-17 12:11:18 -0700283 return service.getConnectionState(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700284 } catch (RemoteException e) {
285 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
286 return BluetoothProfile.STATE_DISCONNECTED;
287 }
288 }
Jack He16eeac32017-08-17 12:11:18 -0700289 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700290 return BluetoothProfile.STATE_DISCONNECTED;
291 }
292
293 /**
294 * Get the current audio configuration for the A2DP source device,
295 * or null if the device has no audio configuration
296 *
297 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
298 *
299 * @param device Remote bluetooth device.
300 * @return audio configuration for the device, or null
301 *
302 * {@see BluetoothAudioConfig}
303 */
Jack Hea355e5e2017-08-22 16:06:54 -0700304 public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700305 if (VDBG) log("getAudioConfig(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800306 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700307 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700308 try {
Jack He16eeac32017-08-17 12:11:18 -0700309 return service.getAudioConfig(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700310 } catch (RemoteException e) {
311 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
312 return null;
313 }
314 }
Jack He16eeac32017-08-17 12:11:18 -0700315 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700316 return null;
317 }
318
319 /**
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700320 * Set priority of the profile
321 *
322 * <p> The device should already be paired.
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800323 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700324 *
325 * @param device Paired bluetooth device
326 * @param priority
327 * @return true if priority is set, false on error
328 * @hide
329 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800330 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700331 public boolean setPriority(BluetoothDevice device, int priority) {
332 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800333 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
334 }
335
336 /**
337 * Set connection policy of the profile
338 *
339 * <p> The device should already be paired.
340 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
341 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
342 *
343 * @param device Paired bluetooth device
344 * @param connectionPolicy is the connection policy to set to for this profile
345 * @return true if connectionPolicy is set, false on error
346 * @hide
347 */
348 @SystemApi
349 @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
350 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
351 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800352 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700353 if (service != null && isEnabled() && isValidDevice(device)) {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800354 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
355 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700356 return false;
357 }
358 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800359 return service.setConnectionPolicy(device, connectionPolicy);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700360 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700361 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
362 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700363 }
364 }
Jack He16eeac32017-08-17 12:11:18 -0700365 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700366 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700367 }
368
369 /**
370 * Get the priority of the profile.
371 *
372 * <p> The priority can be any of:
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800373 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700374 *
375 * @param device Bluetooth device
376 * @return priority of the device
377 * @hide
378 */
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800379 @RequiresPermission(Manifest.permission.BLUETOOTH)
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700380 public int getPriority(BluetoothDevice device) {
381 if (VDBG) log("getPriority(" + device + ")");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800382 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
383 }
384
385 /**
386 * Get the connection policy of the profile.
387 *
388 * <p> The connection policy can be any of:
389 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
390 * {@link #CONNECTION_POLICY_UNKNOWN}
391 *
392 * @param device Bluetooth device
393 * @return connection policy of the device
394 * @hide
395 */
396 @SystemApi
397 @RequiresPermission(Manifest.permission.BLUETOOTH)
398 public int getConnectionPolicy(BluetoothDevice device) {
399 if (VDBG) log("getConnectionPolicy(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800400 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700401 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700402 try {
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800403 return service.getConnectionPolicy(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700404 } catch (RemoteException e) {
405 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800406 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700407 }
408 }
Jack He16eeac32017-08-17 12:11:18 -0700409 if (service == null) Log.w(TAG, "Proxy not attached to service");
Rahul Sabnisdf1ef4a2019-11-27 18:09:33 -0800410 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700411 }
412
413 /**
414 * Check if A2DP profile is streaming music.
415 *
416 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
417 *
418 * @param device BluetoothDevice device
419 */
420 public boolean isA2dpPlaying(BluetoothDevice device) {
Ugo Yud0115462019-03-26 21:38:08 +0800421 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700422 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700423 try {
Jack He16eeac32017-08-17 12:11:18 -0700424 return service.isA2dpPlaying(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700425 } catch (RemoteException e) {
426 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
427 return false;
428 }
429 }
Jack He16eeac32017-08-17 12:11:18 -0700430 if (service == null) Log.w(TAG, "Proxy not attached to service");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700431 return false;
432 }
433
434 /**
Mike Lockwood2263dd12014-05-14 09:51:30 -0700435 * Helper for converting a state to a string.
436 *
437 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700438 *
Mike Lockwood2263dd12014-05-14 09:51:30 -0700439 * @hide
440 */
441 public static String stateToString(int state) {
442 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700443 case STATE_DISCONNECTED:
444 return "disconnected";
445 case STATE_CONNECTING:
446 return "connecting";
447 case STATE_CONNECTED:
448 return "connected";
449 case STATE_DISCONNECTING:
450 return "disconnecting";
451 case STATE_PLAYING:
452 return "playing";
453 case STATE_NOT_PLAYING:
454 return "not playing";
455 default:
456 return "<unknown state " + state + ">";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700457 }
458 }
459
Mike Lockwood2263dd12014-05-14 09:51:30 -0700460 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700461 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Mike Lockwood2263dd12014-05-14 09:51:30 -0700462 }
463
Jack He16eeac32017-08-17 12:11:18 -0700464 private static boolean isValidDevice(BluetoothDevice device) {
465 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Mike Lockwood2263dd12014-05-14 09:51:30 -0700466 }
467
468 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700469 Log.d(TAG, msg);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700470 }
471}