BluetoothA2dp.java revision 081f58abb7ceb702fdb0b65ff0e0ff70dd265a30
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 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; 83 84 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; 94 95 IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE); 96 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; 104 } 105 } 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. 110 * @param device Remote BT device. 111 * @return false on immediate error, true otherwise 112 * @hide 113 */ 114 public boolean connectSink(BluetoothDevice device) { 115 if (DBG) log("connectSink(" + device + ")"); 116 try { 117 return mService.connectSink(device); 118 } catch (RemoteException e) { 119 Log.e(TAG, "", e); 120 return false; 121 } 122 } 123 124 /** Initiate disconnect from an A2DP sink. 125 * Listen for SINK_STATE_CHANGED_ACTION to find out when 126 * disconnect is completed. 127 * @param device Remote BT device. 128 * @return false on immediate error, true otherwise 129 * @hide 130 */ 131 public boolean disconnectSink(BluetoothDevice device) { 132 if (DBG) log("disconnectSink(" + device + ")"); 133 try { 134 return mService.disconnectSink(device); 135 } catch (RemoteException e) { 136 Log.e(TAG, "", e); 137 return false; 138 } 139 } 140 141 /** 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 */ 148 public boolean suspendSink(BluetoothDevice device) { 149 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 */ 164 public boolean resumeSink(BluetoothDevice device) { 165 try { 166 return mService.resumeSink(device); 167 } catch (RemoteException e) { 168 Log.e(TAG, "", e); 169 return false; 170 } 171 } 172 173 /** Check if a specified A2DP sink is connected. 174 * @param device Remote BT device. 175 * @return True if connected (or playing), false otherwise and on error. 176 * @hide 177 */ 178 public boolean isSinkConnected(BluetoothDevice device) { 179 if (DBG) log("isSinkConnected(" + device + ")"); 180 int state = getSinkState(device); 181 return state == STATE_CONNECTED || state == STATE_PLAYING; 182 } 183 184 /** Check if any A2DP sink is connected. 185 * @return a unmodifiable set of connected A2DP sinks, or null on error. 186 * @hide 187 */ 188 public Set<BluetoothDevice> getConnectedSinks() { 189 if (DBG) log("getConnectedSinks()"); 190 try { 191 return Collections.unmodifiableSet( 192 new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks()))); 193 } catch (RemoteException e) { 194 Log.e(TAG, "", e); 195 return null; 196 } 197 } 198 199 /** Get the state of an A2DP sink 200 * @param device Remote BT device. 201 * @return State code, one of STATE_ 202 * @hide 203 */ 204 public int getSinkState(BluetoothDevice device) { 205 if (DBG) log("getSinkState(" + device + ")"); 206 try { 207 return mService.getSinkState(device); 208 } catch (RemoteException e) { 209 Log.e(TAG, "", e); 210 return BluetoothA2dp.STATE_DISCONNECTED; 211 } 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. 221 * @param device Paired sink 222 * @param priority Integer priority, for example PRIORITY_AUTO or 223 * PRIORITY_NONE 224 * @return true if priority is set, false on error 225 */ 226 public boolean setSinkPriority(BluetoothDevice device, int priority) { 227 if (DBG) log("setSinkPriority(" + device + ", " + priority + ")"); 228 try { 229 return mService.setSinkPriority(device, priority); 230 } catch (RemoteException e) { 231 Log.e(TAG, "", e); 232 return false; 233 } 234 } 235 236 /** 237 * Get priority of a2dp sink. 238 * @param device Sink 239 * @return non-negative priority, or negative error code on error. 240 */ 241 public int getSinkPriority(BluetoothDevice device) { 242 if (DBG) log("getSinkPriority(" + device + ")"); 243 try { 244 return mService.getSinkPriority(device); 245 } catch (RemoteException e) { 246 Log.e(TAG, "", e); 247 return PRIORITY_OFF; 248 } 249 } 250 251 /** 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 } 271 272 private static void log(String msg) { 273 Log.d(TAG, msg); 274 } 275} 276