1676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie/* 2ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Copyright (C) 2012 The Android Open Source Project 3ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 4ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * you may not use this file except in compliance with the License. 6ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * You may obtain a copy of the License at 7ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 8ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 10ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Unless required by applicable law or agreed to in writing, software 11ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * See the License for the specific language governing permissions and 14ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * limitations under the License. 15676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 16676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 17676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xiepackage com.android.bluetooth.hdp; 18676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 19676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.BluetoothDevice; 20676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.BluetoothHealth; 21676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.BluetoothHealthAppConfiguration; 22676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.BluetoothProfile; 23676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.IBluetoothHealth; 24676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.IBluetoothHealthCallback; 25676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.content.Intent; 26676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.Handler; 27676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.HandlerThread; 28755aa8f5359a933205552c40b6446b001ae42378Priti Agheraimport android.os.IBinder; 29755aa8f5359a933205552c40b6446b001ae42378Priti Agheraimport android.os.IBinder.DeathRecipient; 3037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.os.Looper; 3137510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.os.Message; 32676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.ParcelFileDescriptor; 33676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.RemoteException; 34676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.util.Log; 3537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService; 3637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; 3737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils; 38676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.io.FileDescriptor; 39676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.io.IOException; 40676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.ArrayList; 41676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Collections; 42676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.HashMap; 438629665794ef845e945595040e4cf1ea2fa508d3Priti Agheraimport java.util.Iterator; 44676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.List; 45676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Map; 46676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Map.Entry; 4737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport java.util.NoSuchElementException; 4837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 49676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 50676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie/** 51676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Provides Bluetooth Health Device profile, as a service in 52676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * the Bluetooth application. 53676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @hide 54676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 55b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class HealthService extends ProfileService { 568629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera private static final boolean DBG = true; 578629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera private static final boolean VDBG = false; 58b5cc776c9353a203cdde97e62b25f05d9633d14cfredc private static final String TAG="HealthService"; 5974ae04c73312403e89db0f8e9bd9601d403b4783fredc 60676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private List<HealthChannel> mHealthChannels; 61676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private Map <BluetoothHealthAppConfiguration, AppInfo> mApps; 62676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private Map <BluetoothDevice, Integer> mHealthDevices; 6374ae04c73312403e89db0f8e9bd9601d403b4783fredc private boolean mNativeAvailable; 64676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthServiceMessageHandler mHandler; 65676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_REGISTER_APPLICATION = 1; 66676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_UNREGISTER_APPLICATION = 2; 67676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_CONNECT_CHANNEL = 3; 68676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_DISCONNECT_CHANNEL = 4; 69676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_APP_REGISTRATION_CALLBACK = 11; 70676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_CHANNEL_STATE_CALLBACK = 12; 71676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 72676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie static { 73676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie classInitNative(); 74676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 75676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 76b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected String getName() { 77b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return TAG; 78676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 79676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 8074ae04c73312403e89db0f8e9bd9601d403b4783fredc protected IProfileServiceBinder initBinder() { 8174ae04c73312403e89db0f8e9bd9601d403b4783fredc return new BluetoothHealthBinder(this); 82676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 83676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 84b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean start() { 856654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHealthChannels = Collections.synchronizedList(new ArrayList<HealthChannel>()); 866654f5c903de510a70f9e72cd5ad7837b615d93ffredc mApps = Collections.synchronizedMap(new HashMap<BluetoothHealthAppConfiguration, 876654f5c903de510a70f9e72cd5ad7837b615d93ffredc AppInfo>()); 886654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHealthDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>()); 896654f5c903de510a70f9e72cd5ad7837b615d93ffredc 906654f5c903de510a70f9e72cd5ad7837b615d93ffredc HandlerThread thread = new HandlerThread("BluetoothHdpHandler"); 916654f5c903de510a70f9e72cd5ad7837b615d93ffredc thread.start(); 926654f5c903de510a70f9e72cd5ad7837b615d93ffredc Looper looper = thread.getLooper(); 936654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHandler = new HealthServiceMessageHandler(looper); 946654f5c903de510a70f9e72cd5ad7837b615d93ffredc initializeNative(); 9574ae04c73312403e89db0f8e9bd9601d403b4783fredc mNativeAvailable=true; 96b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 976654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 986654f5c903de510a70f9e72cd5ad7837b615d93ffredc 99b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean stop() { 10062fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie if (mHandler != null) { 10162fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie mHandler.removeCallbacksAndMessages(null); 10262fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie Looper looper = mHandler.getLooper(); 10362fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie if (looper != null) { 10462fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie looper.quit(); 10562fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie } 1066654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 107755aa8f5359a933205552c40b6446b001ae42378Priti Aghera cleanupApps(); 10874ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 10974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1106654f5c903de510a70f9e72cd5ad7837b615d93ffredc 111755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private void cleanupApps(){ 112f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava if (mApps != null) { 113eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen Iterator<Map.Entry<BluetoothHealthAppConfiguration,AppInfo>> it 114f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava = mApps.entrySet().iterator(); 115f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava while (it.hasNext()) { 116eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen Map.Entry<BluetoothHealthAppConfiguration,AppInfo> entry = it.next(); 117f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava AppInfo appInfo = entry.getValue(); 118f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava if (appInfo != null) 119f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava appInfo.cleanup(); 120f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava it.remove(); 121f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava } 122755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 123755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 12474ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean cleanup() { 12574ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler = null; 1266654f5c903de510a70f9e72cd5ad7837b615d93ffredc //Cleanup native 12774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mNativeAvailable) { 12874ae04c73312403e89db0f8e9bd9601d403b4783fredc cleanupNative(); 12974ae04c73312403e89db0f8e9bd9601d403b4783fredc mNativeAvailable=false; 13074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 131b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mHealthChannels != null) { 132b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mHealthChannels.clear(); 133b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 134b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mHealthDevices != null) { 135b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mHealthDevices.clear(); 1366654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 137b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mApps != null) { 138b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mApps.clear(); 139b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 140b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 141676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 142676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 143676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private final class HealthServiceMessageHandler extends Handler { 144676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthServiceMessageHandler(Looper looper) { 145676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie super(looper); 146676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 147676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 148676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie @Override 149676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public void handleMessage(Message msg) { 1508629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (DBG) log("HealthService Handler msg: " + msg.what); 151676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (msg.what) { 152676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_REGISTER_APPLICATION: 153676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 154676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = 155676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie (BluetoothHealthAppConfiguration) msg.obj; 156755aa8f5359a933205552c40b6446b001ae42378Priti Aghera AppInfo appInfo = mApps.get(appConfig); 157755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if (appInfo == null) break; 158676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int halRole = convertRoleToHal(appConfig.getRole()); 159676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int halChannelType = convertChannelTypeToHal(appConfig.getChannelType()); 1608629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (VDBG) log("register datatype: " + appConfig.getDataType() + " role: " + 161676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie halRole + " name: " + appConfig.getName() + " channeltype: " + 162676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie halChannelType); 163676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = registerHealthAppNative(appConfig.getDataType(), halRole, 164676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie appConfig.getName(), halChannelType); 165676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appId == -1) { 166676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 167676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE); 168755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.cleanup(); 169676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mApps.remove(appConfig); 170676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 171755aa8f5359a933205552c40b6446b001ae42378Priti Aghera //link to death with a recipient object to implement binderDead() 172755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.mRcpObj = new BluetoothHealthDeathRecipient(HealthService.this,appConfig); 173755aa8f5359a933205552c40b6446b001ae42378Priti Aghera IBinder binder = appInfo.mCallback.asBinder(); 174755aa8f5359a933205552c40b6446b001ae42378Priti Aghera try { 175755aa8f5359a933205552c40b6446b001ae42378Priti Aghera binder.linkToDeath(appInfo.mRcpObj,0); 176755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } catch (RemoteException e) { 177755aa8f5359a933205552c40b6446b001ae42378Priti Aghera Log.e(TAG,"LinktoDeath Exception:"+e); 178755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 179755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.mAppId = appId; 180676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 181676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS); 182676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 183676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 184676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 185676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_UNREGISTER_APPLICATION: 186676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 187676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = 188676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie (BluetoothHealthAppConfiguration) msg.obj; 189676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = (mApps.get(appConfig)).mAppId; 190676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (!unregisterHealthAppNative(appId)) { 191676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Failed to unregister application: id: " + appId); 192676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 193676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE); 194676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 195676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 196676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 197676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_CONNECT_CHANNEL: 198676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 199676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = (HealthChannel) msg.obj; 20074ae04c73312403e89db0f8e9bd9601d403b4783fredc byte[] devAddr = Utils.getByteAddress(chan.mDevice); 201676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = (mApps.get(chan.mConfig)).mAppId; 202676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelId = connectChannelNative(devAddr, appId); 203676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mChannelId == -1) { 204676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 205676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 206676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTED, 207676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 208676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 209676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTED, 210676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 211676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 212676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 213676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 214676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 215676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_DISCONNECT_CHANNEL: 216676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 217676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = (HealthChannel) msg.obj; 218676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (!disconnectChannelNative(chan.mChannelId)) { 219676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 220676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 221676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED, 222676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 223676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 224676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED, 225676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 226676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 227676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 228676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 229676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 230676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_APP_REGISTRATION_CALLBACK: 231676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 232676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = findAppConfigByAppId(msg.arg1); 233676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appConfig == null) break; 234676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 235676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int regStatus = convertHalRegStatus(msg.arg2); 236676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, regStatus); 237676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (regStatus == BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE || 238676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie regStatus == BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS) { 239755aa8f5359a933205552c40b6446b001ae42378Priti Aghera //unlink to death once app is unregistered 240755aa8f5359a933205552c40b6446b001ae42378Priti Aghera AppInfo appInfo = mApps.get(appConfig); 241755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.cleanup(); 242676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mApps.remove(appConfig); 243676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 2448629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera } 245676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 246676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_CHANNEL_STATE_CALLBACK: 247676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 248676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ChannelStateEvent channelStateEvent = (ChannelStateEvent) msg.obj; 249676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = findChannelById(channelStateEvent.mChannelId); 2508629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera BluetoothHealthAppConfiguration appConfig = 2518629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera findAppConfigByAppId(channelStateEvent.mAppId); 252676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int newState; 2538629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera newState = convertHalChannelState(channelStateEvent.mState); 2548629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (newState == BluetoothHealth.STATE_CHANNEL_DISCONNECTED && 2558629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera appConfig == null) { 2568629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera Log.e(TAG,"Disconnected for non existing app"); 2578629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera break; 2588629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera } 259676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan == null) { 260676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // incoming connection 2618629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera 262676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothDevice device = getDevice(channelStateEvent.mAddr); 263676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = new HealthChannel(device, appConfig, appConfig.getChannelType()); 264676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelId = channelStateEvent.mChannelId; 265970baea8e58a7b537e76e8bcbba34f428cede061Priti Aghera mHealthChannels.add(chan); 266676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 267676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie newState = convertHalChannelState(channelStateEvent.mState); 268676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newState == BluetoothHealth.STATE_CHANNEL_CONNECTED) { 269676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 270676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd = ParcelFileDescriptor.dup(channelStateEvent.mFd); 271676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (IOException e) { 272676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "failed to dup ParcelFileDescriptor"); 273676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 274676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 275676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 27681491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera /*set the channel fd to null if channel state isnot equal to connected*/ 27781491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera else{ 27881491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera chan.mChannelFd = null; 27981491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera } 280676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, newState, 281676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mState, chan.mChannelFd, chan.mChannelId); 282676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mState = newState; 283676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelStateEvent.mState == CONN_STATE_DESTROYED) { 284676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthChannels.remove(chan); 285676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 286676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 287676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 288676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 289676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 290676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 291676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 292755aa8f5359a933205552c40b6446b001ae42378Priti Aghera//Handler for DeathReceipient 293755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private static class BluetoothHealthDeathRecipient implements IBinder.DeathRecipient{ 294755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private BluetoothHealthAppConfiguration mConfig; 295755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private HealthService mService; 296755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 297755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public BluetoothHealthDeathRecipient(HealthService service, BluetoothHealthAppConfiguration config) { 298755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService = service; 299755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mConfig = config; 300755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 301755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 302755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public void binderDied() { 3038629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (DBG) Log.d(TAG,"Binder is dead."); 304755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService.unregisterAppConfiguration(mConfig); 305755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 306755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 307755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public void cleanup(){ 308755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService = null; 309755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mConfig = null; 310755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 311755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 312755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 313676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 314676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Handlers for incoming service calls 315676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 31674ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class BluetoothHealthBinder extends IBluetoothHealth.Stub implements IProfileServiceBinder { 31774ae04c73312403e89db0f8e9bd9601d403b4783fredc private HealthService mService; 31874ae04c73312403e89db0f8e9bd9601d403b4783fredc 31974ae04c73312403e89db0f8e9bd9601d403b4783fredc public BluetoothHealthBinder(HealthService svc) { 32074ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = svc; 32174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 32274ae04c73312403e89db0f8e9bd9601d403b4783fredc 32374ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean cleanup() { 32474ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = null; 325676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return true; 326676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 327676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 32874ae04c73312403e89db0f8e9bd9601d403b4783fredc private HealthService getService() { 32937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu if (!Utils.checkCaller()) { 33037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu Log.w(TAG,"Health call not allowed for non-active user"); 33137510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu return null; 33237510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu } 33337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 33474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mService != null && mService.isAvailable()) { 33574ae04c73312403e89db0f8e9bd9601d403b4783fredc return mService; 336676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 33774ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 33874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 339676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 34074ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config, 34174ae04c73312403e89db0f8e9bd9601d403b4783fredc IBluetoothHealthCallback callback) { 34274ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 34374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 34474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.registerAppConfiguration(config, callback); 34574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34674ae04c73312403e89db0f8e9bd9601d403b4783fredc 34774ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 34874ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 34974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 35074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.unregisterAppConfiguration(config); 351676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 352676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 353676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean connectChannelToSource(BluetoothDevice device, 354676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config) { 35574ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 35674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 35774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectChannelToSource(device, config); 358676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 359676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 360676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean connectChannelToSink(BluetoothDevice device, 361676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelType) { 36274ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 36374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 36474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectChannelToSink(device, config, channelType); 365676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 366676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 367676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean disconnectChannel(BluetoothDevice device, 368676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelId) { 36974ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 37074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 37174ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnectChannel(device, config, channelId); 372676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 373676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 374676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 375676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config) { 37674ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 37774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return null; 37874ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getMainChannelFd(device, config); 379676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 380676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 381676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public int getHealthDeviceConnectionState(BluetoothDevice device) { 38274ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 38374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothHealth.STATE_DISCONNECTED; 38474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getHealthDeviceConnectionState(device); 385676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 386676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 387676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public List<BluetoothDevice> getConnectedHealthDevices() { 38874ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 38974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice> (0); 39074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectedHealthDevices(); 391676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 392676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 393676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(int[] states) { 39474ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 39574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice> (0); 39674ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getHealthDevicesMatchingConnectionStates(states); 397676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 398676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie }; 399676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 40074ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean registerAppConfiguration(BluetoothHealthAppConfiguration config, 40174ae04c73312403e89db0f8e9bd9601d403b4783fredc IBluetoothHealthCallback callback) { 40274ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, 40374ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH permission"); 404abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker 405abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker if (config == null) { 406abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker Log.e(TAG, "Trying to use a null config for registration"); 407abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker return false; 408abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker } 409abc538d128b495c2c05ba0a69f7c502354a06d40Ajay Panicker 41074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mApps.get(config) != null) { 41174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG, "Config has already been registered"); 41274ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 41374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41474ae04c73312403e89db0f8e9bd9601d403b4783fredc mApps.put(config, new AppInfo(callback)); 41574ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_APPLICATION,config); 41674ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 41774ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 41874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41974ae04c73312403e89db0f8e9bd9601d403b4783fredc 42074ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 42174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 42274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mApps.get(config) == null) { 42374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG,"unregisterAppConfiguration: no app found"); 42474ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 42574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42674ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_APPLICATION,config); 42774ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 42874ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 42974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43074ae04c73312403e89db0f8e9bd9601d403b4783fredc 43174ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectChannelToSource(BluetoothDevice device, 43274ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config) { 43374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 43474ae04c73312403e89db0f8e9bd9601d403b4783fredc return connectChannel(device, config, BluetoothHealth.CHANNEL_TYPE_ANY); 43574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43674ae04c73312403e89db0f8e9bd9601d403b4783fredc 43774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectChannelToSink(BluetoothDevice device, 43874ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config, int channelType) { 43974ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 44074ae04c73312403e89db0f8e9bd9601d403b4783fredc return connectChannel(device, config, channelType); 44174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44274ae04c73312403e89db0f8e9bd9601d403b4783fredc 44374ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnectChannel(BluetoothDevice device, 44474ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config, int channelId) { 44574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 44674ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthChannel chan = findChannelById(channelId); 44774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (chan == null) { 44874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG,"disconnectChannel: no channel found"); 44974ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 45074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45174ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT_CHANNEL,chan); 45274ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 45374ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 45474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45574ae04c73312403e89db0f8e9bd9601d403b4783fredc 45674ae04c73312403e89db0f8e9bd9601d403b4783fredc ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 45774ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config) { 45874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 45974ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthChannel healthChan = null; 46074ae04c73312403e89db0f8e9bd9601d403b4783fredc for (HealthChannel chan: mHealthChannels) { 46174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (chan.mDevice.equals(device) && chan.mConfig.equals(config)) { 46274ae04c73312403e89db0f8e9bd9601d403b4783fredc healthChan = chan; 46374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (healthChan == null) { 46674ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.e(TAG, "No channel found for device: " + device + " config: " + config); 46774ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 46874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46974ae04c73312403e89db0f8e9bd9601d403b4783fredc return healthChan.mChannelFd; 47074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47174ae04c73312403e89db0f8e9bd9601d403b4783fredc 47274ae04c73312403e89db0f8e9bd9601d403b4783fredc int getHealthDeviceConnectionState(BluetoothDevice device) { 47374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 47474ae04c73312403e89db0f8e9bd9601d403b4783fredc return getConnectionState(device); 47574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47674ae04c73312403e89db0f8e9bd9601d403b4783fredc 47774ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> getConnectedHealthDevices() { 47874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 47974ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> devices = lookupHealthDevicesMatchingStates( 48074ae04c73312403e89db0f8e9bd9601d403b4783fredc new int[] {BluetoothHealth.STATE_CONNECTED}); 48174ae04c73312403e89db0f8e9bd9601d403b4783fredc return devices; 48274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48374ae04c73312403e89db0f8e9bd9601d403b4783fredc 48474ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(int[] states) { 48574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 48674ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> devices = lookupHealthDevicesMatchingStates(states); 48774ae04c73312403e89db0f8e9bd9601d403b4783fredc return devices; 48874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48974ae04c73312403e89db0f8e9bd9601d403b4783fredc 490676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void onAppRegistrationState(int appId, int state) { 491676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_APP_REGISTRATION_CALLBACK); 492676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.arg1 = appId; 493676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.arg2 = state; 494676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 495676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 496676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 497676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void onChannelStateChanged(int appId, byte[] addr, int cfgIndex, 498676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelId, int state, FileDescriptor pfd) { 499676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_CHANNEL_STATE_CALLBACK); 500676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ChannelStateEvent channelStateEvent = new ChannelStateEvent(appId, addr, cfgIndex, 501676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie channelId, state, pfd); 502676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.obj = channelStateEvent; 503676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 504676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 505676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 506676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private String getStringChannelType(int type) { 507676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (type == BluetoothHealth.CHANNEL_TYPE_RELIABLE) { 508676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Reliable"; 509676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else if (type == BluetoothHealth.CHANNEL_TYPE_STREAMING) { 510676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Streaming"; 511676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 512676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Any"; 513676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 514676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 515676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 516676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void callStatusCallback(BluetoothHealthAppConfiguration config, int status) { 5178629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (VDBG) log ("Health Device Application: " + config + " State Change: status:" + status); 518676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie IBluetoothHealthCallback callback = (mApps.get(config)).mCallback; 519676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (callback == null) { 520676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Callback object null"); 521676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 522676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 523676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 524676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callback.onHealthAppConfigurationStatusChange(config, status); 525676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (RemoteException e) { 526676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Remote Exception:" + e); 527676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 528676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 529676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 530676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothHealthAppConfiguration findAppConfigByAppId(int appId) { 531676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = null; 532676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (Entry<BluetoothHealthAppConfiguration, AppInfo> e : mApps.entrySet()) { 533676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appId == (e.getValue()).mAppId) { 534676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie appConfig = e.getKey(); 535676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 536676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 537676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 538676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appConfig == null) { 539676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No appConfig found for " + appId); 540676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 541676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return appConfig; 542676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 543676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 544676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertHalRegStatus(int halRegStatus) { 545676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (halRegStatus) { 546676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_REG_SUCCESS: 547676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS; 548676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_REG_FAILED: 549676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE; 550676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_DEREG_SUCCESS: 551676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS; 552676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_DEREG_FAILED: 553676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE; 554676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 555676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Unexpected App Registration state: " + halRegStatus); 556676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE; 557676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 558676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 559676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertHalChannelState(int halChannelState) { 560676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (halChannelState) { 561676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_CONNECTED: 562676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_CONNECTED; 563676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_CONNECTING: 564676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_CONNECTING; 565676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DISCONNECTING: 566676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTING; 567676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DISCONNECTED: 568676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 569676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DESTROYED: 570676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // TODO(BT) add BluetoothHealth.STATE_CHANNEL_DESTROYED; 571676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 572676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie default: 573676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Unexpected channel state: " + halChannelState); 574676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 575676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 576676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 577676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 578676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private boolean connectChannel(BluetoothDevice device, 579676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelType) { 580676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mApps.get(config) == null) { 581676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "connectChannel fail to get a app id from config"); 582676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return false; 583676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 584676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 585676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = new HealthChannel(device, config, channelType); 586676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 587676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_CHANNEL); 588676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.obj = chan; 589676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 590676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 591676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return true; 592676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 593676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 594676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void callHealthChannelCallback(BluetoothHealthAppConfiguration config, 595676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothDevice device, int state, int prevState, ParcelFileDescriptor fd, int id) { 596676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie broadcastHealthDeviceStateChange(device, state); 597676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 598fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie log("Health Device Callback: " + device + " State Change: " + prevState + "->" + 599676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie state); 600676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 601676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ParcelFileDescriptor dupedFd = null; 602676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (fd != null) { 603676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 604676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie dupedFd = fd.dup(); 605676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (IOException e) { 606676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie dupedFd = null; 607676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Exception while duping: " + e); 608676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 609676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 610676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 611676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie IBluetoothHealthCallback callback = (mApps.get(config)).mCallback; 612676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (callback == null) { 613676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No callback found for config: " + config); 614676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return; 615676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 616676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 617676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 618676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callback.onHealthChannelStateChange(config, device, prevState, state, dupedFd, id); 619676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (RemoteException e) { 620676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Remote Exception:" + e); 621676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 622676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 623676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 624676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 625676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This function sends the intent for the updates on the connection status to the remote device. 626676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Note that multiple channels can be connected to the remote device by multiple applications. 627676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This sends an intent for the update to the device connection status and not the channel 628676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * connection status. Only the following state transitions are possible: 629676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 630676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTED} to {@link BluetoothHealth#STATE_CONNECTING} 631676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTING} to {@link BluetoothHealth#STATE_CONNECTED} 632676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTED} to {@link BluetoothHealth#STATE_DISCONNECTING} 633676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTING} to {@link BluetoothHealth#STATE_DISCONNECTED} 634676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTED} to {@link BluetoothHealth#STATE_CONNECTED} 635676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTED} to {@link BluetoothHealth#STATE_DISCONNECTED} 636676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTING} to {{@link BluetoothHealth#STATE_DISCONNECTED} 637676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 638676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param device 639676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param prevChannelState 640676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param newChannelState 641676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @hide 642676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 643676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void broadcastHealthDeviceStateChange(BluetoothDevice device, int newChannelState) { 644676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mHealthDevices.get(device) == null) { 645676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.put(device, BluetoothHealth.STATE_DISCONNECTED); 646676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 647676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 648676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int currDeviceState = mHealthDevices.get(device); 649676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int newDeviceState = convertState(newChannelState); 650676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 651676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (currDeviceState == newDeviceState) return; 652676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 653676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie boolean sendIntent = false; 654676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<HealthChannel> chan; 655676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (currDeviceState) { 656676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_DISCONNECTED: 657676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connection or connect/disconnect attemp with the remote device 658676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 659676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 660676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CONNECTING: 661676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connection, there was a connecting attempt going on 662676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 663676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got connected. 664676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newDeviceState == BluetoothHealth.STATE_CONNECTED) { 665676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 666676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 667676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected 668676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 669676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 670676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING}); 671676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 672676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 673676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 674676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 675676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 676676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CONNECTED: 677676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was at least one connection 678676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 679676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected or is in disconnecting state. 680676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 681676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 682676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED}); 683676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 684676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 685676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 686676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 687676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_DISCONNECTING: 688676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connected channel with the remote device 689676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // We were disconnecting all the channels with the remote device 690676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 691676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected. 692676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 693676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 694676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING}); 695676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 696676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie updateAndSendIntent(device, newDeviceState, currDeviceState); 697676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 698676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 699676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 700676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (sendIntent) 701676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie updateAndSendIntent(device, newDeviceState, currDeviceState); 702676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 703676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 704676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void updateAndSendIntent(BluetoothDevice device, int newDeviceState, 705676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int prevDeviceState) { 706676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newDeviceState == BluetoothHealth.STATE_DISCONNECTED) { 707676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.remove(device); 708676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 709676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.put(device, newDeviceState); 710676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 711676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 712676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 713676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 714676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This function converts the channel connection state to device connection state. 715676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 716676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param state 717676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @return 718676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 719676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertState(int state) { 720676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (state) { 721676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_CONNECTED: 722676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CONNECTED; 723676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_CONNECTING: 724676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CONNECTING; 725676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_DISCONNECTING: 726676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTING; 727676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_DISCONNECTED: 728676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 729676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 730676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Mismatch in Channel and Health Device State: " + state); 731676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 732676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 733676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 734676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertRoleToHal(int role) { 735676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (role == BluetoothHealth.SOURCE_ROLE) return MDEP_ROLE_SOURCE; 736676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (role == BluetoothHealth.SINK_ROLE) return MDEP_ROLE_SINK; 737676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "unkonw role: " + role); 738676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return MDEP_ROLE_SINK; 739676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 740676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 741676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertChannelTypeToHal(int channelType) { 742676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_RELIABLE) return CHANNEL_TYPE_RELIABLE; 743676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_STREAMING) return CHANNEL_TYPE_STREAMING; 744676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_ANY) return CHANNEL_TYPE_ANY; 745676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "unkonw channel type: " + channelType); 746676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return CHANNEL_TYPE_ANY; 747676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 748676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 749676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthChannel findChannelById(int id) { 750676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (HealthChannel chan : mHealthChannels) { 751676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mChannelId == id) return chan; 752676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 753676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No channel found by id: " + id); 754676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return null; 755676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 756676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 757676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private List<HealthChannel> findChannelByStates(BluetoothDevice device, int[] states) { 758676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<HealthChannel> channels = new ArrayList<HealthChannel>(); 759676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (HealthChannel chan: mHealthChannels) { 760676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mDevice.equals(device)) { 761676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (int state : states) { 762676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mState == state) { 763676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie channels.add(chan); 764676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 765676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 766676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 767676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 768676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return channels; 769676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 770676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 771676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int getConnectionState(BluetoothDevice device) { 772676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mHealthDevices.get(device) == null) { 773676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 774676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 775676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return mHealthDevices.get(device); 776676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 777676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 778676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<BluetoothDevice> lookupHealthDevicesMatchingStates(int[] states) { 779676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<BluetoothDevice> healthDevices = new ArrayList<BluetoothDevice>(); 780676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 781676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (BluetoothDevice device: mHealthDevices.keySet()) { 782676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int healthDeviceState = getConnectionState(device); 783676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (int state : states) { 784676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (state == healthDeviceState) { 785676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie healthDevices.add(device); 786676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 787676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 788676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 789676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 790676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return healthDevices; 791676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 792676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 793838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood @Override 794838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood public void dump(StringBuilder sb) { 795838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood super.dump(sb); 796838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mHealthChannels:"); 797838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (HealthChannel channel : mHealthChannels) { 798838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + channel); 799838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 800838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mApps:"); 801838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (BluetoothHealthAppConfiguration conf : mApps.keySet()) { 802838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + conf + " : " + mApps.get(conf)); 803838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 804838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mHealthDevices:"); 805838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (BluetoothDevice device : mHealthDevices.keySet()) { 806838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + device + " : " + mHealthDevices.get(device)); 807838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 808838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 809838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 81074ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class AppInfo { 811676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private IBluetoothHealthCallback mCallback; 812755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private BluetoothHealthDeathRecipient mRcpObj; 813676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mAppId; 814676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 815676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private AppInfo(IBluetoothHealthCallback callback) { 816676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mCallback = callback; 817755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 818676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAppId = -1; 819676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 820755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 821755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private void cleanup(){ 822755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if(mCallback != null){ 823755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if(mRcpObj != null){ 824755aa8f5359a933205552c40b6446b001ae42378Priti Aghera IBinder binder = mCallback.asBinder(); 825755aa8f5359a933205552c40b6446b001ae42378Priti Aghera try{ 826755aa8f5359a933205552c40b6446b001ae42378Priti Aghera binder.unlinkToDeath(mRcpObj,0); 827755aa8f5359a933205552c40b6446b001ae42378Priti Aghera }catch(NoSuchElementException e){ 828755aa8f5359a933205552c40b6446b001ae42378Priti Aghera Log.e(TAG,"No death recipient registered"+e); 829755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 830755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj.cleanup(); 831755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 832755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 833755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mCallback = null; 834755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 835755aa8f5359a933205552c40b6446b001ae42378Priti Aghera else if(mRcpObj != null){ 836755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj.cleanup(); 837755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 838755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 839755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 840676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 841676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 842676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private class HealthChannel { 843676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private ParcelFileDescriptor mChannelFd; 844676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothDevice mDevice; 845676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothHealthAppConfiguration mConfig; 846676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // BluetoothHealth channel state 847676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mState; 848676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mChannelType; 849676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mChannelId; 850676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 851676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthChannel(BluetoothDevice device, BluetoothHealthAppConfiguration config, 852676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelType) { 853676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelFd = null; 854676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mDevice = device; 855676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mConfig = config; 856676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 857676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelType = channelType; 858676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelId = -1; 859676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 860676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 861676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 862676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel state event from Hal 863676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private class ChannelStateEvent { 864676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mAppId; 865676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie byte[] mAddr; 866676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mCfgIndex; 867676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mChannelId; 868676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mState; 869676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie FileDescriptor mFd; 870676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 871676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private ChannelStateEvent(int appId, byte[] addr, int cfgIndex, 872676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelId, int state, FileDescriptor fileDescriptor) { 873676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAppId = appId; 874676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAddr = addr; 875676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mCfgIndex = cfgIndex; 876676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mState = state; 877676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelId = channelId; 878676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mFd = fileDescriptor; 879676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 880676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 881676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 882676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Constants matching Hal header file bt_hl.h 883676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_app_reg_state_t 884676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_REG_SUCCESS = 0; 885676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_REG_FAILED = 1; 886676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_DEREG_SUCCESS = 2; 887676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_DEREG_FAILED = 3; 888676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 889676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_channel_state_t 890676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_CONNECTING = 0; 891676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_CONNECTED = 1; 892676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DISCONNECTING = 2; 893676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DISCONNECTED = 3; 894676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DESTROYED = 4; 895676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 896676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_mdep_role_t 897676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MDEP_ROLE_SOURCE = 0; 898676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MDEP_ROLE_SINK = 1; 899676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 900676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_channel_type_t 901676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_RELIABLE = 0; 902676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_STREAMING = 1; 903676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_ANY =2; 904676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 905676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native static void classInitNative(); 9066654f5c903de510a70f9e72cd5ad7837b615d93ffredc private native void initializeNative(); 9076654f5c903de510a70f9e72cd5ad7837b615d93ffredc private native void cleanupNative(); 908676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native int registerHealthAppNative(int dataType, int role, String name, int channelType); 909676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native boolean unregisterHealthAppNative(int appId); 910676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native int connectChannelNative(byte[] btAddress, int appId); 911676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native boolean disconnectChannelNative(int channelId); 91274ae04c73312403e89db0f8e9bd9601d403b4783fredc 913676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie} 914