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