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 17 package com.android.bluetooth.a2dp; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.bluetooth.BluetoothProfile; 21 import android.bluetooth.IBluetoothA2dp; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.provider.Settings; 25 import android.util.Log; 26 import com.android.bluetooth.btservice.ProfileService; 27 import com.android.bluetooth.Utils; 28 import java.util.ArrayList; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.Map; 32 33 /** 34 * Provides Bluetooth A2DP profile, as a service in the Bluetooth application. 35 * @hide 36 */ 37 public 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 //Binder object: Must be static class or memory leak may occur 204 private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub 205 implements IProfileServiceBinder { 206 private A2dpService mService; 207 208 private A2dpService getService() { 209 if (!Utils.checkCaller()) { 210 Log.w(TAG,"A2dp call not allowed for non-active user"); 211 return null; 212 } 213 214 if (mService != null && mService.isAvailable()) { 215 return mService; 216 } 217 return null; 218 } 219 220 BluetoothA2dpBinder(A2dpService svc) { 221 mService = svc; 222 } 223 224 public boolean cleanup() { 225 mService = null; 226 return true; 227 } 228 229 public boolean connect(BluetoothDevice device) { 230 A2dpService service = getService(); 231 if (service == null) return false; 232 return service.connect(device); 233 } 234 235 public boolean disconnect(BluetoothDevice device) { 236 A2dpService service = getService(); 237 if (service == null) return false; 238 return service.disconnect(device); 239 } 240 241 public List<BluetoothDevice> getConnectedDevices() { 242 A2dpService service = getService(); 243 if (service == null) return new ArrayList<BluetoothDevice>(0); 244 return service.getConnectedDevices(); 245 } 246 247 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 248 A2dpService service = getService(); 249 if (service == null) return new ArrayList<BluetoothDevice>(0); 250 return service.getDevicesMatchingConnectionStates(states); 251 } 252 253 public int getConnectionState(BluetoothDevice device) { 254 A2dpService service = getService(); 255 if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 256 return service.getConnectionState(device); 257 } 258 259 public boolean setPriority(BluetoothDevice device, int priority) { 260 A2dpService service = getService(); 261 if (service == null) return false; 262 return service.setPriority(device, priority); 263 } 264 265 public int getPriority(BluetoothDevice device) { 266 A2dpService service = getService(); 267 if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 268 return service.getPriority(device); 269 } 270 271 public boolean isAvrcpAbsoluteVolumeSupported() { 272 A2dpService service = getService(); 273 if (service == null) return false; 274 return service.isAvrcpAbsoluteVolumeSupported(); 275 } 276 277 public void adjustAvrcpAbsoluteVolume(int direction) { 278 A2dpService service = getService(); 279 if (service == null) return; 280 service.adjustAvrcpAbsoluteVolume(direction); 281 } 282 283 public void setAvrcpAbsoluteVolume(int volume) { 284 A2dpService service = getService(); 285 if (service == null) return; 286 service.setAvrcpAbsoluteVolume(volume); 287 } 288 289 public boolean isA2dpPlaying(BluetoothDevice device) { 290 A2dpService service = getService(); 291 if (service == null) return false; 292 return service.isA2dpPlaying(device); 293 } 294 }; 295 } 296