diff options
author | Jaikumar Ganesh <jaikumar@google.com> | 2011-08-31 15:36:05 -0700 |
---|---|---|
committer | Jaikumar Ganesh <jaikumar@google.com> | 2011-09-08 15:17:17 -0700 |
commit | eb9d34630f74d0260690287f2df57c0cd3d7ba1d (patch) | |
tree | c32b2e59540e97130c8bef912c59246474e68a47 | |
parent | 9fefa3c716e9c8d7dfb6c851c91e37e37732a955 (diff) | |
download | frameworks_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.txt | 38 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothHealth.java | 52 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothHealthAppConfiguration.java | 8 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothHealthCallback.java | 44 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetooth.aidl | 2 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetoothHealthCallback.aidl | 3 | ||||
-rw-r--r-- | core/java/android/server/BluetoothHealthProfileHandler.java | 251 | ||||
-rwxr-xr-x | core/java/android/server/BluetoothService.java | 4 | ||||
-rw-r--r-- | core/jni/android_server_BluetoothService.cpp | 3 |
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; } |