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