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