A2dpService.java revision e013986fbc8796db569587afa5c6b34e53d7a31b
1/* 2 * Copyright (C) 2012 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 com.android.bluetooth.a2dp; 18 19import android.bluetooth.BluetoothDevice; 20import android.bluetooth.BluetoothProfile; 21import android.bluetooth.IBluetoothA2dp; 22import android.content.Context; 23import android.content.Intent; 24import android.provider.Settings; 25import android.util.Log; 26import com.android.bluetooth.btservice.ProfileService; 27import com.android.bluetooth.Utils; 28import java.util.ArrayList; 29import java.util.Iterator; 30import java.util.List; 31import java.util.Map; 32 33/** 34 * Provides Bluetooth A2DP profile, as a service in the Bluetooth application. 35 * @hide 36 */ 37public class A2dpService extends ProfileService { 38 private static final boolean DBG = false; 39 private static final String TAG="A2dpService"; 40 41 private A2dpStateMachine mStateMachine; 42 private Avrcp mAvrcp; 43 private static A2dpService sAd2dpService; 44 45 protected String getName() { 46 return TAG; 47 } 48 49 protected IProfileServiceBinder initBinder() { 50 return new BluetoothA2dpBinder(this); 51 } 52 53 protected boolean start() { 54 mAvrcp = Avrcp.make(this); 55 mStateMachine = A2dpStateMachine.make(this, this); 56 setA2dpService(this); 57 return true; 58 } 59 60 protected boolean stop() { 61 mStateMachine.doQuit(); 62 mAvrcp.doQuit(); 63 return true; 64 } 65 66 protected boolean cleanup() { 67 if (mStateMachine!= null) { 68 mStateMachine.cleanup(); 69 } 70 if (mAvrcp != null) { 71 mAvrcp.cleanup(); 72 mAvrcp = null; 73 } 74 clearA2dpService(); 75 return true; 76 } 77 78 //API Methods 79 80 public static synchronized A2dpService getA2dpService(){ 81 if (sAd2dpService != null && sAd2dpService.isAvailable()) { 82 if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService); 83 return sAd2dpService; 84 } 85 if (DBG) { 86 if (sAd2dpService == null) { 87 Log.d(TAG, "getA2dpService(): service is NULL"); 88 } else if (!(sAd2dpService.isAvailable())) { 89 Log.d(TAG,"getA2dpService(): service is not available"); 90 } 91 } 92 return null; 93 } 94 95 private static synchronized void setA2dpService(A2dpService instance) { 96 if (instance != null && instance.isAvailable()) { 97 if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService); 98 sAd2dpService = instance; 99 } else { 100 if (DBG) { 101 if (sAd2dpService == null) { 102 Log.d(TAG, "setA2dpService(): service not available"); 103 } else if (!sAd2dpService.isAvailable()) { 104 Log.d(TAG,"setA2dpService(): service is cleaning up"); 105 } 106 } 107 } 108 } 109 110 private static synchronized void clearA2dpService() { 111 sAd2dpService = null; 112 } 113 114 public boolean connect(BluetoothDevice device) { 115 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 116 "Need BLUETOOTH ADMIN permission"); 117 118 if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 119 return false; 120 } 121 122 int connectionState = mStateMachine.getConnectionState(device); 123 if (connectionState == BluetoothProfile.STATE_CONNECTED || 124 connectionState == BluetoothProfile.STATE_CONNECTING) { 125 return false; 126 } 127 128 mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device); 129 return true; 130 } 131 132 boolean disconnect(BluetoothDevice device) { 133 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 134 "Need BLUETOOTH ADMIN permission"); 135 int connectionState = mStateMachine.getConnectionState(device); 136 if (connectionState != BluetoothProfile.STATE_CONNECTED && 137 connectionState != BluetoothProfile.STATE_CONNECTING) { 138 return false; 139 } 140 141 mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device); 142 return true; 143 } 144 145 public List<BluetoothDevice> getConnectedDevices() { 146 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 147 return mStateMachine.getConnectedDevices(); 148 } 149 150 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 151 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 152 return mStateMachine.getDevicesMatchingConnectionStates(states); 153 } 154 155 int getConnectionState(BluetoothDevice device) { 156 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 157 return mStateMachine.getConnectionState(device); 158 } 159 160 public boolean setPriority(BluetoothDevice device, int priority) { 161 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 162 "Need BLUETOOTH_ADMIN permission"); 163 Settings.Global.putInt(getContentResolver(), 164 Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), 165 priority); 166 if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority); 167 return true; 168 } 169 170 public int getPriority(BluetoothDevice device) { 171 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 172 "Need BLUETOOTH_ADMIN permission"); 173 int priority = Settings.Global.getInt(getContentResolver(), 174 Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), 175 BluetoothProfile.PRIORITY_UNDEFINED); 176 return priority; 177 } 178 179 /* Absolute volume implementation */ 180 public boolean isAvrcpAbsoluteVolumeSupported() { 181 return mAvrcp.isAbsoluteVolumeSupported(); 182 } 183 184 public void adjustAvrcpAbsoluteVolume(int direction) { 185 mAvrcp.adjustVolume(direction); 186 } 187 188 public void setAvrcpAbsoluteVolume(int volume) { 189 mAvrcp.setAbsoluteVolume(volume); 190 } 191 192 public void setAvrcpAudioState(int state) { 193 mAvrcp.setA2dpAudioState(state); 194 } 195 196 synchronized boolean isA2dpPlaying(BluetoothDevice device) { 197 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 198 "Need BLUETOOTH permission"); 199 if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")"); 200 return mStateMachine.isPlaying(device); 201 } 202 203 synchronized public void sendPassThroughCmd(int keyCode, int keyState) { 204 if (DBG) Log.d(TAG, "sendPassThroughCmd"); 205 if (mAvrcp != null) { 206 mAvrcp.sendPassThroughCmd(keyCode, keyState); 207 } else { 208 Log.e(TAG,"mAvrcp is null"); 209 } 210 } 211 212 synchronized boolean isAvrcpConnected(BluetoothDevice device) { 213 if (DBG) Log.d(TAG, "isAvrcpConnected"); 214 if (mAvrcp != null) { 215 return mAvrcp.isAvrcpConnected(device); 216 } else { 217 Log.e(TAG,"mAvrcp is null"); 218 return false; 219 } 220 } 221 222 //Binder object: Must be static class or memory leak may occur 223 private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub 224 implements IProfileServiceBinder { 225 private A2dpService mService; 226 227 private A2dpService getService() { 228 if (!Utils.checkCaller()) { 229 Log.w(TAG,"A2dp call not allowed for non-active user"); 230 return null; 231 } 232 233 if (mService != null && mService.isAvailable()) { 234 return mService; 235 } 236 return null; 237 } 238 239 BluetoothA2dpBinder(A2dpService svc) { 240 mService = svc; 241 } 242 243 public boolean cleanup() { 244 mService = null; 245 return true; 246 } 247 248 public boolean connect(BluetoothDevice device) { 249 A2dpService service = getService(); 250 if (service == null) return false; 251 return service.connect(device); 252 } 253 254 public boolean disconnect(BluetoothDevice device) { 255 A2dpService service = getService(); 256 if (service == null) return false; 257 return service.disconnect(device); 258 } 259 260 public List<BluetoothDevice> getConnectedDevices() { 261 A2dpService service = getService(); 262 if (service == null) return new ArrayList<BluetoothDevice>(0); 263 return service.getConnectedDevices(); 264 } 265 266 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 267 A2dpService service = getService(); 268 if (service == null) return new ArrayList<BluetoothDevice>(0); 269 return service.getDevicesMatchingConnectionStates(states); 270 } 271 272 public int getConnectionState(BluetoothDevice device) { 273 A2dpService service = getService(); 274 if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 275 return service.getConnectionState(device); 276 } 277 278 public boolean setPriority(BluetoothDevice device, int priority) { 279 A2dpService service = getService(); 280 if (service == null) return false; 281 return service.setPriority(device, priority); 282 } 283 284 public int getPriority(BluetoothDevice device) { 285 A2dpService service = getService(); 286 if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 287 return service.getPriority(device); 288 } 289 290 public boolean isAvrcpAbsoluteVolumeSupported() { 291 A2dpService service = getService(); 292 if (service == null) return false; 293 return service.isAvrcpAbsoluteVolumeSupported(); 294 } 295 296 public void adjustAvrcpAbsoluteVolume(int direction) { 297 A2dpService service = getService(); 298 if (service == null) return; 299 service.adjustAvrcpAbsoluteVolume(direction); 300 } 301 302 public void setAvrcpAbsoluteVolume(int volume) { 303 A2dpService service = getService(); 304 if (service == null) return; 305 service.setAvrcpAbsoluteVolume(volume); 306 } 307 308 public boolean isA2dpPlaying(BluetoothDevice device) { 309 A2dpService service = getService(); 310 if (service == null) return false; 311 return service.isA2dpPlaying(device); 312 } 313 314 public boolean isAvrcpConnected(BluetoothDevice device) { 315 Log.v(TAG,"Binder Call: isAvrcpConnected: " + device.getAddress()); 316 A2dpService service = getService(); 317 if (service == null) return false; 318 return service.isAvrcpConnected(device); 319 } 320 321 public void sendPassThroughCmd(int keyCode, int keyState) { 322 Log.v(TAG,"Binder Call: sendPassThroughCmd"); 323 A2dpService service = getService(); 324 if (service == null) return; 325 service.sendPassThroughCmd(keyCode, keyState); 326 } 327 }; 328} 329