Merge "Make Bluetooth Health APIs public."
This commit is contained in:
committed by
Android (Google) Code Review
commit
cedd460820
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 (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);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user