diff options
8 files changed, 134 insertions, 18 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 28bc424d937d..264db1917d1d 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -774,6 +774,31 @@ public final class BluetoothAdapter { } /** + * Get the current connection state of a profile. + * This function can be used to check whether the local Bluetooth adapter + * is connected to any remote device for a specific profile. + * Profile can be one of {@link BluetoothProfile.HEADSET}, + * {@link BluetoothProfile.A2DP}. + * + * <p>Requires {@link android.Manifest.permission#BLUETOOTH}. + * + * <p> Return value can be one of + * {@link * BluetoothProfile.STATE_DISCONNECTED}, + * {@link * BluetoothProfile.STATE_CONNECTING}, + * {@link * BluetoothProfile.STATE_CONNECTED}, + * {@link * BluetoothProfile.STATE_DISCONNECTING} + * @hide + */ + public int getProfileConnectionState(int profile) { + if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED; + try { + return mService.getProfileConnectionState(profile); + } catch (RemoteException e) {Log.e(TAG, "getProfileConnectionState:", e);} + return BluetoothProfile.STATE_DISCONNECTED; + } + + /** + /** * Picks RFCOMM channels until none are left. * Avoids reserved channels. */ diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 6cd81fde7225..58b386838799 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -83,6 +83,12 @@ public interface BluetoothProfile { public static final int PAN = 5; /** + * PBAP + * @hide + */ + public static final int PBAP = 6; + + /** * Default priority for devices that we try to auto-connect to and * and allow incoming connections for the profile * @hide diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index 48dfed82caad..d4e7f7d48ede 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -53,6 +53,7 @@ interface IBluetooth byte[] readOutOfBandData(); int getAdapterConnectionState(); + int getProfileConnectionState(int profile); boolean changeApplicationBluetoothState(boolean on, in IBluetoothStateChangeCallback callback, in IBinder b); @@ -121,5 +122,5 @@ interface IBluetooth List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states); int getHealthDeviceConnectionState(in BluetoothDevice device); - void sendConnectionStateChange(in BluetoothDevice device, int state, int prevState); + void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState); } diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 8c04853535d6..c4cb3a5f4155 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -523,7 +523,8 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state); - mBluetoothService.sendConnectionStateChange(device, state, prevState); + mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.A2DP, state, + prevState); } } diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java index 105ff332ed04..eafd7bd35a5d 100644 --- a/core/java/android/server/BluetoothHealthProfileHandler.java +++ b/core/java/android/server/BluetoothHealthProfileHandler.java @@ -20,6 +20,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHealth; import android.bluetooth.BluetoothHealthAppConfiguration; +import android.bluetooth.BluetoothProfile; import android.bluetooth.IBluetoothHealthCallback; import android.content.Context; import android.os.Handler; @@ -567,7 +568,8 @@ final class BluetoothHealthProfileHandler { private void updateAndSendIntent(BluetoothDevice device, int prevDeviceState, int newDeviceState) { mHealthDevices.put(device, newDeviceState); - mBluetoothService.sendConnectionStateChange(device, prevDeviceState, newDeviceState); + mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.HEALTH, + prevDeviceState, newDeviceState); } /** diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java index 247e297f5031..31764b063ecf 100644 --- a/core/java/android/server/BluetoothInputProfileHandler.java +++ b/core/java/android/server/BluetoothInputProfileHandler.java @@ -20,6 +20,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDeviceProfileState; import android.bluetooth.BluetoothInputDevice; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfileState; import android.content.Context; import android.content.Intent; @@ -191,7 +192,8 @@ final class BluetoothInputProfileHandler { mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); debugLog("InputDevice state : device: " + device + " State:" + prevState + "->" + state); - mBluetoothService.sendConnectionStateChange(device, state, prevState); + mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.INPUT_DEVICE, state, + prevState); } void handleInputDevicePropertyChange(String address, boolean connected) { diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java index 37cfdc4db8c9..bfad74727d1a 100644 --- a/core/java/android/server/BluetoothPanProfileHandler.java +++ b/core/java/android/server/BluetoothPanProfileHandler.java @@ -19,6 +19,7 @@ package android.server; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothPan; +import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.BroadcastReceiver; import android.content.Context; @@ -303,7 +304,8 @@ final class BluetoothPanProfileHandler { mContext.sendBroadcast(intent, BluetoothService.BLUETOOTH_PERM); debugLog("Pan Device state : device: " + device + " State:" + prevState + "->" + state); - mBluetoothService.sendConnectionStateChange(device, state, prevState); + mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.PAN, state, + prevState); } private class BluetoothPanDevice { diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index ee1467350f25..9f435fdbb60c 100755 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -166,6 +166,7 @@ public class BluetoothService extends IBluetooth.Stub { private static final String INCOMING_CONNECTION_FILE = "/data/misc/bluetooth/incoming_connection.conf"; private HashMap<String, Pair<Integer, String>> mIncomingConnections; + private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState; private static class RemoteService { public String address; @@ -237,6 +238,7 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this); mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this); mIncomingConnections = new HashMap<String, Pair<Integer, String>>(); + mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>(); } public static synchronized String readDockBluetoothAddress() { @@ -1742,6 +1744,19 @@ public class BluetoothService extends IBluetooth.Stub { dumpInputDeviceProfile(pw); dumpPanProfile(pw); dumpApplicationServiceRecords(pw); + dumpProfileState(pw); + } + + private void dumpProfileState(PrintWriter pw) { + pw.println("\n--Profile State dump--"); + pw.println("\n Headset profile state:" + + mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET)); + pw.println("\n A2dp profile state:" + + mAdapter.getProfileConnectionState(BluetoothProfile.A2DP)); + pw.println("\n HID profile state:" + + mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE)); + pw.println("\n PAN profile state:" + + mAdapter.getProfileConnectionState(BluetoothProfile.PAN)); } private void dumpHeadsetService(PrintWriter pw) { @@ -2443,23 +2458,85 @@ public class BluetoothService extends IBluetooth.Stub { return mAdapterConnectionState; } - public synchronized void sendConnectionStateChange(BluetoothDevice device, int state, - int prevState) { + public int getProfileConnectionState(int profile) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + + Pair<Integer, Integer> state = mProfileConnectionState.get(profile); + if (state == null) return BluetoothProfile.STATE_DISCONNECTED; + + return state.first; + } + + private void updateProfileConnectionState(int profile, int newState, int oldState) { + // mProfileConnectionState is a hashmap - + // <Integer, Pair<Integer, Integer>> + // The key is the profile, the value is a pair. first element + // is the state and the second element is the number of devices + // in that state. + int numDev = 1; + int newHashState = newState; + boolean update = true; + + // The following conditions are considered in this function: + // 1. If there is no record of profile and state - update + // 2. If a new device's state is current hash state - increment + // number of devices in the state. + // 3. If a state change has happened to Connected or Connecting + // (if current state is not connected), update. + // 4. If numDevices is 1 and that device state is being updated, update + // 5. If numDevices is > 1 and one of the devices is changing state, + // decrement numDevices but maintain oldState if it is Connected or + // Connecting + Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile); + if (stateNumDev != null) { + int currHashState = stateNumDev.first; + numDev = stateNumDev.second; + + if (newState == currHashState) { + numDev ++; + } else if (newState == BluetoothProfile.STATE_CONNECTED || + (newState == BluetoothProfile.STATE_CONNECTING && + currHashState != BluetoothProfile.STATE_CONNECTED)) { + numDev = 1; + } else if (numDev == 1 && oldState == currHashState) { + update = true; + } else if (numDev > 1 && oldState == currHashState) { + numDev --; + + if (currHashState == BluetoothProfile.STATE_CONNECTED || + currHashState == BluetoothProfile.STATE_CONNECTING) { + newHashState = currHashState; + } + } else { + update = false; + } + } + + if (update) { + mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState, + numDev)); + } + } + + public synchronized void sendConnectionStateChange(BluetoothDevice + device, int profile, int state, int prevState) { // Since this is a binder call check if Bluetooth is on still if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return; - if (updateCountersAndCheckForConnectionStateChange(state, prevState)) { - if (!validateProfileConnectionState(state) || - !validateProfileConnectionState(prevState)) { - // Previously, an invalid state was broadcast anyway, - // with the invalid state converted to -1 in the intent. - // Better to log an error and not send an intent with - // invalid contents or set mAdapterConnectionState to -1. - Log.e(TAG, "Error in sendConnectionStateChange: " - + "prevState " + prevState + " state " + state); - return; - } + if (!validateProfileConnectionState(state) || + !validateProfileConnectionState(prevState)) { + // Previously, an invalid state was broadcast anyway, + // with the invalid state converted to -1 in the intent. + // Better to log an error and not send an intent with + // invalid contents or set mAdapterConnectionState to -1. + Log.e(TAG, "Error in sendConnectionStateChange: " + + "prevState " + prevState + " state " + state); + return; + } + updateProfileConnectionState(profile, state, prevState); + + if (updateCountersAndCheckForConnectionStateChange(state, prevState)) { mAdapterConnectionState = state; if (state == BluetoothProfile.STATE_DISCONNECTED) { |