1 /* 2 * Copyright (C) 2014 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.BluetoothAudioConfig; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothProfile; 22 import android.bluetooth.IBluetoothA2dpSink; 23 import android.util.Log; 24 import com.android.bluetooth.btservice.ProfileService; 25 import com.android.bluetooth.Utils; 26 import java.util.ArrayList; 27 import java.util.List; 28 import java.util.Map; 29 30 /** 31 * Provides Bluetooth A2DP Sink profile, as a service in the Bluetooth application. 32 * @hide 33 */ 34 public class A2dpSinkService extends ProfileService { 35 private static final boolean DBG = false; 36 private static final String TAG = "A2dpSinkService"; 37 38 private A2dpSinkStateMachine mStateMachine; 39 private static A2dpSinkService sA2dpSinkService; 40 getName()41 protected String getName() { 42 return TAG; 43 } 44 initBinder()45 protected IProfileServiceBinder initBinder() { 46 return new BluetoothA2dpSinkBinder(this); 47 } 48 start()49 protected boolean start() { 50 mStateMachine = A2dpSinkStateMachine.make(this, this); 51 setA2dpSinkService(this); 52 return true; 53 } 54 stop()55 protected boolean stop() { 56 mStateMachine.doQuit(); 57 return true; 58 } 59 cleanup()60 protected boolean cleanup() { 61 if (mStateMachine!= null) { 62 mStateMachine.cleanup(); 63 } 64 clearA2dpSinkService(); 65 return true; 66 } 67 68 //API Methods 69 getA2dpSinkService()70 public static synchronized A2dpSinkService getA2dpSinkService(){ 71 if (sA2dpSinkService != null && sA2dpSinkService.isAvailable()) { 72 if (DBG) Log.d(TAG, "getA2dpSinkService(): returning " + sA2dpSinkService); 73 return sA2dpSinkService; 74 } 75 if (DBG) { 76 if (sA2dpSinkService == null) { 77 Log.d(TAG, "getA2dpSinkService(): service is NULL"); 78 } else if (!(sA2dpSinkService.isAvailable())) { 79 Log.d(TAG,"getA2dpSinkService(): service is not available"); 80 } 81 } 82 return null; 83 } 84 setA2dpSinkService(A2dpSinkService instance)85 private static synchronized void setA2dpSinkService(A2dpSinkService instance) { 86 if (instance != null && instance.isAvailable()) { 87 if (DBG) Log.d(TAG, "setA2dpSinkService(): set to: " + sA2dpSinkService); 88 sA2dpSinkService = instance; 89 } else { 90 if (DBG) { 91 if (sA2dpSinkService == null) { 92 Log.d(TAG, "setA2dpSinkService(): service not available"); 93 } else if (!sA2dpSinkService.isAvailable()) { 94 Log.d(TAG,"setA2dpSinkService(): service is cleaning up"); 95 } 96 } 97 } 98 } 99 clearA2dpSinkService()100 private static synchronized void clearA2dpSinkService() { 101 sA2dpSinkService = null; 102 } 103 connect(BluetoothDevice device)104 public boolean connect(BluetoothDevice device) { 105 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 106 "Need BLUETOOTH ADMIN permission"); 107 108 int connectionState = mStateMachine.getConnectionState(device); 109 if (connectionState == BluetoothProfile.STATE_CONNECTED || 110 connectionState == BluetoothProfile.STATE_CONNECTING) { 111 return false; 112 } 113 114 mStateMachine.sendMessage(A2dpSinkStateMachine.CONNECT, device); 115 return true; 116 } 117 disconnect(BluetoothDevice device)118 boolean disconnect(BluetoothDevice device) { 119 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 120 "Need BLUETOOTH ADMIN permission"); 121 int connectionState = mStateMachine.getConnectionState(device); 122 if (connectionState != BluetoothProfile.STATE_CONNECTED && 123 connectionState != BluetoothProfile.STATE_CONNECTING) { 124 return false; 125 } 126 127 mStateMachine.sendMessage(A2dpSinkStateMachine.DISCONNECT, device); 128 return true; 129 } 130 getConnectedDevices()131 public List<BluetoothDevice> getConnectedDevices() { 132 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 133 return mStateMachine.getConnectedDevices(); 134 } 135 getDevicesMatchingConnectionStates(int[] states)136 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 137 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 138 return mStateMachine.getDevicesMatchingConnectionStates(states); 139 } 140 getConnectionState(BluetoothDevice device)141 int getConnectionState(BluetoothDevice device) { 142 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 143 return mStateMachine.getConnectionState(device); 144 } 145 getAudioConfig(BluetoothDevice device)146 BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { 147 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 148 return mStateMachine.getAudioConfig(device); 149 } 150 151 //Binder object: Must be static class or memory leak may occur 152 private static class BluetoothA2dpSinkBinder extends IBluetoothA2dpSink.Stub 153 implements IProfileServiceBinder { 154 private A2dpSinkService mService; 155 getService()156 private A2dpSinkService getService() { 157 if (!Utils.checkCaller()) { 158 Log.w(TAG,"A2dp call not allowed for non-active user"); 159 return null; 160 } 161 162 if (mService != null && mService.isAvailable()) { 163 return mService; 164 } 165 return null; 166 } 167 BluetoothA2dpSinkBinder(A2dpSinkService svc)168 BluetoothA2dpSinkBinder(A2dpSinkService svc) { 169 mService = svc; 170 } 171 cleanup()172 public boolean cleanup() { 173 mService = null; 174 return true; 175 } 176 connect(BluetoothDevice device)177 public boolean connect(BluetoothDevice device) { 178 A2dpSinkService service = getService(); 179 if (service == null) return false; 180 return service.connect(device); 181 } 182 disconnect(BluetoothDevice device)183 public boolean disconnect(BluetoothDevice device) { 184 A2dpSinkService service = getService(); 185 if (service == null) return false; 186 return service.disconnect(device); 187 } 188 getConnectedDevices()189 public List<BluetoothDevice> getConnectedDevices() { 190 A2dpSinkService service = getService(); 191 if (service == null) return new ArrayList<BluetoothDevice>(0); 192 return service.getConnectedDevices(); 193 } 194 getDevicesMatchingConnectionStates(int[] states)195 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 196 A2dpSinkService service = getService(); 197 if (service == null) return new ArrayList<BluetoothDevice>(0); 198 return service.getDevicesMatchingConnectionStates(states); 199 } 200 getConnectionState(BluetoothDevice device)201 public int getConnectionState(BluetoothDevice device) { 202 A2dpSinkService service = getService(); 203 if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 204 return service.getConnectionState(device); 205 } 206 getAudioConfig(BluetoothDevice device)207 public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { 208 A2dpSinkService service = getService(); 209 if (service == null) return null; 210 return service.getAudioConfig(device); 211 } 212 }; 213 214 @Override dump(StringBuilder sb)215 public void dump(StringBuilder sb) { 216 super.dump(sb); 217 if (mStateMachine != null) { 218 mStateMachine.dump(sb); 219 } 220 } 221 } 222