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..."); 120221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn doBind(); 1210f42037eb7b5118015c2caca635538324ccf0ccffredc } 1220f42037eb7b5118015c2caca635538324ccf0ccffredc } catch (Exception re) { 1230f42037eb7b5118015c2caca635538324ccf0ccffredc Log.e(TAG,"",re); 1240f42037eb7b5118015c2caca635538324ccf0ccffredc } 1250f42037eb7b5118015c2caca635538324ccf0ccffredc } 1260f42037eb7b5118015c2caca635538324ccf0ccffredc } 1270f42037eb7b5118015c2caca635538324ccf0ccffredc } 1280f42037eb7b5118015c2caca635538324ccf0ccffredc }; 1290f42037eb7b5118015c2caca635538324ccf0ccffredc 130b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh 1312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 1322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Register an application configuration that acts as a Health SINK. 1332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is the configuration that will be used to communicate with health devices 1342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so 1352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * the callback is used to notify success or failure if the function returns true. 1362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 1372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 1382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 1392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param name The friendly name associated with the application or configuration. 1402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param dataType The dataType of the Source role of Health Profile to which 1412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * the sink wants to connect to. 1422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param callback A callback to indicate success or failure of the registration and 1432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * all operations done on this application configuration. 1442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return If true, callback will be called. 1452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 1462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean registerSinkAppConfiguration(String name, int dataType, 147fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh BluetoothHealthCallback callback) { 1482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (!isEnabled() || name == null) return false; 1492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 150563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")"); 1512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return registerAppConfiguration(name, dataType, SINK_ROLE, 1522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh CHANNEL_TYPE_ANY, callback); 1532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 1542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 1552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 1562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Register an application configuration that acts as a Health SINK or in a Health 1572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * SOURCE role.This is an asynchronous call and so 1582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * the callback is used to notify success or failure if the function returns true. 1592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 1602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 1612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 1622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param name The friendly name associated with the application or configuration. 1632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param dataType The dataType of the Source role of Health Profile. 1642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param channelType The channel type. Will be one of 1652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #CHANNEL_TYPE_RELIABLE} or 1662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #CHANNEL_TYPE_STREAMING} 1672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param callback - A callback to indicate success or failure. 1682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return If true, callback will be called. 1692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @hide 1702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 1712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean registerAppConfiguration(String name, int dataType, int role, 172fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh int channelType, BluetoothHealthCallback callback) { 1732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh boolean result = false; 1742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result; 1752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 176563e414784eb81e4ea4051667d5c8855b17f7534Matthew Xie if (VDBG) log("registerApplication(" + name + ":" + dataType + ")"); 177fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback); 1782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh BluetoothHealthAppConfiguration config = 179fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh new BluetoothHealthAppConfiguration(name, dataType, role, channelType); 1802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 1812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null) { 1822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 183fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh result = mService.registerAppConfiguration(config, wrapper); 1842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 1852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 18613450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 1872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 1882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 1892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 1902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 1912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return result; 1922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 1932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 1942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 1952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Unregister an application configuration that has been registered using 1962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #registerSinkAppConfiguration} 1972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 1982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 1992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param config The health app configuration 2012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return Success or failure. 2022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 2032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 2042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh boolean result = false; 205fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh if (mService != null && isEnabled() && config != null) { 2062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 2072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh result = mService.unregisterAppConfiguration(config); 2082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 2092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 21013450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 2112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 2122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 2132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 2142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 215fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh 2162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return result; 2172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 2182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 2192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 2202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Connect to a health device which has the {@link #SOURCE_ROLE}. 221fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * This is an asynchronous call. If this function returns true, the callback 2222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * associated with the application configuration will be called. 2232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 2252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param device The remote Bluetooth device. 227fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * @param config The application configuration which has been registered using 228fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } 2292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return If true, the callback associated with the application config will be called. 2302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 2312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean connectChannelToSource(BluetoothDevice device, 2322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh BluetoothHealthAppConfiguration config) { 2332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled() && isValidDevice(device) && 234fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh config != null) { 2352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 2362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.connectChannelToSource(device, config); 2372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 2382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 23913450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 2402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 2412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 2422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 2432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 2442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return false; 2452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 2462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 2472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 2482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Connect to a health device which has the {@link #SINK_ROLE}. 2492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is an asynchronous call. If this function returns true, the callback 2502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * associated with the application configuration will be called. 2512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 2532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param device The remote Bluetooth device. 255fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * @param config The application configuration which has been registered using 256fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } 2572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return If true, the callback associated with the application config will be called. 2582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @hide 2592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 2602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean connectChannelToSink(BluetoothDevice device, 2612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh BluetoothHealthAppConfiguration config, int channelType) { 2622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled() && isValidDevice(device) && 263fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh config != null) { 2642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 2652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.connectChannelToSink(device, config, channelType); 2662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 2672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 26813450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 2692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 2702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 2712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 2722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 2732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return false; 2742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 2752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 2762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 2772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Disconnect a connected health channel. 2782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is an asynchronous call. If this function returns true, the callback 2792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * associated with the application configuration will be called. 2802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 2822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 2832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param device The remote Bluetooth device. 284fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * @param config The application configuration which has been registered using 285fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) } 286eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * @param channelId The channel id associated with the channel 2872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return If true, the callback associated with the application config will be called. 2882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 2892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public boolean disconnectChannel(BluetoothDevice device, 290eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh BluetoothHealthAppConfiguration config, int channelId) { 2912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled() && isValidDevice(device) && 292fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh config != null) { 2932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 294eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh return mService.disconnectChannel(device, config, channelId); 2952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 2962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 29713450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 2982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 2992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 3002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 3012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return false; 3032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 3052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 3062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Get the file descriptor of the main channel associated with the remote device 3072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * and application configuration. 3082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 3102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 311eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * <p> Its the responsibility of the caller to close the ParcelFileDescriptor 312eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * when done. 313eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * 3142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param device The remote Bluetooth health device 3152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param config The application configuration 3162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return null on failure, ParcelFileDescriptor on success. 3172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 3182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 3192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh BluetoothHealthAppConfiguration config) { 3202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled() && isValidDevice(device) && 321fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh config != null) { 3222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 3232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.getMainChannelFd(device, config); 3242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 3252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 32613450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 3272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 3282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 3292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 3302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return null; 3322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 3342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 3352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Get the current connection state of the profile. 3362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 3382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is not specific to any application configuration but represents the connection 3402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * state of the local Bluetooth adapter with the remote device. This can be used 3412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * by applications like status bar which would just like to know the state of the 3422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * local adapter. 3432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param device Remote bluetooth device. 3452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return State of the profile connection. One of 3462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING}, 3472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING} 3482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 349fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh @Override 3502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public int getConnectionState(BluetoothDevice device) { 3512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled() && isValidDevice(device)) { 3522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 3532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.getHealthDeviceConnectionState(device); 3542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 3552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, e.toString()); 35613450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 3572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } else { 3582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.w(TAG, "Proxy not attached to service"); 3592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable())); 3602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return STATE_DISCONNECTED; 3622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 3642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 365eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh * Get connected devices for the health profile. 3662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p> Return the set of devices which are in state {@link #STATE_CONNECTED} 3682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 3702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is not specific to any application configuration but represents the connection 3722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * state of the local Bluetooth adapter for this profile. This can be used 3732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * by applications like status bar which would just like to know the state of the 3742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * local adapter. 3752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return List of devices. The list will be empty on error. 3762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 377fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh @Override 3782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public List<BluetoothDevice> getConnectedDevices() { 3792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled()) { 3802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 3812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.getConnectedHealthDevices(); 3822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 3832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 3842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return new ArrayList<BluetoothDevice>(); 38513450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 3862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService == null) Log.w(TAG, "Proxy not attached to service"); 3882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return new ArrayList<BluetoothDevice>(); 3892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 3902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 3912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 3922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Get a list of devices that match any of the given connection 3932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * states. 3942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p> If none of the devices match any of the given states, 3962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * an empty list will be returned. 3972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 3982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. 3992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * This is not specific to any application configuration but represents the connection 4002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * state of the local Bluetooth adapter for this profile. This can be used 4012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * by applications like status bar which would just like to know the state of the 4022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * local adapter. 4032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * 4042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @param states Array of states. States can be one of 4052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING}, 4062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}, 4072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * @return List of devices. The list will be empty on error. 4082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 409fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh @Override 4102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 4112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService != null && isEnabled()) { 4122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh try { 4132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return mService.getHealthDevicesMatchingConnectionStates(states); 4142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } catch (RemoteException e) { 4152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 4162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return new ArrayList<BluetoothDevice>(); 41713450df2b9264ef2220418f308037c19cec739a9Matthew Xie } 4182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 4192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh if (mService == null) Log.w(TAG, "Proxy not attached to service"); 4202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh return new ArrayList<BluetoothDevice>(); 4212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh } 4222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 423fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub { 424fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh private BluetoothHealthCallback mCallback; 425fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh 426fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) { 427fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh mCallback = callback; 428fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh } 429fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh 430fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh @Override 431fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config, 432fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh int status) { 433eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh mCallback.onHealthAppConfigurationStatusChange(config, status); 434fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh } 435fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh 436fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh @Override 437fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config, 438fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh BluetoothDevice device, int prevState, int newState, 439eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh ParcelFileDescriptor fd, int channelId) { 440eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd, 441eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh channelId); 442fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh } 443fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh } 444fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh 4452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health Channel Connection State - Disconnected */ 4462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public static final int STATE_CHANNEL_DISCONNECTED = 0; 4472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health Channel Connection State - Connecting */ 4482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public static final int STATE_CHANNEL_CONNECTING = 1; 4492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health Channel Connection State - Connected */ 4502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public static final int STATE_CHANNEL_CONNECTED = 2; 4512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health Channel Connection State - Disconnecting */ 4522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh public static final int STATE_CHANNEL_DISCONNECTING = 3; 4532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 4542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health App Configuration registration success */ 455eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0; 4562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health App Configuration registration failure */ 457eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh public static final int APP_CONFIG_REGISTRATION_FAILURE = 1; 4582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health App Configuration un-registration success */ 459eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2; 4602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** Health App Configuration un-registration failure */ 461eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3; 4622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 46313450df2b9264ef2220418f308037c19cec739a9Matthew Xie private Context mContext; 4642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh private ServiceListener mServiceListener; 46513450df2b9264ef2220418f308037c19cec739a9Matthew Xie private IBluetoothHealth mService; 4662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh BluetoothAdapter mAdapter; 4672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh 4682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh /** 4692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh * Create a BluetoothHealth proxy object. 4702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh */ 47113450df2b9264ef2220418f308037c19cec739a9Matthew Xie /*package*/ BluetoothHealth(Context context, ServiceListener l) { 47213450df2b9264ef2220418f308037c19cec739a9Matthew Xie mContext = context; 4732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh mServiceListener = l; 4742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh mAdapter = BluetoothAdapter.getDefaultAdapter(); 4750f42037eb7b5118015c2caca635538324ccf0ccffredc IBluetoothManager mgr = mAdapter.getBluetoothManager(); 4760f42037eb7b5118015c2caca635538324ccf0ccffredc if (mgr != null) { 4770f42037eb7b5118015c2caca635538324ccf0ccffredc try { 4780f42037eb7b5118015c2caca635538324ccf0ccffredc mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); 4790f42037eb7b5118015c2caca635538324ccf0ccffredc } catch (RemoteException e) { 4800f42037eb7b5118015c2caca635538324ccf0ccffredc Log.e(TAG,"",e); 4810f42037eb7b5118015c2caca635538324ccf0ccffredc } 4820f42037eb7b5118015c2caca635538324ccf0ccffredc } 4830f42037eb7b5118015c2caca635538324ccf0ccffredc 484221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn doBind(); 485221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn } 486221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn 487221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn boolean doBind() { 488221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn Intent intent = new Intent(IBluetoothHealth.class.getName()); 489221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); 490221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn intent.setComponent(comp); 491221ea892dcc661bd07d6f36ff012edca2c48aed4Dianne Hackborn if (comp == null || !mContext.bindService(intent, mConnection, 0)) { 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