Update code for new BT public APIs.

Change-Id: Id730fb6226db59f3a0416111c4790653c2fccb0b
This commit is contained in:
Jaikumar Ganesh
2010-09-27 17:02:01 -07:00
parent c9cc487b7b
commit 96a79830ea
7 changed files with 275 additions and 180 deletions

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Message;
import android.bluetooth.BluetoothAdapter;
import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.util.Log;
@@ -28,6 +29,8 @@ import android.util.Log;
import com.android.internal.util.HierarchicalState;
import com.android.internal.util.HierarchicalStateMachine;
import java.util.Set;
/**
* This class is the Profile connection state machine associated with a remote
* device. When the device bonds an instance of this class is created.
@@ -91,12 +94,11 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
private BluetoothService mService;
private BluetoothA2dpService mA2dpService;
private BluetoothHeadset mHeadsetService;
private boolean mHeadsetServiceConnected;
private BluetoothDevice mDevice;
private int mHeadsetState;
private int mA2dpState;
private int mHidState;
private int mHeadsetState = BluetoothProfile.STATE_DISCONNECTED;
private int mA2dpState = BluetoothProfile.STATE_DISCONNECTED;
private int mHidState = BluetoothProfile.STATE_DISCONNECTED;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -105,32 +107,29 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (!device.equals(mDevice)) return;
if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);
int oldState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, 0);
int initiator = intent.getIntExtra(
BluetoothHeadset.EXTRA_DISCONNECT_INITIATOR,
BluetoothHeadset.LOCAL_DISCONNECT);
mHeadsetState = newState;
if (newState == BluetoothHeadset.STATE_DISCONNECTED &&
initiator == BluetoothHeadset.REMOTE_DISCONNECT) {
sendMessage(DISCONNECT_HFP_INCOMING);
}
if (newState == BluetoothHeadset.STATE_CONNECTED ||
newState == BluetoothHeadset.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
int oldState = intent.getIntExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, 0);
if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
mA2dpState = newState;
if ((oldState == BluetoothA2dp.STATE_CONNECTED ||
oldState == BluetoothA2dp.STATE_PLAYING) &&
newState == BluetoothA2dp.STATE_DISCONNECTED) {
if (oldState == BluetoothA2dp.STATE_CONNECTED &&
newState == BluetoothA2dp.STATE_DISCONNECTED) {
sendMessage(DISCONNECT_A2DP_INCOMING);
}
if (newState == BluetoothA2dp.STATE_CONNECTED ||
newState == BluetoothA2dp.STATE_DISCONNECTED) {
if (newState == BluetoothProfile.STATE_CONNECTED ||
newState == BluetoothProfile.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
mHeadsetState = newState;
if (oldState == BluetoothHeadset.STATE_CONNECTED &&
newState == BluetoothHeadset.STATE_DISCONNECTED) {
sendMessage(DISCONNECT_HFP_INCOMING);
}
if (newState == BluetoothProfile.STATE_CONNECTED ||
newState == BluetoothProfile.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
@@ -192,31 +191,31 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
IntentFilter filter = new IntentFilter();
// Fine-grained state broadcasts
filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
mContext.registerReceiver(mBroadcastReceiver, filter);
HeadsetServiceListener l = new HeadsetServiceListener();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.HEADSET);
}
private class HeadsetServiceListener implements BluetoothHeadset.ServiceListener {
public HeadsetServiceListener() {
mHeadsetService = new BluetoothHeadset(mContext, this);
}
public void onServiceConnected() {
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
synchronized(BluetoothDeviceProfileState.this) {
mHeadsetServiceConnected = true;
mHeadsetService = (BluetoothHeadset) proxy;
}
}
public void onServiceDisconnected() {
public void onServiceDisconnected(int profile) {
synchronized(BluetoothDeviceProfileState.this) {
mHeadsetServiceConnected = false;
mHeadsetService = null;
}
}
}
};
private class BondedDevice extends HierarchicalState {
@Override
@@ -276,19 +275,25 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
if (isPhoneDocked(mDevice)) {
// Don't auto connect to docks.
break;
} else if (!mHeadsetServiceConnected) {
} else if (mHeadsetService == null) {
deferMessage(message);
} else {
if (mHeadsetService.getPriority(mDevice) ==
BluetoothHeadset.PRIORITY_AUTO_CONNECT &&
!mHeadsetService.isConnected(mDevice)) {
mHeadsetService.connectHeadset(mDevice);
mHeadsetService.getDevicesMatchingConnectionStates(
new int[] {BluetoothProfile.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTING}).size() == 0) {
mHeadsetService.connect(mDevice);
}
if (mA2dpService != null &&
mA2dpService.getSinkPriority(mDevice) ==
mA2dpService.getPriority(mDevice) ==
BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
mA2dpService.getConnectedSinks().length == 0) {
mA2dpService.connectSink(mDevice);
mA2dpService.getDevicesMatchingConnectionStates(
new int[] {BluetoothA2dp.STATE_CONNECTED,
BluetoothProfile.STATE_CONNECTING,
BluetoothProfile.STATE_DISCONNECTING}).length == 0) {
mA2dpService.connect(mDevice);
}
if (mService.getInputDevicePriority(mDevice) ==
BluetoothInputDevice.PRIORITY_AUTO_CONNECT) {
@@ -805,7 +810,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
synchronized void cancelCommand(int command) {
if (command == CONNECT_HFP_OUTGOING ) {
// Cancel the outgoing thread.
if (mHeadsetServiceConnected) {
if (mHeadsetService != null) {
mHeadsetService.cancelConnectThread();
}
// HeadsetService is down. Phone process most likely crashed.
@@ -823,12 +828,14 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
log("Processing command:" + command);
switch(command) {
case CONNECT_HFP_OUTGOING:
if (mHeadsetService != null) {
if (mHeadsetService == null) {
deferHeadsetMessage(command);
} else {
return mHeadsetService.connectHeadsetInternal(mDevice);
}
break;
case CONNECT_HFP_INCOMING:
if (!mHeadsetServiceConnected) {
if (mHeadsetService == null) {
deferHeadsetMessage(command);
} else if (mHeadsetState == BluetoothHeadset.STATE_CONNECTING) {
return mHeadsetService.acceptIncomingConnect(mDevice);
@@ -849,7 +856,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
case CONNECT_HID_INCOMING:
return true;
case DISCONNECT_HFP_OUTGOING:
if (!mHeadsetServiceConnected) {
if (mHeadsetService == null) {
deferHeadsetMessage(command);
} else {
if (mHeadsetService.getPriority(mDevice) ==
@@ -867,9 +874,9 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
return true;
case DISCONNECT_A2DP_OUTGOING:
if (mA2dpService != null) {
if (mA2dpService.getSinkPriority(mDevice) ==
if (mA2dpService.getPriority(mDevice) ==
BluetoothA2dp.PRIORITY_AUTO_CONNECT) {
mA2dpService.setSinkPriority(mDevice, BluetoothHeadset.PRIORITY_ON);
mA2dpService.setPriority(mDevice, BluetoothHeadset.PRIORITY_ON);
}
return mA2dpService.disconnectSinkInternal(mDevice);
}

View File

@@ -59,16 +59,16 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, 0);
if (mProfile == HFP && (newState == BluetoothHeadset.STATE_CONNECTED ||
newState == BluetoothHeadset.STATE_DISCONNECTED)) {
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
if (mProfile == HFP && (newState == BluetoothProfile.STATE_CONNECTED ||
newState == BluetoothProfile.STATE_DISCONNECTED)) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, 0);
if (mProfile == A2DP && (newState == BluetoothA2dp.STATE_CONNECTED ||
newState == BluetoothA2dp.STATE_DISCONNECTED)) {
} else if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
if (mProfile == A2DP && (newState == BluetoothProfile.STATE_CONNECTED ||
newState == BluetoothProfile.STATE_DISCONNECTED)) {
sendMessage(TRANSITION_TO_STABLE);
}
} else if (action.equals(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED)) {
@@ -89,8 +89,8 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
setInitialState(mStableState);
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
}

View File

@@ -19,21 +19,25 @@ package android.bluetooth;
import android.bluetooth.BluetoothDevice;
/**
* System private API for Bluetooth A2DP service
* APIs for Bluetooth A2DP service
*
* {@hide}
* @hide
*/
interface IBluetoothA2dp {
boolean connectSink(in BluetoothDevice device);
boolean disconnectSink(in BluetoothDevice device);
// Public API
boolean connect(in BluetoothDevice device);
boolean disconnect(in BluetoothDevice device);
// change to Set<> once AIDL supports
BluetoothDevice[] getConnectedDevices();
BluetoothDevice[] getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
boolean setPriority(in BluetoothDevice device, int priority);
int getPriority(in BluetoothDevice device);
boolean isA2dpPlaying(in BluetoothDevice device);
// Internal APIs
boolean suspendSink(in BluetoothDevice device);
boolean resumeSink(in BluetoothDevice device);
BluetoothDevice[] getConnectedSinks(); // change to Set<> once AIDL supports
BluetoothDevice[] getNonDisconnectedSinks(); // change to Set<> once AIDL supports
int getSinkState(in BluetoothDevice device);
boolean setSinkPriority(in BluetoothDevice device, int priority);
int getSinkPriority(in BluetoothDevice device);
boolean connectSinkInternal(in BluetoothDevice device);
boolean disconnectSinkInternal(in BluetoothDevice device);
}

View File

@@ -19,25 +19,32 @@ package android.bluetooth;
import android.bluetooth.BluetoothDevice;
/**
* System private API for Bluetooth Headset service
* API for Bluetooth Headset service
*
* {@hide}
*/
interface IBluetoothHeadset {
int getState(in BluetoothDevice device);
BluetoothDevice getCurrentHeadset();
boolean connectHeadset(in BluetoothDevice device);
void disconnectHeadset(in BluetoothDevice device);
boolean isConnected(in BluetoothDevice device);
boolean startVoiceRecognition();
boolean stopVoiceRecognition();
// Public API
boolean connect(in BluetoothDevice device);
boolean disconnect(in BluetoothDevice device);
// Change to Set<> when AIDL supports
BluetoothDevice[] getConnectedDevices();
BluetoothDevice[] getDevicesMatchingConnectionStates(in int[] states);
int getConnectionState(in BluetoothDevice device);
boolean setPriority(in BluetoothDevice device, int priority);
int getPriority(in BluetoothDevice device);
int getBatteryUsageHint();
boolean startVoiceRecognition(in BluetoothDevice device);
boolean stopVoiceRecognition(in BluetoothDevice device);
boolean isAudioConnected(in BluetoothDevice device);
// APIs that can be made public in future
int getBatteryUsageHint(in BluetoothDevice device);
// Internal functions, not be made public
boolean createIncomingConnect(in BluetoothDevice device);
boolean acceptIncomingConnect(in BluetoothDevice device);
boolean cancelConnectThread();
boolean connectHeadsetInternal(in BluetoothDevice device);
boolean disconnectHeadsetInternal(in BluetoothDevice device);
boolean setAudioState(in BluetoothDevice device, int state);
}

View File

@@ -25,6 +25,7 @@ package android.server;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothA2dp;
import android.content.BroadcastReceiver;
@@ -32,17 +33,15 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
import android.provider.Settings;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String TAG = "BluetoothA2dpService";
@@ -57,11 +56,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private static final String PROPERTY_STATE = "State";
private static final String SINK_STATE_DISCONNECTED = "disconnected";
private static final String SINK_STATE_CONNECTING = "connecting";
private static final String SINK_STATE_CONNECTED = "connected";
private static final String SINK_STATE_PLAYING = "playing";
private static int mSinkCount;
private final Context mContext;
@@ -72,6 +66,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private final BluetoothAdapter mAdapter;
private int mTargetA2dpState;
private boolean mAdjustedPriority = false;
private BluetoothDevice mPlayingA2dpDevice;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -95,12 +90,12 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothDevice.ERROR);
switch(bondState) {
case BluetoothDevice.BOND_BONDED:
if (getSinkPriority(device) == BluetoothA2dp.PRIORITY_UNDEFINED) {
setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
if (getPriority(device) == BluetoothA2dp.PRIORITY_UNDEFINED) {
setPriority(device, BluetoothA2dp.PRIORITY_ON);
}
break;
case BluetoothDevice.BOND_NONE:
setSinkPriority(device, BluetoothA2dp.PRIORITY_UNDEFINED);
setPriority(device, BluetoothA2dp.PRIORITY_UNDEFINED);
break;
}
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
@@ -113,7 +108,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
} else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
if (streamType == AudioManager.STREAM_MUSIC) {
BluetoothDevice sinks[] = getConnectedSinks();
BluetoothDevice sinks[] = getConnectedDevices();
if (sinks.length != 0 && isPhoneDocked(sinks[0])) {
String address = sinks[0].getAddress();
int newVolLevel =
@@ -254,7 +250,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
BluetoothDevice[] devices = new BluetoothDevice[mAudioDevices.size()];
devices = mAudioDevices.keySet().toArray(devices);
for (BluetoothDevice device : devices) {
int state = getSinkState(device);
int state = getConnectionState(device);
switch (state) {
case BluetoothA2dp.STATE_CONNECTING:
case BluetoothA2dp.STATE_CONNECTED:
@@ -277,7 +273,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
private synchronized boolean isConnectSinkFeasible(BluetoothDevice device) {
if (!mBluetoothService.isEnabled() || !isSinkDevice(device) ||
getSinkPriority(device) == BluetoothA2dp.PRIORITY_OFF) {
getPriority(device) == BluetoothA2dp.PRIORITY_OFF) {
return false;
}
@@ -292,12 +288,26 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return true;
}
public synchronized boolean connectSink(BluetoothDevice device) {
public synchronized boolean isA2dpPlaying(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
if (DBG) log("isA2dpPlaying(" + device + ")");
if (device.equals(mPlayingA2dpDevice)) return true;
return false;
}
public synchronized boolean connect(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
if (DBG) log("connectSink(" + device + ")");
if (!isConnectSinkFeasible(device)) return false;
for (BluetoothDevice sinkDevice : mAudioDevices.keySet()) {
if (getConnectionState(sinkDevice) != BluetoothProfile.STATE_DISCONNECTED) {
disconnect(sinkDevice);
}
}
return mBluetoothService.connectSink(device.getAddress());
}
@@ -307,17 +317,15 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
int state = mAudioDevices.get(device);
// ignore if there are any active sinks
if (lookupSinksMatchingStates(new int[] {
if (getDevicesMatchingConnectionStates(new int[] {
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_CONNECTED,
BluetoothA2dp.STATE_PLAYING,
BluetoothA2dp.STATE_DISCONNECTING}).size() != 0) {
BluetoothA2dp.STATE_DISCONNECTING}).length != 0) {
return false;
}
switch (state) {
case BluetoothA2dp.STATE_CONNECTED:
case BluetoothA2dp.STATE_PLAYING:
case BluetoothA2dp.STATE_DISCONNECTING:
return false;
case BluetoothA2dp.STATE_CONNECTING:
@@ -343,17 +351,16 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return false;
}
int state = getSinkState(device);
int state = getConnectionState(device);
switch (state) {
case BluetoothA2dp.STATE_DISCONNECTED:
return false;
case BluetoothA2dp.STATE_DISCONNECTING:
return true;
return false;
}
return true;
}
public synchronized boolean disconnectSink(BluetoothDevice device) {
public synchronized boolean disconnect(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
if (DBG) log("disconnectSink(" + device + ")");
@@ -362,7 +369,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
}
public synchronized boolean disconnectSinkInternal(BluetoothDevice device) {
int state = getSinkState(device);
int state = getConnectionState(device);
String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
// State is CONNECTING or CONNECTED or PLAYING
@@ -408,24 +415,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return checkSinkSuspendState(state.intValue());
}
public synchronized BluetoothDevice[] getConnectedSinks() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
new int[] {BluetoothA2dp.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING});
return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
public synchronized BluetoothDevice[] getNonDisconnectedSinks() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
Set<BluetoothDevice> sinks = lookupSinksMatchingStates(
new int[] {BluetoothA2dp.STATE_CONNECTED,
BluetoothA2dp.STATE_PLAYING,
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_DISCONNECTING});
return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
public synchronized int getSinkState(BluetoothDevice device) {
public synchronized int getConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
Integer state = mAudioDevices.get(device);
if (state == null)
@@ -433,19 +423,41 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
return state;
}
public synchronized int getSinkPriority(BluetoothDevice device) {
public synchronized BluetoothDevice[] getConnectedDevices() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
BluetoothDevice[] sinks = getDevicesMatchingConnectionStates(
new int[] {BluetoothA2dp.STATE_CONNECTED});
return sinks;
}
public synchronized BluetoothDevice[] getDevicesMatchingConnectionStates(int[] states) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
ArrayList<BluetoothDevice> sinks = new ArrayList();
if (mAudioDevices.isEmpty()) {
return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
for (BluetoothDevice device: mAudioDevices.keySet()) {
int sinkState = getConnectionState(device);
for (int state : states) {
if (state == sinkState) {
sinks.add(device);
break;
}
}
}
return sinks.toArray(new BluetoothDevice[sinks.size()]);
}
public synchronized int getPriority(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()),
BluetoothA2dp.PRIORITY_UNDEFINED);
}
public synchronized boolean setSinkPriority(BluetoothDevice device, int priority) {
public synchronized boolean setPriority(BluetoothDevice device, int priority) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
return false;
}
return Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority);
}
@@ -471,8 +483,17 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
// We have authorized it and bluez state has changed.
addAudioSink(device);
} else {
int prevState = mAudioDevices.get(device);
handleSinkStateChange(device, prevState, state);
if (state == BluetoothA2dp.STATE_PLAYING && mPlayingA2dpDevice == null) {
mPlayingA2dpDevice = device;
handleSinkPlayingStateChange(device, state, BluetoothA2dp.STATE_NOT_PLAYING);
} else if (state == BluetoothA2dp.STATE_CONNECTED && mPlayingA2dpDevice != null) {
mPlayingA2dpDevice = null;
handleSinkPlayingStateChange(device, BluetoothA2dp.STATE_NOT_PLAYING,
BluetoothA2dp.STATE_PLAYING);
} else {
int prevState = mAudioDevices.get(device);
handleSinkStateChange(device, prevState, state);
}
}
}
}
@@ -484,18 +505,19 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
mSinkCount--;
} else if (state == BluetoothA2dp.STATE_CONNECTED) {
mSinkCount ++;
mPlayingA2dpDevice = null;
}
mAudioDevices.put(device, state);
checkSinkSuspendState(state);
mTargetA2dpState = -1;
if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
if (getPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
state == BluetoothA2dp.STATE_CONNECTING ||
state == BluetoothA2dp.STATE_CONNECTED) {
// We have connected or attempting to connect.
// Bump priority
setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO_CONNECT);
setPriority(device, BluetoothA2dp.PRIORITY_AUTO_CONNECT);
}
if (state == BluetoothA2dp.STATE_CONNECTED) {
@@ -504,45 +526,38 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
adjustOtherSinkPriorities(device);
}
Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, prevState);
intent.putExtra(BluetoothA2dp.EXTRA_SINK_STATE, state);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
}
}
private void handleSinkPlayingStateChange(BluetoothDevice device, int state, int prevState) {
Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
if (DBG) log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state);
}
private void adjustOtherSinkPriorities(BluetoothDevice connectedDevice) {
if (!mAdjustedPriority) {
for (BluetoothDevice device : mAdapter.getBondedDevices()) {
if (getSinkPriority(device) >= BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
if (getPriority(device) >= BluetoothA2dp.PRIORITY_AUTO_CONNECT &&
!device.equals(connectedDevice)) {
setSinkPriority(device, BluetoothA2dp.PRIORITY_ON);
setPriority(device, BluetoothA2dp.PRIORITY_ON);
}
}
mAdjustedPriority = true;
}
}
private synchronized Set<BluetoothDevice> lookupSinksMatchingStates(int[] states) {
Set<BluetoothDevice> sinks = new HashSet<BluetoothDevice>();
if (mAudioDevices.isEmpty()) {
return sinks;
}
for (BluetoothDevice device: mAudioDevices.keySet()) {
int sinkState = getSinkState(device);
for (int state : states) {
if (state == sinkState) {
sinks.add(device);
break;
}
}
}
return sinks;
}
private boolean checkSinkSuspendState(int state) {
boolean result = true;
@@ -568,7 +583,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
if (address == null) return;
BluetoothDevice device = mAdapter.getRemoteDevice(address);
int state = getSinkState(device);
int state = getConnectionState(device);
handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
}
}

View File

@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.content.Intent;
@@ -54,6 +55,7 @@ class BluetoothEventLoop {
private final HashMap<String, Integer> mPasskeyAgentRequestData;
private final BluetoothService mBluetoothService;
private final BluetoothAdapter mAdapter;
private BluetoothA2dp mA2dp;
private final Context mContext;
// The WakeLock is used for bringing up the LCD during a pairing request
// from remote device when Android is in Suspend state.
@@ -118,8 +120,21 @@ class BluetoothEventLoop {
| PowerManager.ON_AFTER_RELEASE, TAG);
mWakeLock.setReferenceCounted(false);
initializeNativeDataNative();
mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
}
private BluetoothProfile.ServiceListener mProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
mA2dp = (BluetoothA2dp) proxy;
}
public void onServiceDisconnected(int profile) {
mA2dp = null;
}
};
protected void finalize() throws Throwable {
try {
cleanupNativeDataNative();
@@ -574,12 +589,11 @@ class BluetoothEventLoop {
// Bluez sends the UUID of the local service being accessed, _not_ the
// remote service
if ((BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
if (mA2dp != null &&
(BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
|| BluetoothUuid.isAdvAudioDist(uuid)) &&
!isOtherSinkInNonDisconnectingState(address)) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
!isOtherSinkInNonDisconnectedState(address)) {
authorized = mA2dp.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
if (authorized) {
Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
mBluetoothService.notifyIncomingA2dpConnection(address);
@@ -630,9 +644,12 @@ class BluetoothEventLoop {
return false;
}
private boolean isOtherSinkInNonDisconnectingState(String address) {
BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
Set<BluetoothDevice> devices = a2dp.getNonDisconnectedSinks();
private boolean isOtherSinkInNonDisconnectedState(String address) {
Set<BluetoothDevice> devices =
mA2dp.getDevicesMatchingConnectionStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
BluetoothA2dp.STATE_CONNECTING,
BluetoothA2dp.STATE_DISCONNECTING});
if (devices.size() == 0) return false;
for(BluetoothDevice dev: devices) {
if (!dev.getAddress().equals(address)) return true;

View File

@@ -30,6 +30,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothDeviceProfileState;
import android.bluetooth.BluetoothPan;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfileState;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.BluetoothSocket;
@@ -88,6 +89,7 @@ public class BluetoothService extends IBluetooth.Stub {
private int mNativeData;
private BluetoothEventLoop mEventLoop;
private BluetoothHeadset mBluetoothHeadset;
private boolean mIsAirplaneSensitive;
private boolean mIsAirplaneToggleable;
private int mBluetoothState;
@@ -2434,7 +2436,8 @@ public class BluetoothService extends IBluetooth.Stub {
pw.println("Local name = " + getName());
pw.println("isDiscovering() = " + isDiscovering());
BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
mAdapter.getProfileProxy(mContext,
mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
pw.println("\n--Known devices--");
for (String address : mDeviceProperties.keySet()) {
@@ -2479,24 +2482,48 @@ public class BluetoothService extends IBluetooth.Stub {
// Rather not do this from here, but no-where else and I need this
// dump
pw.println("\n--Headset Service--");
switch (headset.getState(headset.getCurrentHeadset())) {
case BluetoothHeadset.STATE_DISCONNECTED:
pw.println("getState() = STATE_DISCONNECTED");
break;
case BluetoothHeadset.STATE_CONNECTING:
pw.println("getState() = STATE_CONNECTING");
break;
case BluetoothHeadset.STATE_CONNECTED:
pw.println("getState() = STATE_CONNECTED");
break;
case BluetoothHeadset.STATE_ERROR:
pw.println("getState() = STATE_ERROR");
break;
if (mBluetoothHeadset != null) {
Set<BluetoothDevice> deviceSet = mBluetoothHeadset.getConnectedDevices();
if (deviceSet.size() == 0) {
pw.println("\n--No headsets connected--");
}
BluetoothDevice device = (BluetoothDevice) deviceSet.toArray()[0];
switch (mBluetoothHeadset.getConnectionState(device)) {
case BluetoothHeadset.STATE_DISCONNECTED:
pw.println("getConnectionState() = STATE_DISCONNECTED");
break;
case BluetoothHeadset.STATE_CONNECTING:
pw.println("getConnectionState() = STATE_CONNECTING");
break;
case BluetoothHeadset.STATE_CONNECTED:
pw.println("getConnectionState() = STATE_CONNECTED");
break;
case BluetoothHeadset.STATE_DISCONNECTING:
pw.println("getConnectionState() = STATE_DISCONNECTING");
break;
case BluetoothHeadset.STATE_AUDIO_CONNECTED:
pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
break;
}
deviceSet.clear();
deviceSet = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
pw.println("\n--Connected and Disconnected Headsets");
for (BluetoothDevice dev: deviceSet) {
pw.println(device);
if (mBluetoothHeadset.isAudioConnected(device)) {
pw.println("SCO audio connected to device:" + device);
}
}
pw.println("\ngetCurrentHeadset() = " + device);
pw.println("getBatteryUsageHint() = " +
mBluetoothHeadset.getBatteryUsageHint(device));
mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
}
pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
headset.close();
pw.println("\n--Application Service Records--");
for (Integer handle : mServiceRecordToPid.keySet()) {
Integer pid = mServiceRecordToPid.get(handle);
@@ -2504,6 +2531,16 @@ public class BluetoothService extends IBluetooth.Stub {
}
}
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
}
public void onServiceDisconnected(int profile) {
mBluetoothHeadset = null;
}
};
/* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
if (pairable && discoverable)
return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
@@ -2563,6 +2600,8 @@ public class BluetoothService extends IBluetooth.Stub {
}
public boolean connectHeadset(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
@@ -2575,6 +2614,8 @@ public class BluetoothService extends IBluetooth.Stub {
}
public boolean disconnectHeadset(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
@@ -2587,6 +2628,8 @@ public class BluetoothService extends IBluetooth.Stub {
}
public boolean connectSink(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
@@ -2599,6 +2642,8 @@ public class BluetoothService extends IBluetooth.Stub {
}
public boolean disconnectSink(String address) {
if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();