blob: e8a69d8c1f766238475d51eca3478c4bee86dee7 [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;
21import android.server.BluetoothA2dpService;
22import android.content.Context;
23import android.os.ServiceManager;
24import android.os.RemoteException;
25import android.os.IBinder;
26import android.util.Log;
27
Nick Pellybd022f42009-08-14 18:33:38 -070028import java.util.Arrays;
29import java.util.Collections;
30import java.util.Set;
31import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33/**
34 * Public API for controlling the Bluetooth A2DP Profile Service.
35 *
36 * BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
37 * Service via IPC.
38 *
39 * Creating a BluetoothA2dp object will initiate a binding with the
40 * BluetoothHeadset service. Users of this object should call close() when they
41 * are finished, so that this proxy object can unbind from the service.
42 *
43 * Currently the BluetoothA2dp service runs in the system server and this
44 * proxy object will be immediately bound to the service on construction.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 *
46 * Currently this class provides methods to connect to A2DP audio sinks.
47 *
48 * @hide
49 */
Nick Pellybd022f42009-08-14 18:33:38 -070050public final class BluetoothA2dp {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 private static final String TAG = "BluetoothA2dp";
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080052 private static final boolean DBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
Nick Pelly005b2282009-09-10 10:21:56 -070054 /** int extra for ACTION_SINK_STATE_CHANGED */
55 public static final String EXTRA_SINK_STATE =
56 "android.bluetooth.a2dp.extra.SINK_STATE";
57 /** int extra for ACTION_SINK_STATE_CHANGED */
58 public static final String EXTRA_PREVIOUS_SINK_STATE =
59 "android.bluetooth.a2dp.extra.PREVIOUS_SINK_STATE";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
61 /** Indicates the state of an A2DP audio sink has changed.
Nick Pelly005b2282009-09-10 10:21:56 -070062 * This intent will always contain EXTRA_SINK_STATE,
63 * EXTRA_PREVIOUS_SINK_STATE and BluetoothDevice.EXTRA_DEVICE
64 * extras.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 */
66 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Nick Pelly005b2282009-09-10 10:21:56 -070067 public static final String ACTION_SINK_STATE_CHANGED =
68 "android.bluetooth.a2dp.action.SINK_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70 public static final int STATE_DISCONNECTED = 0;
71 public static final int STATE_CONNECTING = 1;
72 public static final int STATE_CONNECTED = 2;
73 public static final int STATE_DISCONNECTING = 3;
74 /** Playing implies connected */
75 public static final int STATE_PLAYING = 4;
76
77 /** Default priority for a2dp devices that should allow incoming
78 * connections */
79 public static final int PRIORITY_AUTO = 100;
80 /** Default priority for a2dp devices that should not allow incoming
81 * connections */
82 public static final int PRIORITY_OFF = 0;
Nick Pellybd022f42009-08-14 18:33:38 -070083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 private final IBluetoothA2dp mService;
85 private final Context mContext;
86
87 /**
88 * Create a BluetoothA2dp proxy object for interacting with the local
89 * Bluetooth A2DP service.
90 * @param c Context
91 */
92 public BluetoothA2dp(Context c) {
93 mContext = c;
Nick Pellybd022f42009-08-14 18:33:38 -070094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
Michael Chan081f58a2009-09-30 17:59:40 -070096 if (b != null) {
97 mService = IBluetoothA2dp.Stub.asInterface(b);
98 } else {
99 Log.w(TAG, "Bluetooth A2DP service not available!");
100
101 // Instead of throwing an exception which prevents people from going
102 // into Wireless settings in the emulator. Let it crash later when it is actually used.
103 mService = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 }
106
107 /** Initiate a connection to an A2DP sink.
108 * Listen for SINK_STATE_CHANGED_ACTION to find out when the
109 * connection is completed.
Nick Pellybd022f42009-08-14 18:33:38 -0700110 * @param device Remote BT device.
Nick Pellyb24e11b2009-09-08 17:40:43 -0700111 * @return false on immediate error, true otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 * @hide
113 */
Nick Pellyb24e11b2009-09-08 17:40:43 -0700114 public boolean connectSink(BluetoothDevice device) {
Nick Pellybd022f42009-08-14 18:33:38 -0700115 if (DBG) log("connectSink(" + device + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700117 return mService.connectSink(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700119 Log.e(TAG, "", e);
120 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 }
122 }
123
124 /** Initiate disconnect from an A2DP sink.
125 * Listen for SINK_STATE_CHANGED_ACTION to find out when
126 * disconnect is completed.
Nick Pellybd022f42009-08-14 18:33:38 -0700127 * @param device Remote BT device.
Nick Pellyb24e11b2009-09-08 17:40:43 -0700128 * @return false on immediate error, true otherwise
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 * @hide
130 */
Nick Pellyb24e11b2009-09-08 17:40:43 -0700131 public boolean disconnectSink(BluetoothDevice device) {
Nick Pellybd022f42009-08-14 18:33:38 -0700132 if (DBG) log("disconnectSink(" + device + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700134 return mService.disconnectSink(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700136 Log.e(TAG, "", e);
137 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 }
139 }
140
Zhu Lanf9bbe1e2009-06-24 10:51:57 +0800141 /** Initiate suspend from an A2DP sink.
142 * Listen for SINK_STATE_CHANGED_ACTION to find out when
143 * suspend is completed.
144 * @param device Remote BT device.
145 * @return false on immediate error, true otherwise
146 * @hide
147 */
Nick Pellye766eae2009-09-30 12:06:28 -0700148 public boolean suspendSink(BluetoothDevice device) {
Zhu Lanf9bbe1e2009-06-24 10:51:57 +0800149 try {
150 return mService.suspendSink(device);
151 } catch (RemoteException e) {
152 Log.e(TAG, "", e);
153 return false;
154 }
155 }
156
157 /** Initiate resume from an suspended A2DP sink.
158 * Listen for SINK_STATE_CHANGED_ACTION to find out when
159 * resume is completed.
160 * @param device Remote BT device.
161 * @return false on immediate error, true otherwise
162 * @hide
163 */
Nick Pellye766eae2009-09-30 12:06:28 -0700164 public boolean resumeSink(BluetoothDevice device) {
Zhu Lanf9bbe1e2009-06-24 10:51:57 +0800165 try {
166 return mService.resumeSink(device);
167 } catch (RemoteException e) {
168 Log.e(TAG, "", e);
169 return false;
170 }
171 }
172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 /** Check if a specified A2DP sink is connected.
Nick Pellybd022f42009-08-14 18:33:38 -0700174 * @param device Remote BT device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 * @return True if connected (or playing), false otherwise and on error.
176 * @hide
177 */
Nick Pellybd022f42009-08-14 18:33:38 -0700178 public boolean isSinkConnected(BluetoothDevice device) {
179 if (DBG) log("isSinkConnected(" + device + ")");
180 int state = getSinkState(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return state == STATE_CONNECTED || state == STATE_PLAYING;
182 }
183
184 /** Check if any A2DP sink is connected.
Nick Pellybd022f42009-08-14 18:33:38 -0700185 * @return a unmodifiable set of connected A2DP sinks, or null on error.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 * @hide
187 */
Nick Pellybd022f42009-08-14 18:33:38 -0700188 public Set<BluetoothDevice> getConnectedSinks() {
189 if (DBG) log("getConnectedSinks()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700191 return Collections.unmodifiableSet(
192 new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700194 Log.e(TAG, "", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 return null;
196 }
197 }
198
199 /** Get the state of an A2DP sink
Nick Pellybd022f42009-08-14 18:33:38 -0700200 * @param device Remote BT device.
Nick Pellyb24e11b2009-09-08 17:40:43 -0700201 * @return State code, one of STATE_
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 * @hide
203 */
Nick Pellybd022f42009-08-14 18:33:38 -0700204 public int getSinkState(BluetoothDevice device) {
205 if (DBG) log("getSinkState(" + device + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700207 return mService.getSinkState(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700209 Log.e(TAG, "", e);
210 return BluetoothA2dp.STATE_DISCONNECTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 }
212 }
213
214 /**
215 * Set priority of a2dp sink.
216 * Priority is a non-negative integer. By default paired sinks will have
217 * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
218 * Sinks with priority greater than zero will accept incoming connections
219 * (if no sink is currently connected).
220 * Priority for unpaired sink must be PRIORITY_NONE.
Nick Pellybd022f42009-08-14 18:33:38 -0700221 * @param device Paired sink
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 * @param priority Integer priority, for example PRIORITY_AUTO or
223 * PRIORITY_NONE
Nick Pellyb24e11b2009-09-08 17:40:43 -0700224 * @return true if priority is set, false on error
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 */
Nick Pellyb24e11b2009-09-08 17:40:43 -0700226 public boolean setSinkPriority(BluetoothDevice device, int priority) {
Nick Pellybd022f42009-08-14 18:33:38 -0700227 if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700229 return mService.setSinkPriority(device, priority);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700231 Log.e(TAG, "", e);
232 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234 }
235
236 /**
237 * Get priority of a2dp sink.
Nick Pellybd022f42009-08-14 18:33:38 -0700238 * @param device Sink
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 * @return non-negative priority, or negative error code on error.
240 */
Nick Pellybd022f42009-08-14 18:33:38 -0700241 public int getSinkPriority(BluetoothDevice device) {
242 if (DBG) log("getSinkPriority(" + device + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 try {
Nick Pellybd022f42009-08-14 18:33:38 -0700244 return mService.getSinkPriority(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 } catch (RemoteException e) {
Nick Pellyb24e11b2009-09-08 17:40:43 -0700246 Log.e(TAG, "", e);
247 return PRIORITY_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 }
249 }
250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 /** Helper for converting a state to a string.
252 * For debug use only - strings are not internationalized.
253 * @hide
254 */
255 public static String stateToString(int state) {
256 switch (state) {
257 case STATE_DISCONNECTED:
258 return "disconnected";
259 case STATE_CONNECTING:
260 return "connecting";
261 case STATE_CONNECTED:
262 return "connected";
263 case STATE_DISCONNECTING:
264 return "disconnecting";
265 case STATE_PLAYING:
266 return "playing";
267 default:
268 return "<unknown state " + state + ">";
269 }
270 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800271
272 private static void log(String msg) {
273 Log.d(TAG, msg);
274 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275}