summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothHealth.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothHealth.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothHealth.java444
1 files changed, 444 insertions, 0 deletions
diff --git a/framework/java/android/bluetooth/BluetoothHealth.java b/framework/java/android/bluetooth/BluetoothHealth.java
new file mode 100644
index 0000000000..52efc071ce
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothHealth.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.annotation.SdkConstant;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Public API for Bluetooth Health Profile.
+ *
+ * <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
+ */
+public final class BluetoothHealth implements BluetoothProfile {
+ private static final String TAG = "BluetoothHealth";
+ private static final boolean DBG = false;
+
+ /**
+ * Health Profile Source Role - the health device.
+ */
+ public static final int SOURCE_ROLE = 1 << 0;
+
+ /**
+ * Health Profile Sink Role the device talking to the health device.
+ */
+ public static final int SINK_ROLE = 1 << 1;
+
+ /**
+ * Health Profile - Channel Type used - Reliable
+ */
+ public static final int CHANNEL_TYPE_RELIABLE = 10;
+
+ /**
+ * Health Profile - Channel Type used - Streaming
+ */
+ public static final int CHANNEL_TYPE_STREAMING = 11;
+
+ /**
+ * @hide
+ */
+ public static final int CHANNEL_TYPE_ANY = 12;
+
+ private final ArrayList<BluetoothHealthAppConfiguration> mAppConfigs =
+ new ArrayList<BluetoothHealthAppConfiguration>();
+
+ /**
+ * Register an application configuration that acts as a Health SINK.
+ * This is the configuration that will be used to communicate with health devices
+ * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
+ * the callback is used to notify success or failure if the function returns true.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param name The friendly name associated with the application or configuration.
+ * @param dataType The dataType of the Source role of Health Profile to which
+ * the sink wants to connect to.
+ * @param callback A callback to indicate success or failure of the registration and
+ * all operations done on this application configuration.
+ * @return If true, callback will be called.
+ */
+ public boolean registerSinkAppConfiguration(String name, int dataType,
+ IBluetoothHealthCallback callback) {
+ if (!isEnabled() || name == null) return false;
+
+ if (DBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
+ return registerAppConfiguration(name, dataType, SINK_ROLE,
+ CHANNEL_TYPE_ANY, callback);
+ }
+
+ /**
+ * Register an application configuration that acts as a Health SINK or in a Health
+ * SOURCE role.This is an asynchronous call and so
+ * the callback is used to notify success or failure if the function returns true.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param name The friendly name associated with the application or configuration.
+ * @param dataType The dataType of the Source role of Health Profile.
+ * @param channelType The channel type. Will be one of
+ * {@link #CHANNEL_TYPE_RELIABLE} or
+ * {@link #CHANNEL_TYPE_STREAMING}
+ * @param callback - A callback to indicate success or failure.
+ * @return If true, callback will be called.
+ * @hide
+ */
+ public boolean registerAppConfiguration(String name, int dataType, int role,
+ int channelType, IBluetoothHealthCallback callback) {
+ boolean result = false;
+ if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
+
+ if (DBG) log("registerApplication(" + name + ":" + dataType + ")");
+ BluetoothHealthAppConfiguration config =
+ new BluetoothHealthAppConfiguration(name, dataType, role, channelType,
+ callback);
+
+ if (mService != null) {
+ try {
+ result = mService.registerAppConfiguration(config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+
+ if (result) mAppConfigs.add(config);
+ return result;
+ }
+
+ /**
+ * Unregister an application configuration that has been registered using
+ * {@link #registerSinkAppConfiguration}
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param config The health app configuration
+ * @return Success or failure.
+ * @hide
+ */
+ public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
+ boolean result = false;
+ if (mService != null && isEnabled() && isValidAppConfig(config)) {
+ try {
+ result = mService.unregisterAppConfiguration(config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ if (result) mAppConfigs.remove(config);
+ return result;
+ }
+
+ /**
+ * Connect to a health device which has the {@link #SOURCE_ROLE}.
+ * This is an asynchrnous call. If this function returns true, the callback
+ * associated with the application configuration will be called.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device The remote Bluetooth device.
+ * @param config The application configuration which has been registed using
+ * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @return If true, the callback associated with the application config will be called.
+ */
+ public boolean connectChannelToSource(BluetoothDevice device,
+ BluetoothHealthAppConfiguration config) {
+ if (mService != null && isEnabled() && isValidDevice(device) &&
+ isValidAppConfig(config)) {
+ try {
+ return mService.connectChannelToSource(device, config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Connect to a health device which has the {@link #SINK_ROLE}.
+ * This is an asynchronous call. If this function returns true, the callback
+ * associated with the application configuration will be called.
+ *
+ *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device The remote Bluetooth device.
+ * @param config The application configuration which has been registed using
+ * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @return If true, the callback associated with the application config will be called.
+ * @hide
+ */
+ public boolean connectChannelToSink(BluetoothDevice device,
+ BluetoothHealthAppConfiguration config, int channelType) {
+ if (mService != null && isEnabled() && isValidDevice(device) &&
+ isValidAppConfig(config)) {
+ try {
+ return mService.connectChannelToSink(device, config, channelType);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Disconnect a connected health channel.
+ * This is an asynchronous call. If this function returns true, the callback
+ * associated with the application configuration will be called.
+ *
+ *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param device The remote Bluetooth device.
+ * @param config The application configuration which has been registed using
+ * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param fd The file descriptor that was 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) {
+ if (mService != null && isEnabled() && isValidDevice(device) &&
+ isValidAppConfig(config)) {
+ try {
+ return mService.disconnectChannel(device, config, fd);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return false;
+ }
+
+ /**
+ * Get the file descriptor of the main channel associated with the remote device
+ * and application configuration.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @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) &&
+ isValidAppConfig(config)) {
+ try {
+ return mService.getMainChannelFd(device, config);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return null;
+ }
+
+ /**
+ * Get the current connection state of the profile.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * This is not specific to any application configuration but represents the connection
+ * state of the local Bluetooth adapter with the remote device. This can be used
+ * by applications like status bar which would just like to know the state of the
+ * local adapter.
+ *
+ * @param device Remote bluetooth device.
+ * @return State of the profile connection. One of
+ * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
+ */
+ public int getConnectionState(BluetoothDevice device) {
+ if (mService != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return mService.getHealthDeviceConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ } else {
+ Log.w(TAG, "Proxy not attached to service");
+ if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+ }
+ return STATE_DISCONNECTED;
+ }
+
+ /**
+ * Get connected devices for this specific profile.
+ *
+ * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * This is not specific to any application configuration but represents the connection
+ * state of the local Bluetooth adapter for this profile. This can be used
+ * by applications like status bar which would just like to know the state of the
+ * local adapter.
+ * @return List of devices. The list will be empty on error.
+ */
+ public List<BluetoothDevice> getConnectedDevices() {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getConnectedHealthDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Get a list of devices that match any of the given connection
+ * states.
+ *
+ * <p> If none of the devices match any of the given states,
+ * an empty list will be returned.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ * This is not specific to any application configuration but represents the connection
+ * state of the local Bluetooth adapter for this profile. This can be used
+ * by applications like status bar which would just like to know the state of the
+ * local adapter.
+ *
+ * @param states Array of states. States can be one of
+ * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
+ * @return List of devices. The list will be empty on error.
+ */
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (mService != null && isEnabled()) {
+ try {
+ return mService.getHealthDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /** Health Channel Connection State - Disconnected */
+ public static final int STATE_CHANNEL_DISCONNECTED = 0;
+ /** Health Channel Connection State - Connecting */
+ public static final int STATE_CHANNEL_CONNECTING = 1;
+ /** Health Channel Connection State - Connected */
+ public static final int STATE_CHANNEL_CONNECTED = 2;
+ /** Health Channel Connection State - Disconnecting */
+ public static final int STATE_CHANNEL_DISCONNECTING = 3;
+
+ /** Health App Configuration registration success */
+ public static final int APPLICATION_REGISTRATION_SUCCESS = 0;
+ /** Health App Configuration registration failure */
+ public static final int APPLICATION_REGISTRATION_FAILURE = 1;
+ /** Health App Configuration un-registration success */
+ public static final int APPLICATION_UNREGISTRATION_SUCCESS = 2;
+ /** Health App Configuration un-registration failure */
+ public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
+
+ private Context mContext;
+ private ServiceListener mServiceListener;
+ private IBluetooth mService;
+ BluetoothAdapter mAdapter;
+
+ /**
+ * Create a BluetoothHealth proxy object.
+ */
+ /*package*/ BluetoothHealth(Context mContext, ServiceListener l) {
+ IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ mServiceListener = l;
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ if (b != null) {
+ mService = IBluetooth.Stub.asInterface(b);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, this);
+ }
+ } else {
+ Log.w(TAG, "Bluetooth Service not available!");
+
+ // Instead of throwing an exception which prevents people from going
+ // into Wireless settings in the emulator. Let it crash later when it is actually used.
+ mService = null;
+ }
+ }
+
+ private boolean isEnabled() {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+
+ if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
+ log("Bluetooth is Not enabled");
+ return false;
+ }
+
+ private boolean isValidDevice(BluetoothDevice device) {
+ if (device == null) return false;
+
+ if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
+ return false;
+ }
+
+ private boolean isValidAppConfig(BluetoothHealthAppConfiguration config) {
+ if (!mAppConfigs.isEmpty() && mAppConfigs.contains(config)) return true;
+ log("Not a valid config: " + config);
+ return false;
+ }
+
+ private boolean checkAppParam(String name, int role, int channelType,
+ IBluetoothHealthCallback callback) {
+ if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
+ (channelType != CHANNEL_TYPE_RELIABLE &&
+ channelType != CHANNEL_TYPE_STREAMING &&
+ channelType != CHANNEL_TYPE_ANY) || callback == null) {
+ return false;
+ }
+ if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
+ return true;
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}