summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaikumar Ganesh <jaikumar@google.com>2011-08-31 15:36:05 -0700
committerJaikumar Ganesh <jaikumar@google.com>2011-09-08 15:17:17 -0700
commiteb9d34630f74d0260690287f2df57c0cd3d7ba1d (patch)
treec32b2e59540e97130c8bef912c59246474e68a47
parent9fefa3c716e9c8d7dfb6c851c91e37e37732a955 (diff)
downloadframeworks_base-eb9d34630f74d0260690287f2df57c0cd3d7ba1d.zip
frameworks_base-eb9d34630f74d0260690287f2df57c0cd3d7ba1d.tar.gz
frameworks_base-eb9d34630f74d0260690287f2df57c0cd3d7ba1d.tar.bz2
Make Bluetooth Health APIs public.
Fix a few bugs: a) Pass a integer token to identify the channel. b) Close fds in case of errors. Change-Id: I2046787be5008769435f2f72a5bd67c19b749da0
-rw-r--r--api/current.txt38
-rw-r--r--core/java/android/bluetooth/BluetoothHealth.java52
-rw-r--r--core/java/android/bluetooth/BluetoothHealthAppConfiguration.java8
-rw-r--r--core/java/android/bluetooth/BluetoothHealthCallback.java44
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl2
-rw-r--r--core/java/android/bluetooth/IBluetoothHealthCallback.aidl3
-rw-r--r--core/java/android/server/BluetoothHealthProfileHandler.java251
-rwxr-xr-xcore/java/android/server/BluetoothService.java4
-rw-r--r--core/jni/android_server_BluetoothService.cpp3
9 files changed, 267 insertions, 138 deletions
diff --git a/api/current.txt b/api/current.txt
index 850d1a5..d113e90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4528,6 +4528,44 @@ package android.bluetooth {
field public static final java.lang.String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY = "android.bluetooth.headset.intent.category.companyid";
}
+ public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
+ method public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
+ method public int getConnectionState(android.bluetooth.BluetoothDevice);
+ method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
+ method public android.os.ParcelFileDescriptor getMainChannelFd(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
+ method public boolean registerSinkAppConfiguration(java.lang.String, int, android.bluetooth.BluetoothHealthCallback);
+ method public boolean unregisterAppConfiguration(android.bluetooth.BluetoothHealthAppConfiguration);
+ field public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; // 0x1
+ field public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; // 0x0
+ field public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; // 0x3
+ field public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; // 0x2
+ field public static final int CHANNEL_TYPE_RELIABLE = 10; // 0xa
+ field public static final int CHANNEL_TYPE_STREAMING = 11; // 0xb
+ field public static final int SINK_ROLE = 2; // 0x2
+ field public static final int SOURCE_ROLE = 1; // 0x1
+ field public static final int STATE_CHANNEL_CONNECTED = 2; // 0x2
+ field public static final int STATE_CHANNEL_CONNECTING = 1; // 0x1
+ field public static final int STATE_CHANNEL_DISCONNECTED = 0; // 0x0
+ field public static final int STATE_CHANNEL_DISCONNECTING = 3; // 0x3
+ }
+
+ public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getDataType();
+ method public java.lang.String getName();
+ method public int getRole();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public abstract class BluetoothHealthCallback {
+ ctor public BluetoothHealthCallback();
+ method public void onHealthAppConfigurationStatusChange(android.bluetooth.BluetoothHealthAppConfiguration, int);
+ method public void onHealthChannelStateChange(android.bluetooth.BluetoothHealthAppConfiguration, android.bluetooth.BluetoothDevice, int, int, android.os.ParcelFileDescriptor, int);
+ }
+
public abstract interface BluetoothProfile {
method public abstract java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public abstract int getConnectionState(android.bluetooth.BluetoothDevice);
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 0a01dcf..c165d92 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -32,10 +32,25 @@ import java.util.List;
* <p>BluetoothHealth is a proxy object for controlling the Bluetooth
* Service via IPC.
*
- * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHealth proxy object. Use
- * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
- * @hide
+ * <p> How to connect to a health device which is acting in the source role.
+ * <li> Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothHealth proxy object. </li>
+ * <li> Create an {@link BluetoothHealth} callback and call
+ * {@link #registerSinkAppConfiguration} to register an application
+ * configuration </li>
+ * <li> Pair with the remote device. This currently needs to be done manually
+ * from Bluetooth Settings </li>
+ * <li> Connect to a health device using {@link #connectChannelToSource}. Some
+ * devices will connect the channel automatically. The {@link BluetoothHealth}
+ * callback will inform the application of channel state change. </li>
+ * <li> Use the file descriptor provided with a connected channel to read and
+ * write data to the health channel. </li>
+ * <li> The received data needs to be interpreted using a health manager which
+ * implements the IEEE 11073-xxxxx specifications.
+ * <li> When done, close the health channel by calling {@link #disconnectChannel}
+ * and unregister the application configuration calling
+ * {@link #unregisterAppConfiguration}
+ *
*/
public final class BluetoothHealth implements BluetoothProfile {
private static final String TAG = "BluetoothHealth";
@@ -137,7 +152,6 @@ public final class BluetoothHealth implements BluetoothProfile {
*
* @param config The health app configuration
* @return Success or failure.
- * @hide
*/
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
boolean result = false;
@@ -222,16 +236,15 @@ public final class BluetoothHealth implements BluetoothProfile {
* @param device The remote Bluetooth device.
* @param config The application configuration which has been registered using
* {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
- * @param fd The file descriptor that was associated with the channel.
+ * @param channelId The channel id associated with the channel
* @return If true, the callback associated with the application config will be called.
- * @hide
*/
public boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ BluetoothHealthAppConfiguration config, int channelId) {
if (mService != null && isEnabled() && isValidDevice(device) &&
config != null) {
try {
- return mService.disconnectChannel(device, config, fd);
+ return mService.disconnectChannel(device, config, channelId);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -248,11 +261,13 @@ public final class BluetoothHealth implements BluetoothProfile {
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
+ * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
+ * when done.
+ *
* @param device The remote Bluetooth health device
* @param config The application configuration
* @return null on failure, ParcelFileDescriptor on success.
*/
-
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
@@ -300,7 +315,7 @@ public final class BluetoothHealth implements BluetoothProfile {
}
/**
- * Get connected devices for this specific profile.
+ * Get connected devices for the health profile.
*
* <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
*
@@ -368,14 +383,15 @@ public final class BluetoothHealth implements BluetoothProfile {
@Override
public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
int status) {
- mCallback.onHealthAppConfigurationStatusChange(config, status);
+ mCallback.onHealthAppConfigurationStatusChange(config, status);
}
@Override
public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
BluetoothDevice device, int prevState, int newState,
- ParcelFileDescriptor fd) {
- mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
+ ParcelFileDescriptor fd, int channelId) {
+ mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
+ channelId);
}
}
@@ -389,13 +405,13 @@ public final class BluetoothHealth implements BluetoothProfile {
public static final int STATE_CHANNEL_DISCONNECTING = 3;
/** Health App Configuration registration success */
- public static final int APPLICATION_REGISTRATION_SUCCESS = 0;
+ public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
/** Health App Configuration registration failure */
- public static final int APPLICATION_REGISTRATION_FAILURE = 1;
+ public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
/** Health App Configuration un-registration success */
- public static final int APPLICATION_UNREGISTRATION_SUCCESS = 2;
+ public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
/** Health App Configuration un-registration failure */
- public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
+ public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
private ServiceListener mServiceListener;
private IBluetooth mService;
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 7020249..15a9101 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -26,7 +26,6 @@ import android.os.Parcelable;
* that the Bluetooth Health third party application will register to communicate with the
* remote Bluetooth health device.
*
- * @hide
*/
public final class BluetoothHealthAppConfiguration implements Parcelable {
private final String mName;
@@ -39,6 +38,7 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
+ * @hide
*/
BluetoothHealthAppConfiguration(String name, int dataType) {
mName = name;
@@ -54,6 +54,7 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
* @param dataType Data Type of the remote Bluetooth Health device
* @param role {@link BluetoothHealth#SOURCE_ROLE} or
* {@link BluetoothHealth#SINK_ROLE}
+ * @hide
*/
BluetoothHealthAppConfiguration(String name, int dataType, int role, int
channelType) {
@@ -93,7 +94,6 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
mChannelType + "]";
}
- @Override
public int describeContents() {
return 0;
}
@@ -132,6 +132,7 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
* @return One of {@link BluetoothHealth#CHANNEL_TYPE_RELIABLE} or
* {@link BluetoothHealth#CHANNEL_TYPE_STREAMING} or
* {@link BluetoothHealth#CHANNEL_TYPE_ANY}.
+ * @hide
*/
public int getChannelType() {
return mChannelType;
@@ -155,13 +156,10 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
}
};
- @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(mName);
out.writeInt(mDataType);
out.writeInt(mRole);
out.writeInt(mChannelType);
}
-
-
}
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
index 0d11bb5..baf2ade 100644
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -21,22 +21,48 @@ import android.os.ParcelFileDescriptor;
import android.util.Log;
/**
- * This class is used for all the {@link BluetoothHealth} callbacks.
- * @hide
+ * This abstract class is used to implement {@link BluetoothHealth} callbacks.
*/
public abstract class BluetoothHealthCallback {
-
private static final String TAG = "BluetoothHealthCallback";
+ /**
+ * Callback to inform change in registration state of the health
+ * application.
+ * <p> This callback is called on the binder thread (not on the UI thread)
+ *
+ * @param config Bluetooth Health app configuration
+ * @param status Success or failure of the registration or unregistration
+ * calls. Can be one of
+ * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or
+ * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
+ * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS} or
+ * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
+ */
public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
- int status) {
- Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
+ int status) {
+ Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
}
+ /**
+ * Callback to inform change in channel state.
+ * <p> Its the responsibility of the implementor of this callback to close the
+ * parcel file descriptor when done. This callback is called on the Binder
+ * thread (not the UI thread)
+ *
+ * @param config The Health app configutation
+ * @param device The Bluetooth Device
+ * @param prevState The previous state of the channel
+ * @param newState The new state of the channel.
+ * @param fd The Parcel File Descriptor when the channel state is connected.
+ * @param channelId The id associated with the channel. This id will be used
+ * in future calls like when disconnecting the channel.
+ */
public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
- BluetoothDevice device, int prevState, int newState,
- ParcelFileDescriptor fd) {
- Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
- "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
+ BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
+ int channelId) {
+ Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device +
+ "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd +
+ "ChannelId:" + channelId);
}
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index d4e7f7d..fefeb93 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -116,7 +116,7 @@ interface IBluetooth
boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
int channelType);
- boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, in ParcelFileDescriptor fd);
+ boolean disconnectChannel(in BluetoothDevice device, in BluetoothHealthAppConfiguration config, int id);
ParcelFileDescriptor getMainChannelFd(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
List<BluetoothDevice> getConnectedHealthDevices();
List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(in int[] states);
diff --git a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
index 9fe5335..0ace9fe 100644
--- a/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothHealthCallback.aidl
@@ -27,5 +27,6 @@ interface IBluetoothHealthCallback
{
void onHealthAppConfigurationStatusChange(in BluetoothHealthAppConfiguration config, int status);
void onHealthChannelStateChange(in BluetoothHealthAppConfiguration config,
- in BluetoothDevice device, int prevState, int newState, in ParcelFileDescriptor fd);
+ in BluetoothDevice device, int prevState, int newState, in
+ ParcelFileDescriptor fd, int id);
}
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 51c995e..8656cd9 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -29,6 +29,8 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -47,7 +49,6 @@ final class BluetoothHealthProfileHandler {
private static final boolean DBG = true;
private static BluetoothHealthProfileHandler sInstance;
- private Context mContext;
private BluetoothService mBluetoothService;
private ArrayList<HealthChannel> mHealthChannels;
private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
@@ -76,6 +77,17 @@ final class BluetoothHealthProfileHandler {
mConfig = config;
mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
}
+
+ @Override
+ public int hashCode() {
+ int result = 17;
+ result = 31 * result + (mChannelPath == null ? 0 : mChannelPath.hashCode());
+ result = 31 * result + mDevice.hashCode();
+ result = 31 * result + mConfig.hashCode();
+ result = 31 * result + mState;
+ result = 31 * result + mChannelType;
+ return result;
+ }
}
private final Handler mHandler = new Handler() {
@@ -98,28 +110,38 @@ final class BluetoothHealthProfileHandler {
}
if (path == null) {
- mCallbacks.remove(registerApp);
callHealthApplicationStatusCallback(registerApp,
- BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
+ BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE);
+ mCallbacks.remove(registerApp);
} else {
mHealthAppConfigs.put(registerApp, path);
callHealthApplicationStatusCallback(registerApp,
- BluetoothHealth.APPLICATION_REGISTRATION_SUCCESS);
+ BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS);
}
break;
case MESSAGE_UNREGISTER_APPLICATION:
BluetoothHealthAppConfiguration unregisterApp =
(BluetoothHealthAppConfiguration) msg.obj;
+
+ // Disconnect all the channels
+ for (HealthChannel chan : mHealthChannels) {
+ if (chan.mConfig.equals(unregisterApp) &&
+ chan.mState != BluetoothHealth.STATE_CHANNEL_DISCONNECTED) {
+ disconnectChannel(chan.mDevice, unregisterApp, chan.hashCode());
+ }
+ }
+
boolean result = mBluetoothService.unregisterHealthApplicationNative(
mHealthAppConfigs.get(unregisterApp));
if (result) {
- mCallbacks.remove(unregisterApp);
callHealthApplicationStatusCallback(unregisterApp,
- BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
+ BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS);
+ mCallbacks.remove(unregisterApp);
+ mHealthAppConfigs.remove(unregisterApp);
} else {
callHealthApplicationStatusCallback(unregisterApp,
- BluetoothHealth.APPLICATION_UNREGISTRATION_FAILURE);
+ BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE);
}
break;
case MESSAGE_CONNECT_CHANNEL:
@@ -133,7 +155,8 @@ final class BluetoothHealthProfileHandler {
channelType)) {
int prevState = chan.mState;
int state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null);
+ callHealthChannelCallback(chan.mConfig, chan.mDevice, prevState, state, null,
+ chan.hashCode());
mHealthChannels.remove(chan);
}
}
@@ -141,7 +164,6 @@ final class BluetoothHealthProfileHandler {
};
private BluetoothHealthProfileHandler(Context context, BluetoothService service) {
- mContext = context;
mBluetoothService = service;
mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
mHealthChannels = new ArrayList<HealthChannel>();
@@ -205,7 +227,7 @@ final class BluetoothHealthProfileHandler {
int prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
int state = BluetoothHealth.STATE_CHANNEL_CONNECTING;
- callHealthChannelCallback(config, device, prevState, state, null);
+ callHealthChannelCallback(config, device, prevState, state, null, chan.hashCode());
Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_CHANNEL);
msg.obj = chan;
@@ -235,37 +257,44 @@ final class BluetoothHealthProfileHandler {
}
boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
- HealthChannel chan = findChannelByFd(device, config, fd);
- if (chan == null) return false;
+ BluetoothHealthAppConfiguration config, int id) {
+ HealthChannel chan = findChannelById(device, config, id);
+ if (chan == null) {
+ return false;
+ }
String deviceObjectPath =
mBluetoothService.getObjectPathFromAddress(device.getAddress());
- if (mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) {
- int prevState = chan.mState;
- chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+
+ mBluetoothService.releaseChannelFdNative(chan.mChannelPath);
+
+ int prevState = chan.mState;
+ chan.mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTING;
+ callHealthChannelCallback(config, device, prevState, chan.mState,
+ null, chan.hashCode());
+
+ if (!mBluetoothService.destroyChannelNative(deviceObjectPath, chan.mChannelPath)) {
+ prevState = chan.mState;
+ chan.mState = BluetoothHealth.STATE_CHANNEL_CONNECTED;
callHealthChannelCallback(config, device, prevState, chan.mState,
- chan.mChannelFd);
- return true;
- } else {
+ chan.mChannelFd, chan.hashCode());
return false;
+ } else {
+ return true;
}
}
- private HealthChannel findChannelByFd(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ private HealthChannel findChannelById(BluetoothDevice device,
+ BluetoothHealthAppConfiguration config, int id) {
for (HealthChannel chan : mHealthChannels) {
- if (chan.mChannelFd.equals(fd) && chan.mDevice.equals(device) &&
- chan.mConfig.equals(config)) return chan;
+ if (chan.hashCode() == id) return chan;
}
return null;
}
- private HealthChannel findChannelByPath(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, String path) {
+ private HealthChannel findChannelByPath(BluetoothDevice device, String path) {
for (HealthChannel chan : mHealthChannels) {
- if (chan.mChannelPath.equals(path) && chan.mDevice.equals(device) &&
- chan.mConfig.equals(config)) return chan;
+ if (chan.mChannelPath.equals(path) && chan.mDevice.equals(device)) return chan;
}
return null;
}
@@ -296,7 +325,15 @@ final class BluetoothHealthProfileHandler {
ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
HealthChannel chan = getMainChannel(device, config);
- if (chan != null) return chan.mChannelFd;
+ if (chan != null) {
+ ParcelFileDescriptor pfd = null;
+ try {
+ pfd = chan.mChannelFd.dup();
+ return pfd;
+ } catch (IOException e) {
+ return null;
+ }
+ }
String objectPath =
mBluetoothService.getObjectPathFromAddress(device.getAddress());
@@ -308,14 +345,18 @@ final class BluetoothHealthProfileHandler {
// We had no record of the main channel but querying Bluez we got a
// main channel. We might not have received the PropertyChanged yet for
// the main channel creation so update our data structure here.
- chan = findChannelByPath(device, config, mainChannelPath);
+ chan = findChannelByPath(device, mainChannelPath);
if (chan == null) {
errorLog("Main Channel present but we don't have any account of it:" +
device +":" + config);
return null;
}
chan.mMainChannel = true;
- return chan.mChannelFd;
+ try {
+ return chan.mChannelFd.dup();
+ } catch (IOException e) {
+ return null;
+ }
}
/*package*/ void onHealthDevicePropertyChanged(String devicePath,
@@ -334,7 +375,7 @@ final class BluetoothHealthProfileHandler {
BluetoothHealthAppConfiguration config = findHealthApplication(device,
channelPath);
if (config != null) {
- HealthChannel chan = findChannelByPath(device, config, channelPath);
+ HealthChannel chan = findChannelByPath(device, channelPath);
if (chan == null) {
errorLog("Health Channel is not present:" + channelPath);
} else {
@@ -346,21 +387,22 @@ final class BluetoothHealthProfileHandler {
private BluetoothHealthAppConfiguration findHealthApplication(
BluetoothDevice device, String channelPath) {
BluetoothHealthAppConfiguration config = null;
- String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+ HealthChannel chan = findChannelByPath(device, channelPath);
- if (configPath == null) {
- errorLog("No associated application for Health Channel:" + channelPath);
- return null;
+ if (chan != null) {
+ config = chan.mConfig;
} else {
- for (Entry<BluetoothHealthAppConfiguration, String> e :
- mHealthAppConfigs.entrySet()) {
- if (e.getValue().equals(configPath)) {
- config = e.getKey();
+ String configPath = mBluetoothService.getChannelApplicationNative(channelPath);
+ if (configPath == null) {
+ errorLog("Config path is null for application");
+ } else {
+ for (Entry<BluetoothHealthAppConfiguration, String> e :
+ mHealthAppConfigs.entrySet()) {
+ if (e.getValue().equals(configPath)) {
+ config = e.getKey();
+ }
}
- }
- if (config == null) {
- errorLog("No associated application for application path:" + configPath);
- return null;
+ if (config == null) errorLog("No associated application for path:" + configPath);
}
}
return config;
@@ -375,78 +417,83 @@ final class BluetoothHealthProfileHandler {
if (address == null) return;
BluetoothDevice device = adapter.getRemoteDevice(address);
-
- BluetoothHealthAppConfiguration config = findHealthApplication(device,
- channelPath);
+ BluetoothHealthAppConfiguration config;
int state, prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
ParcelFileDescriptor fd;
HealthChannel channel;
+ config = findHealthApplication(device, channelPath);
- if (config != null) {
- if (exists) {
- fd = mBluetoothService.getChannelFdNative(channelPath);
-
- if (fd == null) {
- errorLog("Error obtaining fd for channel:" + channelPath);
- return;
- }
-
- boolean mainChannel =
- getMainChannel(device, config) == null ? false : true;
- if (!mainChannel) {
- String mainChannelPath =
- mBluetoothService.getMainChannelNative(devicePath);
- if (mainChannelPath == null) {
- errorLog("Main Channel Path is null for devicePath:" + devicePath);
- return;
- }
- if (mainChannelPath.equals(channelPath)) mainChannel = true;
- }
-
- channel = findConnectingChannel(device, config);
- if (channel != null) {
- channel.mChannelFd = fd;
- channel.mMainChannel = mainChannel;
- channel.mChannelPath = channelPath;
- prevState = channel.mState;
- } else {
- channel = new HealthChannel(device, config, fd, mainChannel,
- channelPath);
- mHealthChannels.add(channel);
- prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- }
- state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
- } else {
- channel = findChannelByPath(device, config, channelPath);
- if (channel == null) {
- errorLog("Channel not found:" + config + ":" + channelPath);
- return;
- }
-
- fd = channel.mChannelFd;
- // CLOSE FD
- mBluetoothService.releaseChannelFdNative(channel.mChannelPath);
- mHealthChannels.remove(channel);
-
- prevState = channel.mState;
- state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
- }
- channel.mState = state;
- callHealthChannelCallback(config, device, prevState, state, fd);
+ if (exists) {
+ fd = mBluetoothService.getChannelFdNative(channelPath);
+ if (fd == null) {
+ errorLog("Error obtaining fd for channel:" + channelPath);
+ return;
+ }
+ boolean mainChannel =
+ getMainChannel(device, config) == null ? false : true;
+ if (!mainChannel) {
+ String mainChannelPath =
+ mBluetoothService.getMainChannelNative(devicePath);
+ if (mainChannelPath == null) {
+ errorLog("Main Channel Path is null for devicePath:" + devicePath);
+ return;
+ }
+ if (mainChannelPath.equals(channelPath)) mainChannel = true;
+ }
+ channel = findConnectingChannel(device, config);
+ if (channel != null) {
+ channel.mChannelFd = fd;
+ channel.mMainChannel = mainChannel;
+ channel.mChannelPath = channelPath;
+ prevState = channel.mState;
+ } else {
+ channel = new HealthChannel(device, config, fd, mainChannel,
+ channelPath);
+ mHealthChannels.add(channel);
+ prevState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
+ }
+ state = BluetoothHealth.STATE_CHANNEL_CONNECTED;
+ } else {
+ channel = findChannelByPath(device, channelPath);
+ if (channel == null) {
+ errorLog("Channel not found:" + config + ":" + channelPath);
+ return;
+ }
+ mHealthChannels.remove(channel);
+
+ channel.mChannelFd = null;
+ prevState = channel.mState;
+ state = BluetoothHealth.STATE_CHANNEL_DISCONNECTED;
}
+ channel.mState = state;
+ callHealthChannelCallback(config, device, prevState, state, channel.mChannelFd,
+ channel.hashCode());
}
private void callHealthChannelCallback(BluetoothHealthAppConfiguration config,
- BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd) {
+ BluetoothDevice device, int prevState, int state, ParcelFileDescriptor fd, int id) {
broadcastHealthDeviceStateChange(device, prevState, state);
debugLog("Health Device Callback: " + device + " State Change: "
+ prevState + "->" + state);
+
+ ParcelFileDescriptor dupedFd = null;
+ if (fd != null) {
+ try {
+ dupedFd = fd.dup();
+ } catch (IOException e) {
+ dupedFd = null;
+ errorLog("Exception while duping: " + e);
+ }
+ }
+
IBluetoothHealthCallback callback = mCallbacks.get(config);
if (callback != null) {
try {
- callback.onHealthChannelStateChange(config, device, prevState, state, fd);
- } catch (RemoteException e) {}
+ callback.onHealthChannelStateChange(config, device, prevState, state, dupedFd, id);
+ } catch (RemoteException e) {
+ errorLog("Remote Exception:" + e);
+ }
}
}
@@ -458,7 +505,9 @@ final class BluetoothHealthProfileHandler {
if (callback != null) {
try {
callback.onHealthAppConfigurationStatusChange(config, status);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) {
+ errorLog("Remote Exception:" + e);
+ }
}
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 55a0624..95474fe 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -2243,11 +2243,11 @@ public class BluetoothService extends IBluetooth.Stub {
}
public boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
+ BluetoothHealthAppConfiguration config, int id) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
synchronized (mBluetoothHealthProfileHandler) {
- return mBluetoothHealthProfileHandler.disconnectChannel(device, config, fd);
+ return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
}
}
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 819449a..292047b 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1659,6 +1659,7 @@ static jobject getChannelFdNative(JNIEnv *env, jobject object, jstring channelPa
if (fileDesc == NULL) {
// FileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
+ close(fd);
return NULL;
}
@@ -1667,7 +1668,7 @@ static jobject getChannelFdNative(JNIEnv *env, jobject object, jstring channelPa
if (parcelFileDesc == NULL) {
// ParcelFileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
- LOGE("---Parcel File Desc is null");
+ close(fd);
return NULL;
}