BluetoothA2dp.java revision f9bbe1e71a502fe7bd1f4a23ba5bbe4dde0d9d57
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 throw new RuntimeException("Bluetooth A2DP service not available!"); 98 } 99 mService = IBluetoothA2dp.Stub.asInterface(b); 100 } 101 102 /** Initiate a connection to an A2DP sink. 103 * Listen for SINK_STATE_CHANGED_ACTION to find out when the 104 * connection is completed. 105 * @param device Remote BT device. 106 * @return false on immediate error, true otherwise 107 * @hide 108 */ 109 public boolean connectSink(BluetoothDevice device) { 110 if (DBG) log("connectSink(" + device + ")"); 111 try { 112 return mService.connectSink(device); 113 } catch (RemoteException e) { 114 Log.e(TAG, "", e); 115 return false; 116 } 117 } 118 119 /** Initiate disconnect from an A2DP sink. 120 * Listen for SINK_STATE_CHANGED_ACTION to find out when 121 * disconnect is completed. 122 * @param device Remote BT device. 123 * @return false on immediate error, true otherwise 124 * @hide 125 */ 126 public boolean disconnectSink(BluetoothDevice device) { 127 if (DBG) log("disconnectSink(" + device + ")"); 128 try { 129 return mService.disconnectSink(device); 130 } catch (RemoteException e) { 131 Log.e(TAG, "", e); 132 return false; 133 } 134 } 135 136 /** Initiate suspend from an A2DP sink. 137 * Listen for SINK_STATE_CHANGED_ACTION to find out when 138 * suspend is completed. 139 * @param device Remote BT device. 140 * @return false on immediate error, true otherwise 141 * @hide 142 */ 143 public int suspendSink(BluetoothDevice device) { 144 try { 145 return mService.suspendSink(device); 146 } catch (RemoteException e) { 147 Log.e(TAG, "", e); 148 return false; 149 } 150 } 151 152 /** Initiate resume from an suspended A2DP sink. 153 * Listen for SINK_STATE_CHANGED_ACTION to find out when 154 * resume is completed. 155 * @param device Remote BT device. 156 * @return false on immediate error, true otherwise 157 * @hide 158 */ 159 public int resumeSink(BluetoothDevice device) { 160 try { 161 return mService.resumeSink(device); 162 } catch (RemoteException e) { 163 Log.e(TAG, "", e); 164 return false; 165 } 166 } 167 168 /** Check if a specified A2DP sink is connected. 169 * @param device Remote BT device. 170 * @return True if connected (or playing), false otherwise and on error. 171 * @hide 172 */ 173 public boolean isSinkConnected(BluetoothDevice device) { 174 if (DBG) log("isSinkConnected(" + device + ")"); 175 int state = getSinkState(device); 176 return state == STATE_CONNECTED || state == STATE_PLAYING; 177 } 178 179 /** Check if any A2DP sink is connected. 180 * @return a unmodifiable set of connected A2DP sinks, or null on error. 181 * @hide 182 */ 183 public Set<BluetoothDevice> getConnectedSinks() { 184 if (DBG) log("getConnectedSinks()"); 185 try { 186 return Collections.unmodifiableSet( 187 new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks()))); 188 } catch (RemoteException e) { 189 Log.e(TAG, "", e); 190 return null; 191 } 192 } 193 194 /** Get the state of an A2DP sink 195 * @param device Remote BT device. 196 * @return State code, one of STATE_ 197 * @hide 198 */ 199 public int getSinkState(BluetoothDevice device) { 200 if (DBG) log("getSinkState(" + device + ")"); 201 try { 202 return mService.getSinkState(device); 203 } catch (RemoteException e) { 204 Log.e(TAG, "", e); 205 return BluetoothA2dp.STATE_DISCONNECTED; 206 } 207 } 208 209 /** 210 * Set priority of a2dp sink. 211 * Priority is a non-negative integer. By default paired sinks will have 212 * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0). 213 * Sinks with priority greater than zero will accept incoming connections 214 * (if no sink is currently connected). 215 * Priority for unpaired sink must be PRIORITY_NONE. 216 * @param device Paired sink 217 * @param priority Integer priority, for example PRIORITY_AUTO or 218 * PRIORITY_NONE 219 * @return true if priority is set, false on error 220 */ 221 public boolean setSinkPriority(BluetoothDevice device, int priority) { 222 if (DBG) log("setSinkPriority(" + device + ", " + priority + ")"); 223 try { 224 return mService.setSinkPriority(device, priority); 225 } catch (RemoteException e) { 226 Log.e(TAG, "", e); 227 return false; 228 } 229 } 230 231 /** 232 * Get priority of a2dp sink. 233 * @param device Sink 234 * @return non-negative priority, or negative error code on error. 235 */ 236 public int getSinkPriority(BluetoothDevice device) { 237 if (DBG) log("getSinkPriority(" + device + ")"); 238 try { 239 return mService.getSinkPriority(device); 240 } catch (RemoteException e) { 241 Log.e(TAG, "", e); 242 return PRIORITY_OFF; 243 } 244 } 245 246 /** Helper for converting a state to a string. 247 * For debug use only - strings are not internationalized. 248 * @hide 249 */ 250 public static String stateToString(int state) { 251 switch (state) { 252 case STATE_DISCONNECTED: 253 return "disconnected"; 254 case STATE_CONNECTING: 255 return "connecting"; 256 case STATE_CONNECTED: 257 return "connected"; 258 case STATE_DISCONNECTING: 259 return "disconnecting"; 260 case STATE_PLAYING: 261 return "playing"; 262 default: 263 return "<unknown state " + state + ">"; 264 } 265 } 266 267 private static void log(String msg) { 268 Log.d(TAG, msg); 269 } 270} 271