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