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.util.Log;
272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport java.util.ArrayList;
292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport java.util.List;
302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh/**
322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Public API for Bluetooth Health Profile.
332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>BluetoothHealth is a proxy object for controlling the Bluetooth
352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Service via IPC.
362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *
37eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * <p> How to connect to a health device which is acting in the source role.
38eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Use {@link BluetoothAdapter#getProfileProxy} to get
39eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  the BluetoothHealth proxy object. </li>
40eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Create an {@link BluetoothHealth} callback and call
41eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  {@link #registerSinkAppConfiguration} to register an application
42eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  configuration </li>
43eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Pair with the remote device. This currently needs to be done manually
44eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  from Bluetooth Settings </li>
45eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Connect to a health device using {@link #connectChannelToSource}. Some
46eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  devices will connect the channel automatically. The {@link BluetoothHealth}
47eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  callback will inform the application of channel state change. </li>
48eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> Use the file descriptor provided with a connected channel to read and
49eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  write data to the health channel. </li>
50eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> The received data needs to be interpreted using a health manager which
51eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  implements the IEEE 11073-xxxxx specifications.
52eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  <li> When done, close the health channel by calling {@link #disconnectChannel}
53eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  and unregister the application configuration calling
54eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *  {@link #unregisterAppConfiguration}
55eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh *
562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */
572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshpublic final class BluetoothHealth implements BluetoothProfile {
582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static final String TAG = "BluetoothHealth";
590f42037eb7b5118015c2caca635538324ccf0ccffredc    private static final boolean DBG = true;
60563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie    private static final boolean VDBG = 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
1000f42037eb7b5118015c2caca635538324ccf0ccffredc    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
1010f42037eb7b5118015c2caca635538324ccf0ccffredc            new IBluetoothStateChangeCallback.Stub() {
1020f42037eb7b5118015c2caca635538324ccf0ccffredc                public void onBluetoothStateChange(boolean up) {
1030f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
1040f42037eb7b5118015c2caca635538324ccf0ccffredc                    if (!up) {
105563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                        if (VDBG) Log.d(TAG,"Unbinding service...");
1060f42037eb7b5118015c2caca635538324ccf0ccffredc                        synchronized (mConnection) {
1070f42037eb7b5118015c2caca635538324ccf0ccffredc                            try {
1080f42037eb7b5118015c2caca635538324ccf0ccffredc                                mService = null;
1090f42037eb7b5118015c2caca635538324ccf0ccffredc                                mContext.unbindService(mConnection);
1100f42037eb7b5118015c2caca635538324ccf0ccffredc                            } catch (Exception re) {
1110f42037eb7b5118015c2caca635538324ccf0ccffredc                                Log.e(TAG,"",re);
1120f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
1130f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
1140f42037eb7b5118015c2caca635538324ccf0ccffredc                    } else {
1150f42037eb7b5118015c2caca635538324ccf0ccffredc                        synchronized (mConnection) {
1160f42037eb7b5118015c2caca635538324ccf0ccffredc                            try {
1170f42037eb7b5118015c2caca635538324ccf0ccffredc                                if (mService == null) {
118563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie                                    if (VDBG) Log.d(TAG,"Binding service...");
119221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn                                    doBind();
1200f42037eb7b5118015c2caca635538324ccf0ccffredc                                }
1210f42037eb7b5118015c2caca635538324ccf0ccffredc                            } catch (Exception re) {
1220f42037eb7b5118015c2caca635538324ccf0ccffredc                                Log.e(TAG,"",re);
1230f42037eb7b5118015c2caca635538324ccf0ccffredc                            }
1240f42037eb7b5118015c2caca635538324ccf0ccffredc                        }
1250f42037eb7b5118015c2caca635538324ccf0ccffredc                    }
1260f42037eb7b5118015c2caca635538324ccf0ccffredc                }
1270f42037eb7b5118015c2caca635538324ccf0ccffredc        };
1280f42037eb7b5118015c2caca635538324ccf0ccffredc
129b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
1302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK.
1322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is the configuration that will be used to communicate with health devices
1332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
1342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile to which
1402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                   the sink wants to connect to.
1412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback A callback to indicate success or failure of the registration and
1422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               all operations done on this application configuration.
1432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerSinkAppConfiguration(String name, int dataType,
146fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
1472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || name == null) return false;
1482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
149563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
1502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return registerAppConfiguration(name, dataType, SINK_ROLE,
1512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                CHANNEL_TYPE_ANY, callback);
1522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Register an application configuration that acts as a Health SINK or in a Health
1562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * SOURCE role.This is an asynchronous call and so
1572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * the callback is used to notify success or failure if the function returns true.
1582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param name The friendly name associated with the application or configuration.
1622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param dataType The dataType of the Source role of Health Profile.
1632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param channelType The channel type. Will be one of
1642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_RELIABLE}  or
1652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *                              {@link #CHANNEL_TYPE_STREAMING}
1662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param callback - A callback to indicate success or failure.
1672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, callback will be called.
1682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
1692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
1702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean registerAppConfiguration(String name, int dataType, int role,
171fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            int channelType, BluetoothHealthCallback callback) {
1722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
1732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
1742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
175563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("registerApplication(" + name + ":" + dataType + ")");
176fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
1772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothHealthAppConfiguration config =
178fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
1792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null) {
1812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
182fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                result = mService.registerAppConfiguration(config, wrapper);
1832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
1842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
18513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
1862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
1872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
1882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
1892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
1902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
1912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
1922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
1932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
1942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Unregister an application configuration that has been registered using
1952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * {@link #registerSinkAppConfiguration}
1962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
1982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
1992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config  The health app configuration
2002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return Success or failure.
2012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
2032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        boolean result = false;
204fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        if (mService != null && isEnabled() && config != null) {
2052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                result = mService.unregisterAppConfiguration(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        }
214fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
2152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return result;
2162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
2172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
2192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Connect to a health device which has the {@link #SOURCE_ROLE}.
220fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
226fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
227fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
2282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSource(BluetoothDevice device,
2312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
2322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
233fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSource(device, config);
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     * Connect to a health device which has the {@link #SINK_ROLE}.
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) }
2562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @hide
2582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSink(BluetoothDevice device,
2602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelType) {
2612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
262fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
2642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.connectChannelToSink(device, config, channelType);
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     * Disconnect a connected health channel.
2772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is an asynchronous call. If this function returns true, the callback
2782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * associated with the application configuration will be called.
2792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
2812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
2822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth device.
283fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     * @param config The application configuration which has been registered using
284fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
285eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * @param channelId The channel id associated with the channel
2862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return If true, the callback associated with the application config will be called.
2872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
2882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean disconnectChannel(BluetoothDevice device,
289eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelId) {
2902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
291fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
2922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
293eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                return mService.disconnectChannel(device, config, channelId);
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 false;
3022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the file descriptor of the main channel associated with the remote device
3062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * and application configuration.
3072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
310eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
311eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * when done.
312eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     *
3132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device The remote Bluetooth health device
3142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param config The application configuration
3152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return null on failure, ParcelFileDescriptor on success.
3162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
3172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
3182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
3192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device) &&
320fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                config != null) {
3212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getMainChannelFd(device, config);
3232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
32513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return null;
3312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get the current connection state of the profile.
3352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter with the remote device. This can be used
3402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param device Remote bluetooth device.
3442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return State of the profile connection. One of
3452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
3462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
3472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
348fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public int getConnectionState(BluetoothDevice device) {
3502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled() && isValidDevice(device)) {
3512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDeviceConnectionState(device);
3532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, e.toString());
35513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        } else {
3572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            Log.w(TAG, "Proxy not attached to service");
3582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
3592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return STATE_DISCONNECTED;
3612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
364eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh     * Get connected devices for the health profile.
3652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
3672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
3722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
3732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
3742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
3752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
376fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
3772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getConnectedDevices() {
3782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
3792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
3802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getConnectedHealthDevices();
3812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
3822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
3832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return new ArrayList<BluetoothDevice>();
38413450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
3852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
3862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
3872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return new ArrayList<BluetoothDevice>();
3882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
3892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
3902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
3912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Get a list of devices that match any of the given connection
3922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * states.
3932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p> If none of the devices match any of the given states,
3952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * an empty list will be returned.
3962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
3972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
3982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * This is not specific to any application configuration but represents the connection
3992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * state of the local Bluetooth adapter for this profile. This can be used
4002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * by applications like status bar which would just like to know the state of the
4012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * local adapter.
4022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *
4032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @param states Array of states. States can be one of
4042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
4052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
4062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * @return List of devices. The list will be empty on error.
4072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
408fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    @Override
4092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
4102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService != null && isEnabled()) {
4112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            try {
4122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mService.getHealthDevicesMatchingConnectionStates(states);
4132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            } catch (RemoteException e) {
4142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
4152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return new ArrayList<BluetoothDevice>();
41613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
4172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
4182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (mService == null) Log.w(TAG, "Proxy not attached to service");
4192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return new ArrayList<BluetoothDevice>();
4202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
422fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
423fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        private BluetoothHealthCallback mCallback;
424fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
425fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
426fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            mCallback = callback;
427fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
428fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
429fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
430fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
431fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                                         int status) {
432eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh           mCallback.onHealthAppConfigurationStatusChange(config, status);
433fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
434fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
435fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        @Override
436fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
437fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                       BluetoothDevice device, int prevState, int newState,
438eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                       ParcelFileDescriptor fd, int channelId) {
439eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
440eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh                                                 channelId);
441fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh        }
442fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    }
443fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
4442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     /** Health Channel Connection State - Disconnected */
4452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTED  = 0;
4462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connecting */
4472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTING    = 1;
4482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Connected */
4492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_CONNECTED     = 2;
4502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health Channel Connection State - Disconnecting */
4512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public static final int STATE_CHANNEL_DISCONNECTING = 3;
4522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration success */
454eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
4552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration registration failure */
456eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
4572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration success */
458eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
4592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /** Health App Configuration un-registration failure */
460eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh    public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
4612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
46213450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private Context mContext;
4632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private ServiceListener mServiceListener;
46413450df2b9264ef2220418f308037c19cec739a9Matthew Xie    private IBluetoothHealth mService;
4652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    BluetoothAdapter mAdapter;
4662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**
4682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     * Create a BluetoothHealth proxy object.
4692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh     */
47013450df2b9264ef2220418f308037c19cec739a9Matthew Xie    /*package*/ BluetoothHealth(Context context, ServiceListener l) {
47113450df2b9264ef2220418f308037c19cec739a9Matthew Xie        mContext = context;
4722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mServiceListener = l;
4732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mAdapter = BluetoothAdapter.getDefaultAdapter();
4740f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
4750f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
4760f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
4770f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
4780f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (RemoteException e) {
4790f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
4800f42037eb7b5118015c2caca635538324ccf0ccffredc            }
4810f42037eb7b5118015c2caca635538324ccf0ccffredc        }
4820f42037eb7b5118015c2caca635538324ccf0ccffredc
483221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        doBind();
484221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    }
485221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn
486221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn    boolean doBind() {
487221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        Intent intent = new Intent(IBluetoothHealth.class.getName());
488221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
489221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        intent.setComponent(comp);
490466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
491466ce96da8ca7ea8c97e716b02a7d55007179aa1Dianne Hackborn                android.os.Process.myUserHandle())) {
492221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
493221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn            return false;
4942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
495221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn        return true;
4962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
4972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
4989bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    /*package*/ void close() {
499563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie        if (VDBG) log("close()");
5000f42037eb7b5118015c2caca635538324ccf0ccffredc        IBluetoothManager mgr = mAdapter.getBluetoothManager();
5010f42037eb7b5118015c2caca635538324ccf0ccffredc        if (mgr != null) {
5020f42037eb7b5118015c2caca635538324ccf0ccffredc            try {
5030f42037eb7b5118015c2caca635538324ccf0ccffredc                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
5040f42037eb7b5118015c2caca635538324ccf0ccffredc            } catch (Exception e) {
5050f42037eb7b5118015c2caca635538324ccf0ccffredc                Log.e(TAG,"",e);
5060f42037eb7b5118015c2caca635538324ccf0ccffredc            }
5070f42037eb7b5118015c2caca635538324ccf0ccffredc        }
5080f42037eb7b5118015c2caca635538324ccf0ccffredc
5090f42037eb7b5118015c2caca635538324ccf0ccffredc        synchronized (mConnection) {
5100f42037eb7b5118015c2caca635538324ccf0ccffredc            if (mService != null) {
5110f42037eb7b5118015c2caca635538324ccf0ccffredc                try {
5120f42037eb7b5118015c2caca635538324ccf0ccffredc                    mService = null;
5130f42037eb7b5118015c2caca635538324ccf0ccffredc                    mContext.unbindService(mConnection);
5140f42037eb7b5118015c2caca635538324ccf0ccffredc                } catch (Exception re) {
5150f42037eb7b5118015c2caca635538324ccf0ccffredc                    Log.e(TAG,"",re);
5160f42037eb7b5118015c2caca635538324ccf0ccffredc                }
5170f42037eb7b5118015c2caca635538324ccf0ccffredc            }
51813450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
5199bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        mServiceListener = null;
5209bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh    }
5219bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
5229b6939939901cb82bc6fca93aad3810a4936dfc6Matthew Xie    private final ServiceConnection mConnection = new ServiceConnection() {
52313450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceConnected(ComponentName className, IBinder service) {
52413450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object connected");
52513450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = IBluetoothHealth.Stub.asInterface(service);
52613450df2b9264ef2220418f308037c19cec739a9Matthew Xie
52713450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
52813450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
52913450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
53013450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
53113450df2b9264ef2220418f308037c19cec739a9Matthew Xie        public void onServiceDisconnected(ComponentName className) {
53213450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (DBG) Log.d(TAG, "Proxy object disconnected");
53313450df2b9264ef2220418f308037c19cec739a9Matthew Xie            mService = null;
53413450df2b9264ef2220418f308037c19cec739a9Matthew Xie            if (mServiceListener != null) {
53513450df2b9264ef2220418f308037c19cec739a9Matthew Xie                mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
53613450df2b9264ef2220418f308037c19cec739a9Matthew Xie            }
53713450df2b9264ef2220418f308037c19cec739a9Matthew Xie        }
53813450df2b9264ef2220418f308037c19cec739a9Matthew Xie    };
53913450df2b9264ef2220418f308037c19cec739a9Matthew Xie
5402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isEnabled() {
5412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
5422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
5442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        log("Bluetooth is Not enabled");
5452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
5462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean isValidDevice(BluetoothDevice device) {
5492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (device == null) return false;
5502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
5522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return false;
5532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private boolean checkAppParam(String name, int role, int channelType,
556fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh            BluetoothHealthCallback callback) {
5572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
5582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                (channelType != CHANNEL_TYPE_RELIABLE &&
5592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_STREAMING &&
5602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                channelType != CHANNEL_TYPE_ANY) || callback == null) {
5612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return false;
5622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
5632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
5642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        return true;
5652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
5672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private static void log(String msg) {
5682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        Log.d(TAG, msg);
5692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
5702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh}
571