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";
600f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final boolean DBG = true;
61563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = false;
622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile Source Role - the health device.
652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int SOURCE_ROLE = 1 << 0;
672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile Sink Role the device talking to the health device.
702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int SINK_ROLE = 1 << 1;
722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile - Channel Type used - Reliable
752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_RELIABLE = 10;
772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Health Profile - Channel Type used - Streaming
802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_STREAMING = 11;
822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int CHANNEL_TYPE_ANY = 12;
872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
88b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
89b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_SUCCESS = 6000;
90b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
91b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_ERROR = 6001;
92b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
93b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
94b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
95b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
96b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
97b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
98b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /** @hide */
99b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
100b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
1010f42037eb7b5118015c2caca635538324ccf0ccffredc    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
1020f42037eb7b5118015c2caca635538324ccf0ccffredc            new IBluetoothStateChangeCallback.Stub() {
1030f42037eb7b5118015c2caca635538324ccf0ccffredc                public void onBluetoothStateChange(boolean up) {
1040f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
1050f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (!up) {
106563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                        if (VDBG) Log.d(TAG,"Unbinding service...");
1070f42037eb7b5118015c2caca635538324ccf0ccffredc                        synchronized (mConnection) {
1080f42037eb7b5118015c2caca635538324ccf0ccffredc                            try {
1090f42037eb7b5118015c2caca635538324ccf0ccffredc                                mService = null;
1100f42037eb7b5118015c2caca635538324ccf0ccffredc                                mContext.unbindService(mConnection);
1110f42037eb7b5118015c2caca635538324ccf0ccffredc                            } catch (Exception re) {
1120f42037eb7b5118015c2caca635538324ccf0ccffredc                                Log.e(TAG,"",re);
1130f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
1140f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
1150f42037eb7b5118015c2caca635538324ccf0ccffredc                    } else {
1160f42037eb7b5118015c2caca635538324ccf0ccffredc                        synchronized (mConnection) {
1170f42037eb7b5118015c2caca635538324ccf0ccffredc                            try {
1180f42037eb7b5118015c2caca635538324ccf0ccffredc                                if (mService == null) {
119563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                                    if (VDBG) Log.d(TAG,"Binding service...");
1200f42037eb7b5118015c2caca635538324ccf0ccffredc                                    if (!mContext.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
1210f42037eb7b5118015c2caca635538324ccf0ccffredc                                        Log.e(TAG, "Could not bind to Bluetooth Health Service");
1220f42037eb7b5118015c2caca635538324ccf0ccffredc                                    }
1230f42037eb7b5118015c2caca635538324ccf0ccffredc                                }
1240f42037eb7b5118015c2caca635538324ccf0ccffredc                            } catch (Exception re) {
1250f42037eb7b5118015c2caca635538324ccf0ccffredc                                Log.e(TAG,"",re);
1260f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
1270f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
1280f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
1290f42037eb7b5118015c2caca635538324ccf0ccffredc                }
1300f42037eb7b5118015c2caca635538324ccf0ccffredc        };
1310f42037eb7b5118015c2caca635538324ccf0ccffredc
132b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
1332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK.
1352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is the configuration that will be used to communicate with health devices
1362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
1372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile to which
1432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                   the sink wants to connect to.
1442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback A callback to indicate success or failure of the registration and
1452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               all operations done on this application configuration.
1462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerSinkAppConfiguration(String name, int dataType,
149fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
1502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || name == null) return false;
1512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
152563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
1532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return registerAppConfiguration(name, dataType, SINK_ROLE,
1542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                CHANNEL_TYPE_ANY, callback);
1552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK or in a Health
1592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * SOURCE role.This is an asynchronous call and so
1602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile.
1662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param channelType The channel type. Will be one of
1672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_RELIABLE}  or
1682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_STREAMING}
1692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback - A callback to indicate success or failure.
1702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
1722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerAppConfiguration(String name, int dataType, int role,
174fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            int channelType, BluetoothHealthCallback callback) {
1752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
1762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
1772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
178563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("registerApplication(" + name + ":" + dataType + ")");
179fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
1802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothHealthAppConfiguration config =
181fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
1822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null) {
1842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
185fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                result = mService.registerAppConfiguration(config, wrapper);
1862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
1872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
18813450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
1892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
1902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
1912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
1922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
1932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
1942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Unregister an application configuration that has been registered using
1982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * {@link #registerSinkAppConfiguration}
1992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config  The health app configuration
2032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return Success or failure.
2042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
2062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
207fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        if (mService != null && isEnabled() && config != null) {
2082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                result = mService.unregisterAppConfiguration(config);
2102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
21213450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
217fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
2182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
2192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Connect to a health device which has the {@link #SOURCE_ROLE}.
223fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
229fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
230fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
2312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSource(BluetoothDevice device,
2342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
2352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
236fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSource(device, config);
2392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
24113450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
2462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
2472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Connect to a health device which has the {@link #SINK_ROLE}.
2512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
257fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
258fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
2592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
2612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSink(BluetoothDevice device,
2632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelType) {
2642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
265fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSink(device, config, channelType);
2682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
27013450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
2712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
2722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
2732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
2742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
2752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
2762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Disconnect a connected health channel.
2802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
286fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
287fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
288eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * @param channelId The channel id associated with the channel
2892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean disconnectChannel(BluetoothDevice device,
292eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelId) {
2932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
294fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
296eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                return mService.disconnectChannel(device, config, channelId);
2972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
2982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
29913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
3052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the file descriptor of the main channel associated with the remote device
3092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * and application configuration.
3102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
313eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
314eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * when done.
315eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     *
3162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth health device
3172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config The application configuration
3182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return null on failure, ParcelFileDescriptor on success.
3192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
3202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
3212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
3222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
323fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
3242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getMainChannelFd(device, config);
3262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
32813450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return null;
3342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the current connection state of the profile.
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 with the remote device. 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     *
3462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device Remote bluetooth device.
3472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return State of the profile connection. One of
3482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
3492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
3502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
351fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
3532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device)) {
3542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDeviceConnectionState(device);
3562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
35813450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return STATE_DISCONNECTED;
3642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
367eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * Get connected devices for the health profile.
3682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
3702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
3752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
3782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
379fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
3812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
3822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getConnectedHealthDevices();
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
3932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get a list of devices that match any of the given connection
3952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * states.
3962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> If none of the devices match any of the given states,
3982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * an empty list will be returned.
3992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
4002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
4012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
4022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
4032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
4042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
4052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
4062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param states Array of states. States can be one of
4072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
4082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
4092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
4102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
411fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
4122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
4132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
4142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
4152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDevicesMatchingConnectionStates(states);
4162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
4172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
4182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return new ArrayList<BluetoothDevice>();
41913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
4202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
4212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
4222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return new ArrayList<BluetoothDevice>();
4232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
425fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
426fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        private BluetoothHealthCallback mCallback;
427fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
428fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
429fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            mCallback = callback;
430fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
431fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
432fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
433fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
434fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                                         int status) {
435eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh           mCallback.onHealthAppConfigurationStatusChange(config, status);
436fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
437fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
438fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
439fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
440fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                       BluetoothDevice device, int prevState, int newState,
441eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                       ParcelFileDescriptor fd, int channelId) {
442eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
443eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                                 channelId);
444fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
445fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    }
446fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
4472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     /** Health Channel Connection State - Disconnected */
4482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTED  = 0;
4492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connecting */
4502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTING    = 1;
4512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connected */
4522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTED     = 2;
4532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Disconnecting */
4542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTING = 3;
4552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration success */
457eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
4582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration failure */
459eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
4602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration success */
461eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
4622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration failure */
463eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
4642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
46513450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private Context mContext;
4662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private ServiceListener mServiceListener;
46713450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private IBluetoothHealth mService;
4682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    BluetoothAdapter mAdapter;
4692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
4712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Create a BluetoothHealth proxy object.
4722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
47313450df2b9264ef2220418f308037c19cec739a9Matthew Xie    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
47413450df2b9264ef2220418f308037c19cec739a9Matthew Xie        mContext = context;
4752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mServiceListener = l;
4762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
4770f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
4780f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
4790f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
4800f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
4810f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (RemoteException e) {
4820f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
4830f42037eb7b5118015c2caca635538324ccf0ccffredc            }
4840f42037eb7b5118015c2caca635538324ccf0ccffredc        }
4850f42037eb7b5118015c2caca635538324ccf0ccffredc
48613450df2b9264ef2220418f308037c19cec739a9Matthew Xie        if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
48713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            Log.e(TAG, "Could not bind to Bluetooth Health Service");
4882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
4892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4919bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    /*package*/ void close() {
492563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("close()");
4930f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
4940f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
4950f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
4960f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
4970f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (Exception e) {
4980f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
4990f42037eb7b5118015c2caca635538324ccf0ccffredc            }
5000f42037eb7b5118015c2caca635538324ccf0ccffredc        }
5010f42037eb7b5118015c2caca635538324ccf0ccffredc
5020f42037eb7b5118015c2caca635538324ccf0ccffredc        synchronized (mConnection) {
5030f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mService != null) {
5040f42037eb7b5118015c2caca635538324ccf0ccffredc                try {
5050f42037eb7b5118015c2caca635538324ccf0ccffredc                    mService = null;
5060f42037eb7b5118015c2caca635538324ccf0ccffredc                    mContext.unbindService(mConnection);
5070f42037eb7b5118015c2caca635538324ccf0ccffredc                } catch (Exception re) {
5080f42037eb7b5118015c2caca635538324ccf0ccffredc                    Log.e(TAG,"",re);
5090f42037eb7b5118015c2caca635538324ccf0ccffredc                }
5100f42037eb7b5118015c2caca635538324ccf0ccffredc            }
51113450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
5129bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        mServiceListener = null;
5139bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    }
5149bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
51513450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private ServiceConnection mConnection = new ServiceConnection() {
51613450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
51713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object connected");
51813450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = IBluetoothHealth.Stub.asInterface(service);
51913450df2b9264ef2220418f308037c19cec739a9Matthew Xie
52013450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
52113450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
52213450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
52313450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
52413450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceDisconnected(ComponentName className) {
52513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object disconnected");
52613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = null;
52713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
52813450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
52913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
53013450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
53113450df2b9264ef2220418f308037c19cec739a9Matthew Xie    };
53213450df2b9264ef2220418f308037c19cec739a9Matthew Xie
5332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isEnabled() {
5342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
5352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
5372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        log("Bluetooth is Not enabled");
5382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
5392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isValidDevice(BluetoothDevice device) {
5422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (device == null) return false;
5432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
5452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
5462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean checkAppParam(String name, int role, int channelType,
549fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
5502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
5512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                (channelType != CHANNEL_TYPE_RELIABLE &&
5522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_STREAMING &&
5532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_ANY) || callback == null) {
5542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return false;
5552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
5562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
5572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return true;
5582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static void log(String msg) {
5612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        Log.d(TAG, msg);
5622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh}
564