BluetoothHealth.java revision 13450df2b9264ef2220418f308037c19cec739a9
12ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh/*
22ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Copyright (C) 2011 The Android Open Source Project
32ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
42ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Licensed under the Apache License, Version 2.0 (the "License");
52ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * you may not use this file except in compliance with the License.
62ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * You may obtain a copy of the License at
72ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
82ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *      http://www.apache.org/licenses/LICENSE-2.0
92ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Unless required by applicable law or agreed to in writing, software
112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * distributed under the License is distributed on an "AS IS" BASIS,
122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * See the License for the specific language governing permissions and
142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * limitations under the License.
152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */
162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshpackage android.bluetooth;
182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1913450df2b9264ef2220418f308037c19cec739a9Matthew Xieimport android.content.ComponentName;
202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.content.Context;
2113450df2b9264ef2220418f308037c19cec739a9Matthew Xieimport android.content.Intent;
2213450df2b9264ef2220418f308037c19cec739a9Matthew Xieimport android.content.ServiceConnection;
232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.IBinder;
242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.ParcelFileDescriptor;
252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.RemoteException;
262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.ServiceManager;
272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.util.Log;
282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport java.util.ArrayList;
302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport java.util.List;
312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh/**
332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Public API for Bluetooth Health Profile.
342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>BluetoothHealth is a proxy object for controlling the Bluetooth
362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Service via IPC.
372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
38eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * <p> How to connect to a health device which is acting in the source role.
39eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Use {@link BluetoothAdapter#getProfileProxy} to get
40eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  the BluetoothHealth proxy object. </li>
41eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Create an {@link BluetoothHealth} callback and call
42eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  {@link #registerSinkAppConfiguration} to register an application
43eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  configuration </li>
44eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Pair with the remote device. This currently needs to be done manually
45eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  from Bluetooth Settings </li>
46eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Connect to a health device using {@link #connectChannelToSource}. Some
47eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  devices will connect the channel automatically. The {@link BluetoothHealth}
48eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  callback will inform the application of channel state change. </li>
49eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Use the file descriptor provided with a connected channel to read and
50eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  write data to the health channel. </li>
51eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> The received data needs to be interpreted using a health manager which
52eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  implements the IEEE 11073-xxxxx specifications.
53eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> When done, close the health channel by calling {@link #disconnectChannel}
54eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  and unregister the application configuration calling
55eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  {@link #unregisterAppConfiguration}
56eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *
572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */
582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshpublic final class BluetoothHealth implements BluetoothProfile {
592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static final String TAG = "BluetoothHealth";
602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static final boolean DBG = false;
612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile Source Role - the health device.
642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int SOURCE_ROLE = 1 << 0;
662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile Sink Role the device talking to the health device.
692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int SINK_ROLE = 1 << 1;
712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile - Channel Type used - Reliable
742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_RELIABLE = 10;
762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile - Channel Type used - Streaming
792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_STREAMING = 11;
812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_ANY = 12;
862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
87b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
88b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_SUCCESS = 6000;
89b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
90b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_ERROR = 6001;
91b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
92b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
93b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
94b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
95b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
96b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
97b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
98b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
99b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
100b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
1012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK.
1032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is the configuration that will be used to communicate with health devices
1042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
1052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile to which
1112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                   the sink wants to connect to.
1122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback A callback to indicate success or failure of the registration and
1132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               all operations done on this application configuration.
1142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerSinkAppConfiguration(String name, int dataType,
117fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
1182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || name == null) return false;
1192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (DBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
1212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return registerAppConfiguration(name, dataType, SINK_ROLE,
1222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                CHANNEL_TYPE_ANY, callback);
1232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK or in a Health
1272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * SOURCE role.This is an asynchronous call and so
1282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile.
1342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param channelType The channel type. Will be one of
1352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_RELIABLE}  or
1362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_STREAMING}
1372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback - A callback to indicate success or failure.
1382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
1402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerAppConfiguration(String name, int dataType, int role,
142fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            int channelType, BluetoothHealthCallback callback) {
1432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
1442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
1452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (DBG) log("registerApplication(" + name + ":" + dataType + ")");
147fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
1482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothHealthAppConfiguration config =
149fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
1502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null) {
1522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
153fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                result = mService.registerAppConfiguration(config, wrapper);
1542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
1552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
15613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
1572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
1582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
1592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
1602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
1612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
1622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Unregister an application configuration that has been registered using
1662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * {@link #registerSinkAppConfiguration}
1672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config  The health app configuration
1712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return Success or failure.
1722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
1742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
175fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        if (mService != null && isEnabled() && config != null) {
1762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
1772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                result = mService.unregisterAppConfiguration(config);
1782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
1792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
18013450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
1812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
1822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
1832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
1842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
185fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
1862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
1872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Connect to a health device which has the {@link #SOURCE_ROLE}.
191fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
1922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
1932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
197fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
198fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
1992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSource(BluetoothDevice device,
2022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
2032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
204fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSource(device, config);
2072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
20913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
2142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
2152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Connect to a health device which has the {@link #SINK_ROLE}.
2192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
225fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
226fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
2272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
2292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSink(BluetoothDevice device,
2312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelType) {
2322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
233fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSink(device, config, channelType);
2362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
23813450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
2432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
2442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Disconnect a connected health channel.
2482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
254fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
255fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
256eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * @param channelId The channel id associated with the channel
2572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean disconnectChannel(BluetoothDevice device,
260eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelId) {
2612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
262fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
264eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                return mService.disconnectChannel(device, config, channelId);
2652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
26713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
2722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
2732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the file descriptor of the main channel associated with the remote device
2772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * and application configuration.
2782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
281eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
282eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * when done.
283eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     *
2842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth health device
2852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config The application configuration
2862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return null on failure, ParcelFileDescriptor on success.
2872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
2892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
2902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
291fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getMainChannelFd(device, config);
2942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
29613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return null;
3022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the current connection state of the profile.
3062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter with the remote device. This can be used
3112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device Remote bluetooth device.
3152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return State of the profile connection. One of
3162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
3172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
3182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
319fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
3212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device)) {
3222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDeviceConnectionState(device);
3242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
32613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return STATE_DISCONNECTED;
3322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
335eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * Get connected devices for the health profile.
3362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
3382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
3432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
3462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
347fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
3492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
3502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getConnectedHealthDevices();
3522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
3542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return new ArrayList<BluetoothDevice>();
35513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return new ArrayList<BluetoothDevice>();
3592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get a list of devices that match any of the given connection
3632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * states.
3642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> If none of the devices match any of the given states,
3662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * an empty list will be returned.
3672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
3712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param states Array of states. States can be one of
3752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
3762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
3772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
3782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
379fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
3812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
3822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDevicesMatchingConnectionStates(states);
3842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
3862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return new ArrayList<BluetoothDevice>();
38713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return new ArrayList<BluetoothDevice>();
3912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
393fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
394fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        private BluetoothHealthCallback mCallback;
395fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
396fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
397fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            mCallback = callback;
398fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
399fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
400fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
401fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
402fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                                         int status) {
403eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh           mCallback.onHealthAppConfigurationStatusChange(config, status);
404fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
405fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
406fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
407fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
408fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                       BluetoothDevice device, int prevState, int newState,
409eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                       ParcelFileDescriptor fd, int channelId) {
410eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
411eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                                 channelId);
412fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
413fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    }
414fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
4152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     /** Health Channel Connection State - Disconnected */
4162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTED  = 0;
4172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connecting */
4182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTING    = 1;
4192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connected */
4202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTED     = 2;
4212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Disconnecting */
4222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTING = 3;
4232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration success */
425eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
4262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration failure */
427eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
4282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration success */
429eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
4302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration failure */
431eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
4322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
43313450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private Context mContext;
4342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private ServiceListener mServiceListener;
43513450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private IBluetoothHealth mService;
4362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    BluetoothAdapter mAdapter;
4372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
4392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Create a BluetoothHealth proxy object.
4402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
44113450df2b9264ef2220418f308037c19cec739a9Matthew Xie    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
44213450df2b9264ef2220418f308037c19cec739a9Matthew Xie        mContext = context;
4432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mServiceListener = l;
4442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
44513450df2b9264ef2220418f308037c19cec739a9Matthew Xie        if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
44613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            Log.e(TAG, "Could not bind to Bluetooth Health Service");
4472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
4482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4509bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    /*package*/ void close() {
45113450df2b9264ef2220418f308037c19cec739a9Matthew Xie        if (DBG) log("close()");
45213450df2b9264ef2220418f308037c19cec739a9Matthew Xie        if (mConnection != null) {
45313450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mContext.unbindService(mConnection);
45413450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mConnection = null;
45513450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
4569bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        mServiceListener = null;
4579bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    }
4589bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
45913450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private ServiceConnection mConnection = new ServiceConnection() {
46013450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
46113450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object connected");
46213450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = IBluetoothHealth.Stub.asInterface(service);
46313450df2b9264ef2220418f308037c19cec739a9Matthew Xie
46413450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
46513450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
46613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
46713450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
46813450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceDisconnected(ComponentName className) {
46913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object disconnected");
47013450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = null;
47113450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
47213450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
47313450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
47413450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
47513450df2b9264ef2220418f308037c19cec739a9Matthew Xie    };
47613450df2b9264ef2220418f308037c19cec739a9Matthew Xie
4772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isEnabled() {
4782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
4792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
4812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        log("Bluetooth is Not enabled");
4822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
4832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isValidDevice(BluetoothDevice device) {
4862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (device == null) return false;
4872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
4892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
4902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean checkAppParam(String name, int role, int channelType,
493fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
4942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
4952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                (channelType != CHANNEL_TYPE_RELIABLE &&
4962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_STREAMING &&
4972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_ANY) || callback == null) {
4982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return false;
4992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
5002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
5012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return true;
5022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static void log(String msg) {
5052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        Log.d(TAG, msg);
5062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh}
508