blob: f66b5ff466c3f790d84aabe3b330edc4b60ae8ad [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;
20import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080023import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080025import android.content.Intent;
26import android.content.ServiceConnection;
RoboErik4197cb62015-01-21 15:45:32 -080027import android.media.AudioManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070029import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070030import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.Log;
32
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070033import java.util.ArrayList;
34import java.util.List;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
37/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070038 * This class provides the public APIs to control the Bluetooth A2DP
39 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070041 *<p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
42 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
43 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070045 * <p> Android only supports one connected Bluetooth A2dp device at a time.
46 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070048public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080050 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070051 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070053 /**
54 * Intent used to broadcast the change in connection state of the A2DP
55 * profile.
56 *
57 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080058 * <ul>
59 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
60 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
61 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
62 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070063 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080064 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070065 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
66 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
67 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080068 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
69 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 */
71 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070072 public static final String ACTION_CONNECTION_STATE_CHANGED =
73 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070075 /**
76 * Intent used to broadcast the change in the Playing state of the A2DP
77 * profile.
78 *
79 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080080 * <ul>
81 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
82 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080083 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080084 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070085 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080086 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070087 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
88 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080089 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
90 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070091 */
92 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
93 public static final String ACTION_PLAYING_STATE_CHANGED =
94 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Hemant Gupta3b76a4b2014-02-14 19:53:31 +053096 /** @hide */
97 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
98 public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
99 "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
100
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700101 /**
102 * A2DP sink device is streaming music. This state can be one of
103 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
104 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
105 */
106 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -0700107
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700108 /**
109 * A2DP sink device is NOT streaming music. This state can be one of
110 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
111 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
112 */
113 public static final int STATE_NOT_PLAYING = 11;
114
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800115 private Context mContext;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700116 private ServiceListener mServiceListener;
117 private IBluetoothA2dp mService;
118 private BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
fredc0f420372012-04-12 00:02:00 -0700120 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
121 new IBluetoothStateChangeCallback.Stub() {
122 public void onBluetoothStateChange(boolean up) {
123 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
124 if (!up) {
Matthew Xie563e4142012-10-09 22:10:37 -0700125 if (VDBG) Log.d(TAG,"Unbinding service...");
fredc0f420372012-04-12 00:02:00 -0700126 synchronized (mConnection) {
127 try {
128 mService = null;
129 mContext.unbindService(mConnection);
130 } catch (Exception re) {
131 Log.e(TAG,"",re);
132 }
133 }
134 } else {
135 synchronized (mConnection) {
136 try {
137 if (mService == null) {
Matthew Xie563e4142012-10-09 22:10:37 -0700138 if (VDBG) Log.d(TAG,"Binding service...");
Dianne Hackborn221ea892013-08-04 16:50:16 -0700139 doBind();
fredc0f420372012-04-12 00:02:00 -0700140 }
141 } catch (Exception re) {
142 Log.e(TAG,"",re);
143 }
144 }
145 }
146 }
147 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 /**
149 * Create a BluetoothA2dp proxy object for interacting with the local
150 * Bluetooth A2DP service.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700151 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 */
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800153 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
154 mContext = context;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700155 mServiceListener = l;
156 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700157 IBluetoothManager mgr = mAdapter.getBluetoothManager();
158 if (mgr != null) {
159 try {
160 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
161 } catch (RemoteException e) {
162 Log.e(TAG,"",e);
163 }
164 }
165
Dianne Hackborn221ea892013-08-04 16:50:16 -0700166 doBind();
167 }
168
169 boolean doBind() {
170 Intent intent = new Intent(IBluetoothA2dp.class.getName());
171 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
172 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700173 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
174 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700175 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
176 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700178 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
180
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800181 /*package*/ void close() {
182 mServiceListener = null;
fredc0f420372012-04-12 00:02:00 -0700183 IBluetoothManager mgr = mAdapter.getBluetoothManager();
184 if (mgr != null) {
185 try {
186 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
187 } catch (Exception e) {
188 Log.e(TAG,"",e);
189 }
190 }
191
192 synchronized (mConnection) {
193 if (mService != null) {
194 try {
195 mService = null;
196 mContext.unbindService(mConnection);
197 } catch (Exception re) {
198 Log.e(TAG,"",re);
199 }
200 }
201 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800202 }
203
fredc0f420372012-04-12 00:02:00 -0700204 public void finalize() {
Mathias Jeppsson2d2d8c22013-08-06 11:41:55 +0200205 // The empty finalize needs to be kept or the
206 // cts signature tests would fail.
fredc0f420372012-04-12 00:02:00 -0700207 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700208 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700209 * Initiate connection to a profile of the remote bluetooth device.
210 *
211 * <p> Currently, the system supports only 1 connection to the
212 * A2DP profile. The API will automatically disconnect connected
213 * devices before connecting.
214 *
215 * <p> This API returns false in scenarios like the profile on the
216 * device is already connected or Bluetooth is not turned on.
217 * When this API returns true, it is guaranteed that
218 * connection state intent for the profile will be broadcasted with
219 * the state. Users can get the connection state of the profile
220 * from this intent.
221 *
222 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
223 * permission.
224 *
225 * @param device Remote Bluetooth Device
226 * @return false on immediate error,
227 * true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700228 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700230 public boolean connect(BluetoothDevice device) {
231 if (DBG) log("connect(" + device + ")");
232 if (mService != null && isEnabled() &&
233 isValidDevice(device)) {
234 try {
235 return mService.connect(device);
236 } catch (RemoteException e) {
237 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
238 return false;
239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700241 if (mService == null) Log.w(TAG, "Proxy not attached to service");
242 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
244
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700245 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700246 * Initiate disconnection from a profile
247 *
248 * <p> This API will return false in scenarios like the profile on the
249 * Bluetooth device is not in connected state etc. When this API returns,
250 * true, it is guaranteed that the connection state change
251 * intent will be broadcasted with the state. Users can get the
252 * disconnection state of the profile from this intent.
253 *
254 * <p> If the disconnection is initiated by a remote device, the state
255 * will transition from {@link #STATE_CONNECTED} to
256 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
257 * host (local) device the state will transition from
258 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
259 * state {@link #STATE_DISCONNECTED}. The transition to
260 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
261 * two scenarios.
262 *
263 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
264 * permission.
265 *
266 * @param device Remote Bluetooth Device
267 * @return false on immediate error,
268 * true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700269 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700271 public boolean disconnect(BluetoothDevice device) {
272 if (DBG) log("disconnect(" + device + ")");
273 if (mService != null && isEnabled() &&
274 isValidDevice(device)) {
275 try {
276 return mService.disconnect(device);
277 } catch (RemoteException e) {
278 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
279 return false;
280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700282 if (mService == null) Log.w(TAG, "Proxy not attached to service");
283 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700286 /**
287 * {@inheritDoc}
288 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700289 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700290 if (VDBG) log("getConnectedDevices()");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700291 if (mService != null && isEnabled()) {
292 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700293 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700294 } catch (RemoteException e) {
295 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700296 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700297 }
298 }
299 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700300 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700301 }
302
303 /**
304 * {@inheritDoc}
305 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700306 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700307 if (VDBG) log("getDevicesMatchingStates()");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700308 if (mService != null && isEnabled()) {
309 try {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700310 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700311 } catch (RemoteException e) {
312 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700313 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700314 }
315 }
316 if (mService == null) Log.w(TAG, "Proxy not attached to service");
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700317 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700318 }
319
320 /**
321 * {@inheritDoc}
322 */
323 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700324 if (VDBG) log("getState(" + device + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700325 if (mService != null && isEnabled()
326 && isValidDevice(device)) {
327 try {
328 return mService.getConnectionState(device);
329 } catch (RemoteException e) {
330 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
331 return BluetoothProfile.STATE_DISCONNECTED;
332 }
333 }
334 if (mService == null) Log.w(TAG, "Proxy not attached to service");
335 return BluetoothProfile.STATE_DISCONNECTED;
336 }
337
338 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700339 * Set priority of the profile
340 *
341 * <p> The device should already be paired.
fredc0f420372012-04-12 00:02:00 -0700342 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700343 * {@link #PRIORITY_OFF},
344 *
345 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
346 * permission.
347 *
348 * @param device Paired bluetooth device
349 * @param priority
350 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700351 * @hide
352 */
353 public boolean setPriority(BluetoothDevice device, int priority) {
354 if (DBG) log("setPriority(" + device + ", " + priority + ")");
355 if (mService != null && isEnabled()
356 && isValidDevice(device)) {
357 if (priority != BluetoothProfile.PRIORITY_OFF &&
Ganesh Ganapathi Batta6f6c54512012-07-31 16:08:17 -0700358 priority != BluetoothProfile.PRIORITY_ON){
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700359 return false;
360 }
361 try {
362 return mService.setPriority(device, priority);
363 } catch (RemoteException e) {
364 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
365 return false;
366 }
367 }
368 if (mService == null) Log.w(TAG, "Proxy not attached to service");
369 return false;
370 }
371
372 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700373 * Get the priority of the profile.
374 *
375 * <p> The priority can be any of:
376 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
377 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
378 *
379 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
380 *
381 * @param device Bluetooth device
382 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700383 * @hide
384 */
Tor Norbye2d497522015-04-23 17:10:21 -0700385 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700386 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700387 if (VDBG) log("getPriority(" + device + ")");
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700388 if (mService != null && isEnabled()
389 && isValidDevice(device)) {
390 try {
391 return mService.getPriority(device);
392 } catch (RemoteException e) {
393 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
394 return BluetoothProfile.PRIORITY_OFF;
395 }
396 }
397 if (mService == null) Log.w(TAG, "Proxy not attached to service");
398 return BluetoothProfile.PRIORITY_OFF;
399 }
400
401 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700402 * Checks if Avrcp device supports the absolute volume feature.
403 *
404 * @return true if device supports absolute volume
405 * @hide
406 */
407 public boolean isAvrcpAbsoluteVolumeSupported() {
408 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
409 if (mService != null && isEnabled()) {
410 try {
411 return mService.isAvrcpAbsoluteVolumeSupported();
412 } catch (RemoteException e) {
413 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
414 return false;
415 }
416 }
417 if (mService == null) Log.w(TAG, "Proxy not attached to service");
418 return false;
419 }
420
421 /**
RoboErik4197cb62015-01-21 15:45:32 -0800422 * Tells remote device to adjust volume. Only if absolute volume is
423 * supported. Uses the following values:
424 * <ul>
425 * <li>{@link AudioManager#ADJUST_LOWER}</li>
426 * <li>{@link AudioManager#ADJUST_RAISE}</li>
427 * <li>{@link AudioManager#ADJUST_MUTE}</li>
428 * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
429 * </ul>
John Du5a0cf7a2013-07-19 11:30:34 -0700430 *
RoboErik4197cb62015-01-21 15:45:32 -0800431 * @param direction One of the supported adjust values.
John Du5a0cf7a2013-07-19 11:30:34 -0700432 * @hide
433 */
434 public void adjustAvrcpAbsoluteVolume(int direction) {
435 if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
436 if (mService != null && isEnabled()) {
437 try {
438 mService.adjustAvrcpAbsoluteVolume(direction);
439 return;
440 } catch (RemoteException e) {
441 Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
442 return;
443 }
444 }
445 if (mService == null) Log.w(TAG, "Proxy not attached to service");
446 }
447
448 /**
449 * Tells remote device to set an absolute volume. Only if absolute volume is supported
450 *
451 * @param volume Absolute volume to be set on AVRCP side
452 * @hide
453 */
454 public void setAvrcpAbsoluteVolume(int volume) {
455 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
456 if (mService != null && isEnabled()) {
457 try {
458 mService.setAvrcpAbsoluteVolume(volume);
459 return;
460 } catch (RemoteException e) {
461 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
462 return;
463 }
464 }
465 if (mService == null) Log.w(TAG, "Proxy not attached to service");
466 }
467
468 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700469 * Check if A2DP profile is streaming music.
470 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800471 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700472 *
473 * @param device BluetoothDevice device
474 */
475 public boolean isA2dpPlaying(BluetoothDevice device) {
476 if (mService != null && isEnabled()
477 && isValidDevice(device)) {
478 try {
479 return mService.isA2dpPlaying(device);
480 } catch (RemoteException e) {
481 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
482 return false;
483 }
484 }
485 if (mService == null) Log.w(TAG, "Proxy not attached to service");
486 return false;
487 }
488
489 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700490 * This function checks if the remote device is an AVCRP
491 * target and thus whether we should send volume keys
492 * changes or not.
493 * @hide
494 */
495 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
496 if (isEnabled() && isValidDevice(device)) {
497 ParcelUuid[] uuids = device.getUuids();
498 if (uuids == null) return false;
499
500 for (ParcelUuid uuid: uuids) {
501 if (BluetoothUuid.isAvrcpTarget(uuid)) {
502 return true;
503 }
504 }
505 }
506 return false;
507 }
508
Matthew Xiea0c68032011-06-25 21:47:07 -0700509 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700510 * Helper for converting a state to a string.
511 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 * For debug use only - strings are not internationalized.
513 * @hide
514 */
515 public static String stateToString(int state) {
516 switch (state) {
517 case STATE_DISCONNECTED:
518 return "disconnected";
519 case STATE_CONNECTING:
520 return "connecting";
521 case STATE_CONNECTED:
522 return "connected";
523 case STATE_DISCONNECTING:
524 return "disconnecting";
525 case STATE_PLAYING:
526 return "playing";
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700527 case STATE_NOT_PLAYING:
528 return "not playing";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 default:
530 return "<unknown state " + state + ">";
531 }
532 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800533
Matthew Xie9b693992013-10-10 11:21:40 -0700534 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800535 public void onServiceConnected(ComponentName className, IBinder service) {
536 if (DBG) Log.d(TAG, "Proxy object connected");
537 mService = IBluetoothA2dp.Stub.asInterface(service);
538
539 if (mServiceListener != null) {
540 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
541 }
542 }
543 public void onServiceDisconnected(ComponentName className) {
544 if (DBG) Log.d(TAG, "Proxy object disconnected");
545 mService = null;
546 if (mServiceListener != null) {
547 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
548 }
549 }
550 };
551
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700552 private boolean isEnabled() {
553 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
554 return false;
555 }
556
557 private boolean isValidDevice(BluetoothDevice device) {
558 if (device == null) return false;
559
560 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
561 return false;
562 }
563
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800564 private static void log(String msg) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700565 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567}