| /* |
| * Copyright (C) 2012 Google Inc. |
| */ |
| package com.android.bluetooth.a2dp; |
| |
| import android.bluetooth.BluetoothDevice; |
| import android.bluetooth.BluetoothProfile; |
| import android.bluetooth.IBluetoothA2dp; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.provider.Settings; |
| import android.util.Log; |
| import com.android.bluetooth.btservice.ProfileService; |
| import com.android.bluetooth.Utils; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Provides Bluetooth A2DP profile, as a service in the Bluetooth application. |
| * @hide |
| */ |
| public class A2dpService extends ProfileService { |
| private static final boolean DBG = true; |
| private static final String TAG="A2dpService"; |
| |
| private A2dpStateMachine mStateMachine; |
| private static A2dpService sAd2dpService; |
| |
| protected String getName() { |
| return TAG; |
| } |
| |
| protected IProfileServiceBinder initBinder() { |
| return new BluetoothA2dpBinder(this); |
| } |
| |
| protected boolean start() { |
| mStateMachine = A2dpStateMachine.make(this, this); |
| setA2dpService(this); |
| return true; |
| } |
| |
| protected boolean stop() { |
| mStateMachine.doQuit(); |
| return true; |
| } |
| |
| protected boolean cleanup() { |
| if (mStateMachine!= null) { |
| mStateMachine.cleanup(); |
| } |
| clearA2dpService(); |
| return true; |
| } |
| |
| //API Methods |
| |
| public static synchronized A2dpService getA2dpService(){ |
| if (sAd2dpService != null && sAd2dpService.isAvailable()) { |
| if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService); |
| return sAd2dpService; |
| } |
| if (DBG) { |
| if (sAd2dpService == null) { |
| Log.d(TAG, "getA2dpService(): service is NULL"); |
| } else if (!(sAd2dpService.isAvailable())) { |
| Log.d(TAG,"getA2dpService(): service is not available"); |
| } |
| } |
| return null; |
| } |
| |
| private static synchronized void setA2dpService(A2dpService instance) { |
| if (instance != null && instance.isAvailable()) { |
| if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService); |
| sAd2dpService = instance; |
| } else { |
| if (DBG) { |
| if (sAd2dpService == null) { |
| Log.d(TAG, "setA2dpService(): service not available"); |
| } else if (!sAd2dpService.isAvailable()) { |
| Log.d(TAG,"setA2dpService(): service is cleaning up"); |
| } |
| } |
| } |
| } |
| |
| private static synchronized void clearA2dpService() { |
| sAd2dpService = null; |
| } |
| |
| public boolean connect(BluetoothDevice device) { |
| enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, |
| "Need BLUETOOTH ADMIN permission"); |
| |
| if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { |
| return false; |
| } |
| |
| int connectionState = mStateMachine.getConnectionState(device); |
| if (connectionState == BluetoothProfile.STATE_CONNECTED || |
| connectionState == BluetoothProfile.STATE_CONNECTING) { |
| return false; |
| } |
| |
| mStateMachine.sendMessage(A2dpStateMachine.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(A2dpStateMachine.DISCONNECT, device); |
| return true; |
| } |
| |
| public List<BluetoothDevice> getConnectedDevices() { |
| enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); |
| return mStateMachine.getConnectedDevices(); |
| } |
| |
| List<BluetoothDevice> 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); |
| } |
| |
| public boolean setPriority(BluetoothDevice device, int priority) { |
| enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, |
| "Need BLUETOOTH_ADMIN permission"); |
| Settings.Global.putInt(getContentResolver(), |
| Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), |
| priority); |
| if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority); |
| return true; |
| } |
| |
| public int getPriority(BluetoothDevice device) { |
| enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, |
| "Need BLUETOOTH_ADMIN permission"); |
| int priority = Settings.Global.getInt(getContentResolver(), |
| Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), |
| BluetoothProfile.PRIORITY_UNDEFINED); |
| return priority; |
| } |
| |
| synchronized boolean isA2dpPlaying(BluetoothDevice device) { |
| enforceCallingOrSelfPermission(BLUETOOTH_PERM, |
| "Need BLUETOOTH permission"); |
| if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")"); |
| return mStateMachine.isPlaying(device); |
| } |
| |
| //Binder object: Must be static class or memory leak may occur |
| private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub |
| implements IProfileServiceBinder { |
| private A2dpService mService; |
| |
| private A2dpService 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; |
| } |
| |
| BluetoothA2dpBinder(A2dpService svc) { |
| mService = svc; |
| } |
| |
| public boolean cleanup() { |
| mService = null; |
| return true; |
| } |
| |
| public boolean connect(BluetoothDevice device) { |
| A2dpService service = getService(); |
| if (service == null) return false; |
| return service.connect(device); |
| } |
| |
| public boolean disconnect(BluetoothDevice device) { |
| A2dpService service = getService(); |
| if (service == null) return false; |
| return service.disconnect(device); |
| } |
| |
| public List<BluetoothDevice> getConnectedDevices() { |
| A2dpService service = getService(); |
| if (service == null) return new ArrayList<BluetoothDevice>(0); |
| return service.getConnectedDevices(); |
| } |
| |
| public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { |
| A2dpService service = getService(); |
| if (service == null) return new ArrayList<BluetoothDevice>(0); |
| return service.getDevicesMatchingConnectionStates(states); |
| } |
| |
| public int getConnectionState(BluetoothDevice device) { |
| A2dpService service = getService(); |
| if (service == null) return BluetoothProfile.STATE_DISCONNECTED; |
| return service.getConnectionState(device); |
| } |
| |
| public boolean setPriority(BluetoothDevice device, int priority) { |
| A2dpService service = getService(); |
| if (service == null) return false; |
| return service.setPriority(device, priority); |
| } |
| |
| public int getPriority(BluetoothDevice device) { |
| A2dpService service = getService(); |
| if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; |
| return service.getPriority(device); |
| } |
| |
| public boolean isA2dpPlaying(BluetoothDevice device) { |
| A2dpService service = getService(); |
| if (service == null) return false; |
| return service.isA2dpPlaying(device); |
| } |
| }; |
| } |