BluetoothA2dp.java revision b16c4f7dd92dabf0cc27438a5d3d9ebd203a38b3
1/* 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 28import java.util.Arrays; 29import java.util.Collections; 30import java.util.Set; 31import java.util.HashSet; 32 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. 45 * 46 * Currently this class provides methods to connect to A2DP audio sinks. 47 * 48 * @hide 49 */ 50public final class BluetoothA2dp { 51 private static final String TAG = "BluetoothA2dp"; 52 private static final boolean DBG = false; 53 54 /** 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"; 60 61 /** Indicates the state of an A2DP audio sink has changed. 62 * This intent will always contain EXTRA_SINK_STATE, 63 * EXTRA_PREVIOUS_SINK_STATE and BluetoothDevice.EXTRA_DEVICE 64 * extras. 65 */ 66 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 67 public static final String ACTION_SINK_STATE_CHANGED = 68 "android.bluetooth.a2dp.action.SINK_STATE_CHANGED"; 69 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 we try to auto-connect 78 * and allow incoming connections */ 79 public static final int PRIORITY_AUTO_CONNECT = 1000; 80 /** Default priority for a2dp devices that should allow incoming 81 * connections */ 82 public static final int PRIORITY_ON = 100; 83 /** Default priority for a2dp devices that should not allow incoming 84 * connections */ 85 public static final int PRIORITY_OFF = 0; 86 87 private final IBluetoothA2dp mService; 88 private final Context mContext; 89 90 /** 91 * Create a BluetoothA2dp proxy object for interacting with the local 92 * Bluetooth A2DP service. 93 * @param c Context 94 */ 95 public BluetoothA2dp(Context c) { 96 mContext = c; 97 98 IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE); 99 if (b != null) { 100 mService = IBluetoothA2dp.Stub.asInterface(b); 101 } else { 102 Log.w(TAG, "Bluetooth A2DP service not available!"); 103 104 // Instead of throwing an exception which prevents people from going 105 // into Wireless settings in the emulator. Let it crash later when it is actually used. 106 mService = null; 107 } 108 } 109 110 /** Initiate a connection to an A2DP sink. 111 * Listen for SINK_STATE_CHANGED_ACTION to find out when the 112 * connection is completed. 113 * @param device Remote BT device. 114 * @return false on immediate error, true otherwise 115 * @hide 116 */ 117 public boolean connectSink(BluetoothDevice device) { 118 if (DBG) log("connectSink(" + device + ")"); 119 try { 120 return mService.connectSink(device); 121 } catch (RemoteException e) { 122 Log.e(TAG, "", e); 123 return false; 124 } 125 } 126 127 /** Initiate disconnect from an A2DP sink. 128 * Listen for SINK_STATE_CHANGED_ACTION to find out when 129 * disconnect is completed. 130 * @param device Remote BT device. 131 * @return false on immediate error, true otherwise 132 * @hide 133 */ 134 public boolean disconnectSink(BluetoothDevice device) { 135 if (DBG) log("disconnectSink(" + device + ")"); 136 try { 137 return mService.disconnectSink(device); 138 } catch (RemoteException e) { 139 Log.e(TAG, "", e); 140 return false; 141 } 142 } 143 144 /** Initiate suspend from an A2DP sink. 145 * Listen for SINK_STATE_CHANGED_ACTION to find out when 146 * suspend is completed. 147 * @param device Remote BT device. 148 * @return false on immediate error, true otherwise 149 * @hide 150 */ 151 public boolean suspendSink(BluetoothDevice device) { 152 try { 153 return mService.suspendSink(device); 154 } catch (RemoteException e) { 155 Log.e(TAG, "", e); 156 return false; 157 } 158 } 159 160 /** Initiate resume from an suspended A2DP sink. 161 * Listen for SINK_STATE_CHANGED_ACTION to find out when 162 * resume is completed. 163 * @param device Remote BT device. 164 * @return false on immediate error, true otherwise 165 * @hide 166 */ 167 public boolean resumeSink(BluetoothDevice device) { 168 try { 169 return mService.resumeSink(device); 170 } catch (RemoteException e) { 171 Log.e(TAG, "", e); 172 return false; 173 } 174 } 175 176 /** Check if a specified A2DP sink is connected. 177 * @param device Remote BT device. 178 * @return True if connected (or playing), false otherwise and on error. 179 * @hide 180 */ 181 public boolean isSinkConnected(BluetoothDevice device) { 182 if (DBG) log("isSinkConnected(" + device + ")"); 183 int state = getSinkState(device); 184 return state == STATE_CONNECTED || state == STATE_PLAYING; 185 } 186 187 /** Check if any A2DP sink is connected. 188 * @return a unmodifiable set of connected A2DP sinks, or null on error. 189 * @hide 190 */ 191 public Set<BluetoothDevice> getConnectedSinks() { 192 if (DBG) log("getConnectedSinks()"); 193 try { 194 return Collections.unmodifiableSet( 195 new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks()))); 196 } catch (RemoteException e) { 197 Log.e(TAG, "", e); 198 return null; 199 } 200 } 201 202 /** Check if any A2DP sink is in Non Disconnected state 203 * i.e playing, connected, connecting, disconnecting. 204 * @return a unmodifiable set of connected A2DP sinks, or null on error. 205 * @hide 206 */ 207 public Set<BluetoothDevice> getNonDisconnectedSinks() { 208 if (DBG) log("getNonDisconnectedSinks()"); 209 try { 210 return Collections.unmodifiableSet( 211 new HashSet<BluetoothDevice>(Arrays.asList(mService.getNonDisconnectedSinks()))); 212 } catch (RemoteException e) { 213 Log.e(TAG, "", e); 214 return null; 215 } 216 } 217 218 /** Get the state of an A2DP sink 219 * @param device Remote BT device. 220 * @return State code, one of STATE_ 221 * @hide 222 */ 223 public int getSinkState(BluetoothDevice device) { 224 if (DBG) log("getSinkState(" + device + ")"); 225 try { 226 return mService.getSinkState(device); 227 } catch (RemoteException e) { 228 Log.e(TAG, "", e); 229 return BluetoothA2dp.STATE_DISCONNECTED; 230 } 231 } 232 233 /** 234 * Set priority of a2dp sink. 235 * Priority is a non-negative integer. By default paired sinks will have 236 * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0). 237 * Sinks with priority greater than zero will accept incoming connections 238 * (if no sink is currently connected). 239 * Priority for unpaired sink must be PRIORITY_NONE. 240 * @param device Paired sink 241 * @param priority Integer priority, for example PRIORITY_AUTO or 242 * PRIORITY_NONE 243 * @return true if priority is set, false on error 244 */ 245 public boolean setSinkPriority(BluetoothDevice device, int priority) { 246 if (DBG) log("setSinkPriority(" + device + ", " + priority + ")"); 247 try { 248 return mService.setSinkPriority(device, priority); 249 } catch (RemoteException e) { 250 Log.e(TAG, "", e); 251 return false; 252 } 253 } 254 255 /** 256 * Get priority of a2dp sink. 257 * @param device Sink 258 * @return non-negative priority, or negative error code on error. 259 */ 260 public int getSinkPriority(BluetoothDevice device) { 261 if (DBG) log("getSinkPriority(" + device + ")"); 262 try { 263 return mService.getSinkPriority(device); 264 } catch (RemoteException e) { 265 Log.e(TAG, "", e); 266 return PRIORITY_OFF; 267 } 268 } 269 270 /** Helper for converting a state to a string. 271 * For debug use only - strings are not internationalized. 272 * @hide 273 */ 274 public static String stateToString(int state) { 275 switch (state) { 276 case STATE_DISCONNECTED: 277 return "disconnected"; 278 case STATE_CONNECTING: 279 return "connecting"; 280 case STATE_CONNECTED: 281 return "connected"; 282 case STATE_DISCONNECTING: 283 return "disconnecting"; 284 case STATE_PLAYING: 285 return "playing"; 286 default: 287 return "<unknown state " + state + ">"; 288 } 289 } 290 291 private static void log(String msg) { 292 Log.d(TAG, msg); 293 } 294} 295