/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.a2dp; import android.bluetooth.BluetoothAudioConfig; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetoothA2dpSink; import android.util.Log; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.Utils; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Provides Bluetooth A2DP Sink profile, as a service in the Bluetooth application. * @hide */ public class A2dpSinkService extends ProfileService { private static final boolean DBG = false; private static final String TAG = "A2dpSinkService"; private A2dpSinkStateMachine mStateMachine; private static A2dpSinkService sA2dpSinkService; protected String getName() { return TAG; } protected IProfileServiceBinder initBinder() { return new BluetoothA2dpSinkBinder(this); } protected boolean start() { mStateMachine = A2dpSinkStateMachine.make(this, this); setA2dpSinkService(this); return true; } protected boolean stop() { mStateMachine.doQuit(); return true; } protected boolean cleanup() { if (mStateMachine!= null) { mStateMachine.cleanup(); } clearA2dpSinkService(); return true; } //API Methods public static synchronized A2dpSinkService getA2dpSinkService(){ if (sA2dpSinkService != null && sA2dpSinkService.isAvailable()) { if (DBG) Log.d(TAG, "getA2dpSinkService(): returning " + sA2dpSinkService); return sA2dpSinkService; } if (DBG) { if (sA2dpSinkService == null) { Log.d(TAG, "getA2dpSinkService(): service is NULL"); } else if (!(sA2dpSinkService.isAvailable())) { Log.d(TAG,"getA2dpSinkService(): service is not available"); } } return null; } private static synchronized void setA2dpSinkService(A2dpSinkService instance) { if (instance != null && instance.isAvailable()) { if (DBG) Log.d(TAG, "setA2dpSinkService(): set to: " + sA2dpSinkService); sA2dpSinkService = instance; } else { if (DBG) { if (sA2dpSinkService == null) { Log.d(TAG, "setA2dpSinkService(): service not available"); } else if (!sA2dpSinkService.isAvailable()) { Log.d(TAG,"setA2dpSinkService(): service is cleaning up"); } } } } private static synchronized void clearA2dpSinkService() { sA2dpSinkService = null; } public boolean connect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState == BluetoothProfile.STATE_CONNECTED || connectionState == BluetoothProfile.STATE_CONNECTING) { return false; } mStateMachine.sendMessage(A2dpSinkStateMachine.CONNECT, device); return true; } boolean disconnect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; } mStateMachine.sendMessage(A2dpSinkStateMachine.DISCONNECT, device); return true; } public List getConnectedDevices() { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getConnectedDevices(); } List getDevicesMatchingConnectionStates(int[] states) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getDevicesMatchingConnectionStates(states); } int getConnectionState(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getConnectionState(device); } BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); return mStateMachine.getAudioConfig(device); } //Binder object: Must be static class or memory leak may occur private static class BluetoothA2dpSinkBinder extends IBluetoothA2dpSink.Stub implements IProfileServiceBinder { private A2dpSinkService mService; private A2dpSinkService getService() { if (!Utils.checkCaller()) { Log.w(TAG,"A2dp call not allowed for non-active user"); return null; } if (mService != null && mService.isAvailable()) { return mService; } return null; } BluetoothA2dpSinkBinder(A2dpSinkService svc) { mService = svc; } public boolean cleanup() { mService = null; return true; } public boolean connect(BluetoothDevice device) { A2dpSinkService service = getService(); if (service == null) return false; return service.connect(device); } public boolean disconnect(BluetoothDevice device) { A2dpSinkService service = getService(); if (service == null) return false; return service.disconnect(device); } public List getConnectedDevices() { A2dpSinkService service = getService(); if (service == null) return new ArrayList(0); return service.getConnectedDevices(); } public List getDevicesMatchingConnectionStates(int[] states) { A2dpSinkService service = getService(); if (service == null) return new ArrayList(0); return service.getDevicesMatchingConnectionStates(states); } public int getConnectionState(BluetoothDevice device) { A2dpSinkService service = getService(); if (service == null) return BluetoothProfile.STATE_DISCONNECTED; return service.getConnectionState(device); } public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) { A2dpSinkService service = getService(); if (service == null) return null; return service.getAudioConfig(device); } }; }