BluetoothA2dp.java revision 005b228cdfb369d9b3b325884c0337ba5968bf8c
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 /** Check if a specified A2DP sink is connected. 137 * @param device Remote BT device. 138 * @return True if connected (or playing), false otherwise and on error. 139 * @hide 140 */ 141 public boolean isSinkConnected(BluetoothDevice device) { 142 if (DBG) log("isSinkConnected(" + device + ")"); 143 int state = getSinkState(device); 144 return state == STATE_CONNECTED || state == STATE_PLAYING; 145 } 146 147 /** Check if any A2DP sink is connected. 148 * @return a unmodifiable set of connected A2DP sinks, or null on error. 149 * @hide 150 */ 151 public Set<BluetoothDevice> getConnectedSinks() { 152 if (DBG) log("getConnectedSinks()"); 153 try { 154 return Collections.unmodifiableSet( 155 new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks()))); 156 } catch (RemoteException e) { 157 Log.e(TAG, "", e); 158 return null; 159 } 160 } 161 162 /** Get the state of an A2DP sink 163 * @param device Remote BT device. 164 * @return State code, one of STATE_ 165 * @hide 166 */ 167 public int getSinkState(BluetoothDevice device) { 168 if (DBG) log("getSinkState(" + device + ")"); 169 try { 170 return mService.getSinkState(device); 171 } catch (RemoteException e) { 172 Log.e(TAG, "", e); 173 return BluetoothA2dp.STATE_DISCONNECTED; 174 } 175 } 176 177 /** 178 * Set priority of a2dp sink. 179 * Priority is a non-negative integer. By default paired sinks will have 180 * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0). 181 * Sinks with priority greater than zero will accept incoming connections 182 * (if no sink is currently connected). 183 * Priority for unpaired sink must be PRIORITY_NONE. 184 * @param device Paired sink 185 * @param priority Integer priority, for example PRIORITY_AUTO or 186 * PRIORITY_NONE 187 * @return true if priority is set, false on error 188 */ 189 public boolean setSinkPriority(BluetoothDevice device, int priority) { 190 if (DBG) log("setSinkPriority(" + device + ", " + priority + ")"); 191 try { 192 return mService.setSinkPriority(device, priority); 193 } catch (RemoteException e) { 194 Log.e(TAG, "", e); 195 return false; 196 } 197 } 198 199 /** 200 * Get priority of a2dp sink. 201 * @param device Sink 202 * @return non-negative priority, or negative error code on error. 203 */ 204 public int getSinkPriority(BluetoothDevice device) { 205 if (DBG) log("getSinkPriority(" + device + ")"); 206 try { 207 return mService.getSinkPriority(device); 208 } catch (RemoteException e) { 209 Log.e(TAG, "", e); 210 return PRIORITY_OFF; 211 } 212 } 213 214 /** Helper for converting a state to a string. 215 * For debug use only - strings are not internationalized. 216 * @hide 217 */ 218 public static String stateToString(int state) { 219 switch (state) { 220 case STATE_DISCONNECTED: 221 return "disconnected"; 222 case STATE_CONNECTING: 223 return "connecting"; 224 case STATE_CONNECTED: 225 return "connected"; 226 case STATE_DISCONNECTING: 227 return "disconnecting"; 228 case STATE_PLAYING: 229 return "playing"; 230 default: 231 return "<unknown state " + state + ">"; 232 } 233 } 234 235 private static void log(String msg) { 236 Log.d(TAG, msg); 237 } 238} 239