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.IBluetooth; 24676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.IBluetoothHealth; 25676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.bluetooth.IBluetoothHealthCallback; 26676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.content.Intent; 2737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.content.pm.PackageManager; 28676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.Handler; 29676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.HandlerThread; 30755aa8f5359a933205552c40b6446b001ae42378Priti Agheraimport android.os.IBinder; 31755aa8f5359a933205552c40b6446b001ae42378Priti Agheraimport android.os.IBinder.DeathRecipient; 3237510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.os.Looper; 3337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.os.Message; 34676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.ParcelFileDescriptor; 35676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.RemoteException; 36676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.os.ServiceManager; 37676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport android.util.Log; 3837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService; 3937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; 4037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils; 41676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.io.FileDescriptor; 42676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.io.IOException; 43676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.ArrayList; 44676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Collections; 45676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.HashMap; 468629665794ef845e945595040e4cf1ea2fa508d3Priti Agheraimport java.util.Iterator; 47676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.List; 48676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Map; 49676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xieimport java.util.Map.Entry; 5037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport java.util.NoSuchElementException; 5137510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 52676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 53676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie/** 54676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Provides Bluetooth Health Device profile, as a service in 55676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * the Bluetooth application. 56676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @hide 57676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 58b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class HealthService extends ProfileService { 598629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera private static final boolean DBG = true; 608629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera private static final boolean VDBG = false; 61b5cc776c9353a203cdde97e62b25f05d9633d14cfredc private static final String TAG="HealthService"; 6274ae04c73312403e89db0f8e9bd9601d403b4783fredc 63676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private List<HealthChannel> mHealthChannels; 64676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private Map <BluetoothHealthAppConfiguration, AppInfo> mApps; 65676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private Map <BluetoothDevice, Integer> mHealthDevices; 6674ae04c73312403e89db0f8e9bd9601d403b4783fredc private boolean mNativeAvailable; 67676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthServiceMessageHandler mHandler; 68676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_REGISTER_APPLICATION = 1; 69676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_UNREGISTER_APPLICATION = 2; 70676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_CONNECT_CHANNEL = 3; 71676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_DISCONNECT_CHANNEL = 4; 72676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_APP_REGISTRATION_CALLBACK = 11; 73676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MESSAGE_CHANNEL_STATE_CALLBACK = 12; 74676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 75676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie static { 76676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie classInitNative(); 77676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 78676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 79b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected String getName() { 80b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return TAG; 81676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 82676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 8374ae04c73312403e89db0f8e9bd9601d403b4783fredc protected IProfileServiceBinder initBinder() { 8474ae04c73312403e89db0f8e9bd9601d403b4783fredc return new BluetoothHealthBinder(this); 85676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 86676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 87b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean start() { 886654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHealthChannels = Collections.synchronizedList(new ArrayList<HealthChannel>()); 896654f5c903de510a70f9e72cd5ad7837b615d93ffredc mApps = Collections.synchronizedMap(new HashMap<BluetoothHealthAppConfiguration, 906654f5c903de510a70f9e72cd5ad7837b615d93ffredc AppInfo>()); 916654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHealthDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>()); 926654f5c903de510a70f9e72cd5ad7837b615d93ffredc 936654f5c903de510a70f9e72cd5ad7837b615d93ffredc HandlerThread thread = new HandlerThread("BluetoothHdpHandler"); 946654f5c903de510a70f9e72cd5ad7837b615d93ffredc thread.start(); 956654f5c903de510a70f9e72cd5ad7837b615d93ffredc Looper looper = thread.getLooper(); 966654f5c903de510a70f9e72cd5ad7837b615d93ffredc mHandler = new HealthServiceMessageHandler(looper); 976654f5c903de510a70f9e72cd5ad7837b615d93ffredc initializeNative(); 9874ae04c73312403e89db0f8e9bd9601d403b4783fredc mNativeAvailable=true; 99b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 1006654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 1016654f5c903de510a70f9e72cd5ad7837b615d93ffredc 102b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean stop() { 10362fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie if (mHandler != null) { 10462fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie mHandler.removeCallbacksAndMessages(null); 10562fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie Looper looper = mHandler.getLooper(); 10662fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie if (looper != null) { 10762fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie looper.quit(); 10862fb56f2ba7d998e3e7416fc19d25ea91cc85111Matthew Xie } 1096654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 110755aa8f5359a933205552c40b6446b001ae42378Priti Aghera cleanupApps(); 11174ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 11274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1136654f5c903de510a70f9e72cd5ad7837b615d93ffredc 114755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private void cleanupApps(){ 115f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava if (mApps != null) { 116f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava Iterator <Map.Entry<BluetoothHealthAppConfiguration,AppInfo>>it 117f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava = mApps.entrySet().iterator(); 118f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava while (it.hasNext()) { 119f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava Map.Entry<BluetoothHealthAppConfiguration,AppInfo> entry = it.next(); 120f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava AppInfo appInfo = entry.getValue(); 121f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava if (appInfo != null) 122f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava appInfo.cleanup(); 123f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava it.remove(); 124f2fab45657d6097f08b95a83eca0bf8005807599Nitin Srivastava } 125755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 126755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 12774ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean cleanup() { 12874ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler = null; 1296654f5c903de510a70f9e72cd5ad7837b615d93ffredc //Cleanup native 13074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mNativeAvailable) { 13174ae04c73312403e89db0f8e9bd9601d403b4783fredc cleanupNative(); 13274ae04c73312403e89db0f8e9bd9601d403b4783fredc mNativeAvailable=false; 13374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 134b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mHealthChannels != null) { 135b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mHealthChannels.clear(); 136b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 137b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mHealthDevices != null) { 138b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mHealthDevices.clear(); 1396654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 140b5cc776c9353a203cdde97e62b25f05d9633d14cfredc if(mApps != null) { 141b5cc776c9353a203cdde97e62b25f05d9633d14cfredc mApps.clear(); 142b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 143b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 144676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 145676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 146676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private final class HealthServiceMessageHandler extends Handler { 147676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthServiceMessageHandler(Looper looper) { 148676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie super(looper); 149676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 150676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 151676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie @Override 152676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public void handleMessage(Message msg) { 1538629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (DBG) log("HealthService Handler msg: " + msg.what); 154676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (msg.what) { 155676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_REGISTER_APPLICATION: 156676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 157676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = 158676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie (BluetoothHealthAppConfiguration) msg.obj; 159755aa8f5359a933205552c40b6446b001ae42378Priti Aghera AppInfo appInfo = mApps.get(appConfig); 160755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if (appInfo == null) break; 161676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int halRole = convertRoleToHal(appConfig.getRole()); 162676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int halChannelType = convertChannelTypeToHal(appConfig.getChannelType()); 1638629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (VDBG) log("register datatype: " + appConfig.getDataType() + " role: " + 164676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie halRole + " name: " + appConfig.getName() + " channeltype: " + 165676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie halChannelType); 166676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = registerHealthAppNative(appConfig.getDataType(), halRole, 167676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie appConfig.getName(), halChannelType); 168676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appId == -1) { 169676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 170676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE); 171755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.cleanup(); 172676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mApps.remove(appConfig); 173676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 174755aa8f5359a933205552c40b6446b001ae42378Priti Aghera //link to death with a recipient object to implement binderDead() 175755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.mRcpObj = new BluetoothHealthDeathRecipient(HealthService.this,appConfig); 176755aa8f5359a933205552c40b6446b001ae42378Priti Aghera IBinder binder = appInfo.mCallback.asBinder(); 177755aa8f5359a933205552c40b6446b001ae42378Priti Aghera try { 178755aa8f5359a933205552c40b6446b001ae42378Priti Aghera binder.linkToDeath(appInfo.mRcpObj,0); 179755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } catch (RemoteException e) { 180755aa8f5359a933205552c40b6446b001ae42378Priti Aghera Log.e(TAG,"LinktoDeath Exception:"+e); 181755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 182755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.mAppId = appId; 183676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 184676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS); 185676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 186676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 187676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 188676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_UNREGISTER_APPLICATION: 189676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 190676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = 191676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie (BluetoothHealthAppConfiguration) msg.obj; 192676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = (mApps.get(appConfig)).mAppId; 193676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (!unregisterHealthAppNative(appId)) { 194676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Failed to unregister application: id: " + appId); 195676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, 196676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE); 197676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 198676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 199676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 200676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_CONNECT_CHANNEL: 201676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 202676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = (HealthChannel) msg.obj; 20374ae04c73312403e89db0f8e9bd9601d403b4783fredc byte[] devAddr = Utils.getByteAddress(chan.mDevice); 204676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int appId = (mApps.get(chan.mConfig)).mAppId; 205676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelId = connectChannelNative(devAddr, appId); 206676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mChannelId == -1) { 207676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 208676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 209676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTED, 210676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 211676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 212676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTED, 213676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 214676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 215676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 216676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 217676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 218676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_DISCONNECT_CHANNEL: 219676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 220676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = (HealthChannel) msg.obj; 221676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (!disconnectChannelNative(chan.mChannelId)) { 222676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 223676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 224676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED, 225676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 226676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, 227676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED, 228676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING, 229676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd, chan.mChannelId); 230676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 231676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 232676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 233676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_APP_REGISTRATION_CALLBACK: 234676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 235676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = findAppConfigByAppId(msg.arg1); 236676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appConfig == null) break; 237676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 238676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int regStatus = convertHalRegStatus(msg.arg2); 239676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callStatusCallback(appConfig, regStatus); 240676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (regStatus == BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE || 241676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie regStatus == BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS) { 242755aa8f5359a933205552c40b6446b001ae42378Priti Aghera //unlink to death once app is unregistered 243755aa8f5359a933205552c40b6446b001ae42378Priti Aghera AppInfo appInfo = mApps.get(appConfig); 244755aa8f5359a933205552c40b6446b001ae42378Priti Aghera appInfo.cleanup(); 245676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mApps.remove(appConfig); 246676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 2478629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera } 248676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 249676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case MESSAGE_CHANNEL_STATE_CALLBACK: 250676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie { 251676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ChannelStateEvent channelStateEvent = (ChannelStateEvent) msg.obj; 252676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = findChannelById(channelStateEvent.mChannelId); 2538629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera BluetoothHealthAppConfiguration appConfig = 2548629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera findAppConfigByAppId(channelStateEvent.mAppId); 255676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int newState; 2568629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera newState = convertHalChannelState(channelStateEvent.mState); 2578629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (newState == BluetoothHealth.STATE_CHANNEL_DISCONNECTED && 2588629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera appConfig == null) { 2598629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera Log.e(TAG,"Disconnected for non existing app"); 2608629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera break; 2618629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera } 262676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan == null) { 263676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // incoming connection 2648629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera 265676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothDevice device = getDevice(channelStateEvent.mAddr); 266676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = new HealthChannel(device, appConfig, appConfig.getChannelType()); 267676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelId = channelStateEvent.mChannelId; 268970baea8e58a7b537e76e8bcbba34f428cede061Priti Aghera mHealthChannels.add(chan); 269676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 270676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie newState = convertHalChannelState(channelStateEvent.mState); 271676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newState == BluetoothHealth.STATE_CHANNEL_CONNECTED) { 272676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 273676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mChannelFd = ParcelFileDescriptor.dup(channelStateEvent.mFd); 274676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (IOException e) { 275676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "failed to dup ParcelFileDescriptor"); 276676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 277676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 278676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 27981491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera /*set the channel fd to null if channel state isnot equal to connected*/ 28081491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera else{ 28181491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera chan.mChannelFd = null; 28281491a292e9f01007c0f291e7f6acd054f6dcb4cPriti Aghera } 283676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callHealthChannelCallback(chan.mConfig, chan.mDevice, newState, 284676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mState, chan.mChannelFd, chan.mChannelId); 285676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan.mState = newState; 286676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelStateEvent.mState == CONN_STATE_DESTROYED) { 287676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthChannels.remove(chan); 288676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 289676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 290676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 291676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 292676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 293676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 294676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 295755aa8f5359a933205552c40b6446b001ae42378Priti Aghera//Handler for DeathReceipient 296755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private static class BluetoothHealthDeathRecipient implements IBinder.DeathRecipient{ 297755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private BluetoothHealthAppConfiguration mConfig; 298755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private HealthService mService; 299755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 300755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public BluetoothHealthDeathRecipient(HealthService service, BluetoothHealthAppConfiguration config) { 301755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService = service; 302755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mConfig = config; 303755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 304755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 305755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public void binderDied() { 3068629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (DBG) Log.d(TAG,"Binder is dead."); 307755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService.unregisterAppConfiguration(mConfig); 308755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 309755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 310755aa8f5359a933205552c40b6446b001ae42378Priti Aghera public void cleanup(){ 311755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mService = null; 312755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mConfig = null; 313755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 314755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 315755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 316676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 317676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Handlers for incoming service calls 318676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 31974ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class BluetoothHealthBinder extends IBluetoothHealth.Stub implements IProfileServiceBinder { 32074ae04c73312403e89db0f8e9bd9601d403b4783fredc private HealthService mService; 32174ae04c73312403e89db0f8e9bd9601d403b4783fredc 32274ae04c73312403e89db0f8e9bd9601d403b4783fredc public BluetoothHealthBinder(HealthService svc) { 32374ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = svc; 32474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 32574ae04c73312403e89db0f8e9bd9601d403b4783fredc 32674ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean cleanup() { 32774ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = null; 328676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return true; 329676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 330676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 33174ae04c73312403e89db0f8e9bd9601d403b4783fredc private HealthService getService() { 33237510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu if (!Utils.checkCaller()) { 33337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu Log.w(TAG,"Health call not allowed for non-active user"); 33437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu return null; 33537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu } 33637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 33774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mService != null && mService.isAvailable()) { 33874ae04c73312403e89db0f8e9bd9601d403b4783fredc return mService; 339676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 34074ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 34174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 342676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 34374ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config, 34474ae04c73312403e89db0f8e9bd9601d403b4783fredc IBluetoothHealthCallback callback) { 34574ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 34674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 34774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.registerAppConfiguration(config, callback); 34874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34974ae04c73312403e89db0f8e9bd9601d403b4783fredc 35074ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 35174ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 35274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 35374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.unregisterAppConfiguration(config); 354676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 355676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 356676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean connectChannelToSource(BluetoothDevice device, 357676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config) { 35874ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 35974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 36074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectChannelToSource(device, config); 361676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 362676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 363676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean connectChannelToSink(BluetoothDevice device, 364676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelType) { 36574ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 36674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 36774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectChannelToSink(device, config, channelType); 368676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 369676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 370676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public boolean disconnectChannel(BluetoothDevice device, 371676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelId) { 37274ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 37374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 37474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnectChannel(device, config, channelId); 375676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 376676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 377676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 378676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config) { 37974ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 38074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return null; 38174ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getMainChannelFd(device, config); 382676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 383676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 384676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public int getHealthDeviceConnectionState(BluetoothDevice device) { 38574ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 38674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothHealth.STATE_DISCONNECTED; 38774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getHealthDeviceConnectionState(device); 388676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 389676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 390676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public List<BluetoothDevice> getConnectedHealthDevices() { 39174ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 39274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice> (0); 39374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectedHealthDevices(); 394676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 395676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 396676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(int[] states) { 39774ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthService service = getService(); 39874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice> (0); 39974ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getHealthDevicesMatchingConnectionStates(states); 400676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 401676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie }; 402676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 40374ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean registerAppConfiguration(BluetoothHealthAppConfiguration config, 40474ae04c73312403e89db0f8e9bd9601d403b4783fredc IBluetoothHealthCallback callback) { 40574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, 40674ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH permission"); 40774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mApps.get(config) != null) { 40874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG, "Config has already been registered"); 40974ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 41074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41174ae04c73312403e89db0f8e9bd9601d403b4783fredc mApps.put(config, new AppInfo(callback)); 41274ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_APPLICATION,config); 41374ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 41474ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 41574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41674ae04c73312403e89db0f8e9bd9601d403b4783fredc 41774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) { 41874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 41974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mApps.get(config) == null) { 42074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG,"unregisterAppConfiguration: no app found"); 42174ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 42274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42374ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_APPLICATION,config); 42474ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 42574ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 42674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42774ae04c73312403e89db0f8e9bd9601d403b4783fredc 42874ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectChannelToSource(BluetoothDevice device, 42974ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config) { 43074ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 43174ae04c73312403e89db0f8e9bd9601d403b4783fredc return connectChannel(device, config, BluetoothHealth.CHANNEL_TYPE_ANY); 43274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43374ae04c73312403e89db0f8e9bd9601d403b4783fredc 43474ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectChannelToSink(BluetoothDevice device, 43574ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config, int channelType) { 43674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 43774ae04c73312403e89db0f8e9bd9601d403b4783fredc return connectChannel(device, config, channelType); 43874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43974ae04c73312403e89db0f8e9bd9601d403b4783fredc 44074ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnectChannel(BluetoothDevice device, 44174ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config, int channelId) { 44274ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 44374ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthChannel chan = findChannelById(channelId); 44474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (chan == null) { 44574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG,"disconnectChannel: no channel found"); 44674ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 44774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44874ae04c73312403e89db0f8e9bd9601d403b4783fredc Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT_CHANNEL,chan); 44974ae04c73312403e89db0f8e9bd9601d403b4783fredc mHandler.sendMessage(msg); 45074ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 45174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45274ae04c73312403e89db0f8e9bd9601d403b4783fredc 45374ae04c73312403e89db0f8e9bd9601d403b4783fredc ParcelFileDescriptor getMainChannelFd(BluetoothDevice device, 45474ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothHealthAppConfiguration config) { 45574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 45674ae04c73312403e89db0f8e9bd9601d403b4783fredc HealthChannel healthChan = null; 45774ae04c73312403e89db0f8e9bd9601d403b4783fredc for (HealthChannel chan: mHealthChannels) { 45874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (chan.mDevice.equals(device) && chan.mConfig.equals(config)) { 45974ae04c73312403e89db0f8e9bd9601d403b4783fredc healthChan = chan; 46074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (healthChan == null) { 46374ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.e(TAG, "No channel found for device: " + device + " config: " + config); 46474ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 46574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46674ae04c73312403e89db0f8e9bd9601d403b4783fredc return healthChan.mChannelFd; 46774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46874ae04c73312403e89db0f8e9bd9601d403b4783fredc 46974ae04c73312403e89db0f8e9bd9601d403b4783fredc int getHealthDeviceConnectionState(BluetoothDevice device) { 47074ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 47174ae04c73312403e89db0f8e9bd9601d403b4783fredc return getConnectionState(device); 47274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47374ae04c73312403e89db0f8e9bd9601d403b4783fredc 47474ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> getConnectedHealthDevices() { 47574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 47674ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> devices = lookupHealthDevicesMatchingStates( 47774ae04c73312403e89db0f8e9bd9601d403b4783fredc new int[] {BluetoothHealth.STATE_CONNECTED}); 47874ae04c73312403e89db0f8e9bd9601d403b4783fredc return devices; 47974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48074ae04c73312403e89db0f8e9bd9601d403b4783fredc 48174ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(int[] states) { 48274ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 48374ae04c73312403e89db0f8e9bd9601d403b4783fredc List<BluetoothDevice> devices = lookupHealthDevicesMatchingStates(states); 48474ae04c73312403e89db0f8e9bd9601d403b4783fredc return devices; 48574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48674ae04c73312403e89db0f8e9bd9601d403b4783fredc 487676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void onAppRegistrationState(int appId, int state) { 488676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_APP_REGISTRATION_CALLBACK); 489676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.arg1 = appId; 490676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.arg2 = state; 491676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 492676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 493676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 494676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void onChannelStateChanged(int appId, byte[] addr, int cfgIndex, 495676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelId, int state, FileDescriptor pfd) { 496676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_CHANNEL_STATE_CALLBACK); 497676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ChannelStateEvent channelStateEvent = new ChannelStateEvent(appId, addr, cfgIndex, 498676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie channelId, state, pfd); 499676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.obj = channelStateEvent; 500676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 501676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 502676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 503676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private String getStringChannelType(int type) { 504676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (type == BluetoothHealth.CHANNEL_TYPE_RELIABLE) { 505676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Reliable"; 506676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else if (type == BluetoothHealth.CHANNEL_TYPE_STREAMING) { 507676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Streaming"; 508676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 509676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return "Any"; 510676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 511676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 512676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 513676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void callStatusCallback(BluetoothHealthAppConfiguration config, int status) { 5148629665794ef845e945595040e4cf1ea2fa508d3Priti Aghera if (VDBG) log ("Health Device Application: " + config + " State Change: status:" + status); 515676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie IBluetoothHealthCallback callback = (mApps.get(config)).mCallback; 516676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (callback == null) { 517676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Callback object null"); 518676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 519676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 520676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 521676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callback.onHealthAppConfigurationStatusChange(config, status); 522676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (RemoteException e) { 523676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Remote Exception:" + e); 524676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 525676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 526676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 527676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothHealthAppConfiguration findAppConfigByAppId(int appId) { 528676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration appConfig = null; 529676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (Entry<BluetoothHealthAppConfiguration, AppInfo> e : mApps.entrySet()) { 530676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appId == (e.getValue()).mAppId) { 531676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie appConfig = e.getKey(); 532676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 533676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 534676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 535676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (appConfig == null) { 536676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No appConfig found for " + appId); 537676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 538676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return appConfig; 539676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 540676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 541676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertHalRegStatus(int halRegStatus) { 542676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (halRegStatus) { 543676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_REG_SUCCESS: 544676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_SUCCESS; 545676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_REG_FAILED: 546676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE; 547676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_DEREG_SUCCESS: 548676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_UNREGISTRATION_SUCCESS; 549676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case APP_REG_STATE_DEREG_FAILED: 550676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_UNREGISTRATION_FAILURE; 551676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 552676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Unexpected App Registration state: " + halRegStatus); 553676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.APP_CONFIG_REGISTRATION_FAILURE; 554676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 555676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 556676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertHalChannelState(int halChannelState) { 557676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (halChannelState) { 558676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_CONNECTED: 559676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_CONNECTED; 560676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_CONNECTING: 561676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_CONNECTING; 562676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DISCONNECTING: 563676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTING; 564676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DISCONNECTED: 565676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 566676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case CONN_STATE_DESTROYED: 567676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // TODO(BT) add BluetoothHealth.STATE_CHANNEL_DESTROYED; 568676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 569676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie default: 570676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Unexpected channel state: " + halChannelState); 571676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 572676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 573676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 574676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 575676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private boolean connectChannel(BluetoothDevice device, 576676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealthAppConfiguration config, int channelType) { 577676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mApps.get(config) == null) { 578676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "connectChannel fail to get a app id from config"); 579676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return false; 580676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 581676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 582676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie HealthChannel chan = new HealthChannel(device, config, channelType); 583676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 584676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_CHANNEL); 585676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie msg.obj = chan; 586676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHandler.sendMessage(msg); 587676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 588676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return true; 589676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 590676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 591676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void callHealthChannelCallback(BluetoothHealthAppConfiguration config, 592676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothDevice device, int state, int prevState, ParcelFileDescriptor fd, int id) { 593676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie broadcastHealthDeviceStateChange(device, state); 594676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 595fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie log("Health Device Callback: " + device + " State Change: " + prevState + "->" + 596676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie state); 597676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 598676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie ParcelFileDescriptor dupedFd = null; 599676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (fd != null) { 600676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 601676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie dupedFd = fd.dup(); 602676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (IOException e) { 603676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie dupedFd = null; 604676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Exception while duping: " + e); 605676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 606676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 607676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 608676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie IBluetoothHealthCallback callback = (mApps.get(config)).mCallback; 609676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (callback == null) { 610676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No callback found for config: " + config); 611676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return; 612676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 613676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 614676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie try { 615676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie callback.onHealthChannelStateChange(config, device, prevState, state, dupedFd, id); 616676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } catch (RemoteException e) { 617676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Remote Exception:" + e); 618676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 619676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 620676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 621676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 622676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This function sends the intent for the updates on the connection status to the remote device. 623676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * Note that multiple channels can be connected to the remote device by multiple applications. 624676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This sends an intent for the update to the device connection status and not the channel 625676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * connection status. Only the following state transitions are possible: 626676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 627676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTED} to {@link BluetoothHealth#STATE_CONNECTING} 628676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTING} to {@link BluetoothHealth#STATE_CONNECTED} 629676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTED} to {@link BluetoothHealth#STATE_DISCONNECTING} 630676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTING} to {@link BluetoothHealth#STATE_DISCONNECTED} 631676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_DISCONNECTED} to {@link BluetoothHealth#STATE_CONNECTED} 632676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTED} to {@link BluetoothHealth#STATE_DISCONNECTED} 633676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * {@link BluetoothHealth#STATE_CONNECTING} to {{@link BluetoothHealth#STATE_DISCONNECTED} 634676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 635676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param device 636676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param prevChannelState 637676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param newChannelState 638676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @hide 639676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 640676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void broadcastHealthDeviceStateChange(BluetoothDevice device, int newChannelState) { 641676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mHealthDevices.get(device) == null) { 642676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.put(device, BluetoothHealth.STATE_DISCONNECTED); 643676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 644676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 645676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int currDeviceState = mHealthDevices.get(device); 646676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int newDeviceState = convertState(newChannelState); 647676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 648676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (currDeviceState == newDeviceState) return; 649676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 650676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie boolean sendIntent = false; 651676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<HealthChannel> chan; 652676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (currDeviceState) { 653676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_DISCONNECTED: 654676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connection or connect/disconnect attemp with the remote device 655676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 656676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 657676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CONNECTING: 658676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connection, there was a connecting attempt going on 659676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 660676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got connected. 661676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newDeviceState == BluetoothHealth.STATE_CONNECTED) { 662676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 663676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 664676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected 665676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 666676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 667676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING}); 668676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 669676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 670676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 671676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 672676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 673676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CONNECTED: 674676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was at least one connection 675676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 676676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected or is in disconnecting state. 677676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 678676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 679676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTED}); 680676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 681676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie sendIntent = true; 682676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 683676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 684676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_DISCONNECTING: 685676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // there was no connected channel with the remote device 686676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // We were disconnecting all the channels with the remote device 687676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 688676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel got disconnected. 689676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie chan = findChannelByStates(device, new int [] { 690676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_CONNECTING, 691676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie BluetoothHealth.STATE_CHANNEL_DISCONNECTING}); 692676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.isEmpty()) { 693676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie updateAndSendIntent(device, newDeviceState, currDeviceState); 694676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 695676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 696676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 697676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (sendIntent) 698676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie updateAndSendIntent(device, newDeviceState, currDeviceState); 699676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 700676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 701676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private void updateAndSendIntent(BluetoothDevice device, int newDeviceState, 702676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int prevDeviceState) { 703676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (newDeviceState == BluetoothHealth.STATE_DISCONNECTED) { 704676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.remove(device); 705676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } else { 706676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mHealthDevices.put(device, newDeviceState); 707676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 70874ae04c73312403e89db0f8e9bd9601d403b4783fredc notifyProfileConnectionStateChanged(device, BluetoothProfile.HEALTH, newDeviceState, prevDeviceState); 709676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 710676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 711676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie /** 712676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * This function converts the channel connection state to device connection state. 713676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * 714676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @param state 715676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie * @return 716676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie */ 717676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertState(int state) { 718676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie switch (state) { 719676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_CONNECTED: 720676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CONNECTED; 721676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_CONNECTING: 722676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_CONNECTING; 723676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_DISCONNECTING: 724676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTING; 725676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie case BluetoothHealth.STATE_CHANNEL_DISCONNECTED: 726676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 727676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 728676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "Mismatch in Channel and Health Device State: " + state); 729676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 730676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 731676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 732676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertRoleToHal(int role) { 733676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (role == BluetoothHealth.SOURCE_ROLE) return MDEP_ROLE_SOURCE; 734676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (role == BluetoothHealth.SINK_ROLE) return MDEP_ROLE_SINK; 735676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "unkonw role: " + role); 736676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return MDEP_ROLE_SINK; 737676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 738676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 739676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int convertChannelTypeToHal(int channelType) { 740676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_RELIABLE) return CHANNEL_TYPE_RELIABLE; 741676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_STREAMING) return CHANNEL_TYPE_STREAMING; 742676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (channelType == BluetoothHealth.CHANNEL_TYPE_ANY) return CHANNEL_TYPE_ANY; 743676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "unkonw channel type: " + channelType); 744676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return CHANNEL_TYPE_ANY; 745676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 746676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 747676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthChannel findChannelById(int id) { 748676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (HealthChannel chan : mHealthChannels) { 749676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mChannelId == id) return chan; 750676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 751676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie Log.e(TAG, "No channel found by id: " + id); 752676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return null; 753676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 754676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 755676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private List<HealthChannel> findChannelByStates(BluetoothDevice device, int[] states) { 756676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<HealthChannel> channels = new ArrayList<HealthChannel>(); 757676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (HealthChannel chan: mHealthChannels) { 758676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mDevice.equals(device)) { 759676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (int state : states) { 760676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (chan.mState == state) { 761676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie channels.add(chan); 762676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 763676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 764676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 765676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 766676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return channels; 767676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 768676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 769676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int getConnectionState(BluetoothDevice device) { 770676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (mHealthDevices.get(device) == null) { 771676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return BluetoothHealth.STATE_DISCONNECTED; 772676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 773676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return mHealthDevices.get(device); 774676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 775676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 776676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<BluetoothDevice> lookupHealthDevicesMatchingStates(int[] states) { 777676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie List<BluetoothDevice> healthDevices = new ArrayList<BluetoothDevice>(); 778676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 779676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (BluetoothDevice device: mHealthDevices.keySet()) { 780676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int healthDeviceState = getConnectionState(device); 781676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie for (int state : states) { 782676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie if (state == healthDeviceState) { 783676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie healthDevices.add(device); 784676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie break; 785676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 786676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 787676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 788676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie return healthDevices; 789676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 790676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 791838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood @Override 792838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood public void dump(StringBuilder sb) { 793838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood super.dump(sb); 794838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mHealthChannels:"); 795838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (HealthChannel channel : mHealthChannels) { 796838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + channel); 797838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 798838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mApps:"); 799838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (BluetoothHealthAppConfiguration conf : mApps.keySet()) { 800838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + conf + " : " + mApps.get(conf)); 801838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 802838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, "mHealthDevices:"); 803838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood for (BluetoothDevice device : mHealthDevices.keySet()) { 804838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood println(sb, " " + device + " : " + mHealthDevices.get(device)); 805838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 806838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 807838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 80874ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class AppInfo { 809676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private IBluetoothHealthCallback mCallback; 810755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private BluetoothHealthDeathRecipient mRcpObj; 811676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mAppId; 812676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 813676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private AppInfo(IBluetoothHealthCallback callback) { 814676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mCallback = callback; 815755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 816676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAppId = -1; 817676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 818755aa8f5359a933205552c40b6446b001ae42378Priti Aghera 819755aa8f5359a933205552c40b6446b001ae42378Priti Aghera private void cleanup(){ 820755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if(mCallback != null){ 821755aa8f5359a933205552c40b6446b001ae42378Priti Aghera if(mRcpObj != null){ 822755aa8f5359a933205552c40b6446b001ae42378Priti Aghera IBinder binder = mCallback.asBinder(); 823755aa8f5359a933205552c40b6446b001ae42378Priti Aghera try{ 824755aa8f5359a933205552c40b6446b001ae42378Priti Aghera binder.unlinkToDeath(mRcpObj,0); 825755aa8f5359a933205552c40b6446b001ae42378Priti Aghera }catch(NoSuchElementException e){ 826755aa8f5359a933205552c40b6446b001ae42378Priti Aghera Log.e(TAG,"No death recipient registered"+e); 827755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 828755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj.cleanup(); 829755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 830755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 831755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mCallback = null; 832755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 833755aa8f5359a933205552c40b6446b001ae42378Priti Aghera else if(mRcpObj != null){ 834755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj.cleanup(); 835755aa8f5359a933205552c40b6446b001ae42378Priti Aghera mRcpObj = null; 836755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 837755aa8f5359a933205552c40b6446b001ae42378Priti Aghera } 838676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 839676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 840676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private class HealthChannel { 841676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private ParcelFileDescriptor mChannelFd; 842676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothDevice mDevice; 843676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private BluetoothHealthAppConfiguration mConfig; 844676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // BluetoothHealth channel state 845676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mState; 846676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mChannelType; 847676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private int mChannelId; 848676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 849676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private HealthChannel(BluetoothDevice device, BluetoothHealthAppConfiguration config, 850676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelType) { 851676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelFd = null; 852676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mDevice = device; 853676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mConfig = config; 854676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mState = BluetoothHealth.STATE_CHANNEL_DISCONNECTED; 855676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelType = channelType; 856676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelId = -1; 857676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 858676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 859676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 860676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Channel state event from Hal 861676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private class ChannelStateEvent { 862676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mAppId; 863676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie byte[] mAddr; 864676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mCfgIndex; 865676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mChannelId; 866676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int mState; 867676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie FileDescriptor mFd; 868676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 869676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private ChannelStateEvent(int appId, byte[] addr, int cfgIndex, 870676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie int channelId, int state, FileDescriptor fileDescriptor) { 871676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAppId = appId; 872676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mAddr = addr; 873676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mCfgIndex = cfgIndex; 874676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mState = state; 875676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mChannelId = channelId; 876676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie mFd = fileDescriptor; 877676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 878676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie } 879676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 880676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // Constants matching Hal header file bt_hl.h 881676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_app_reg_state_t 882676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_REG_SUCCESS = 0; 883676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_REG_FAILED = 1; 884676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_DEREG_SUCCESS = 2; 885676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int APP_REG_STATE_DEREG_FAILED = 3; 886676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 887676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_channel_state_t 888676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_CONNECTING = 0; 889676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_CONNECTED = 1; 890676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DISCONNECTING = 2; 891676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DISCONNECTED = 3; 892676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CONN_STATE_DESTROYED = 4; 893676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 894676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_mdep_role_t 895676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MDEP_ROLE_SOURCE = 0; 896676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int MDEP_ROLE_SINK = 1; 897676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 898676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie // bthl_channel_type_t 899676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_RELIABLE = 0; 900676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_STREAMING = 1; 901676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private static final int CHANNEL_TYPE_ANY =2; 902676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie 903676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native static void classInitNative(); 9046654f5c903de510a70f9e72cd5ad7837b615d93ffredc private native void initializeNative(); 9056654f5c903de510a70f9e72cd5ad7837b615d93ffredc private native void cleanupNative(); 906676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native int registerHealthAppNative(int dataType, int role, String name, int channelType); 907676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native boolean unregisterHealthAppNative(int appId); 908676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native int connectChannelNative(byte[] btAddress, int appId); 909676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie private native boolean disconnectChannelNative(int channelId); 91074ae04c73312403e89db0f8e9bd9601d403b4783fredc 911676cb1bdd1c14c7af56562bab51f168e7f8f6d62Matthew Xie} 912