19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/*
2f04335f899f2cce69f843692a3cb9cec229683c2tturney * Copyright (C) 2017 The Android Open Source Project
39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
4f04335f899f2cce69f843692a3cb9cec229683c2tturney * Licensed under the Apache License, Version 2.0 (the "License");
5f04335f899f2cce69f843692a3cb9cec229683c2tturney * you may not use this file except in compliance with the License.
6f04335f899f2cce69f843692a3cb9cec229683c2tturney * You may obtain a copy of the License at
79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
8f04335f899f2cce69f843692a3cb9cec229683c2tturney *      http://www.apache.org/licenses/LICENSE-2.0
99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software
11f04335f899f2cce69f843692a3cb9cec229683c2tturney * distributed under the License is distributed on an "AS IS" BASIS,
12f04335f899f2cce69f843692a3cb9cec229683c2tturney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f04335f899f2cce69f843692a3cb9cec229683c2tturney * See the License for the specific language governing permissions and
14f04335f899f2cce69f843692a3cb9cec229683c2tturney * limitations under the License.
159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage com.googlecode.android_scripting.facade.bluetooth;
189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.app.Service;
209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothA2dp;
217b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwalimport android.bluetooth.BluetoothA2dpSink;
229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothAdapter;
239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothDevice;
249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothHeadset;
257b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwalimport android.bluetooth.BluetoothHeadsetClient;
2609d1d71d52031355d43ac30885025ef3bd36043aHansong Zhangimport android.bluetooth.BluetoothHidDevice;
2716f89b8cb5f2322ea354e18abbe0289db648a882Hansong Zhangimport android.bluetooth.BluetoothHidHost;
2809d1d71d52031355d43ac30885025ef3bd36043aHansong Zhangimport android.bluetooth.BluetoothManager;
29fc6e4af002e75301e13ddf524c0317e3a52be858tturneyimport android.bluetooth.BluetoothMap;
3075dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzoimport android.bluetooth.BluetoothMapClient;
3109d1d71d52031355d43ac30885025ef3bd36043aHansong Zhangimport android.bluetooth.BluetoothPan;
3248e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwalimport android.bluetooth.BluetoothPbapClient;
3348e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwalimport android.bluetooth.BluetoothProfile;
349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothUuid;
359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.BroadcastReceiver;
369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.Context;
379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.Intent;
389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.IntentFilter;
399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.os.Bundle;
409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.os.ParcelUuid;
419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.Log;
439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.EventFacade;
449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.FacadeManager;
459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.jsonrpc.RpcReceiver;
469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.Rpc;
47f0a094f3709187319222e64d8434f168ad8ffac9Jack Heimport com.googlecode.android_scripting.rpc.RpcDefault;
48f0a094f3709187319222e64d8434f168ad8ffac9Jack Heimport com.googlecode.android_scripting.rpc.RpcOptional;
4909d1d71d52031355d43ac30885025ef3bd36043aHansong Zhangimport com.googlecode.android_scripting.rpc.RpcParameter;
509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
51d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadiimport org.json.JSONArray;
52d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadiimport org.json.JSONException;
53d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
54e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.ArrayList;
55e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.Arrays;
56e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.Collections;
57e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.HashMap;
58e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.List;
59e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singhimport java.util.Map;
60e76a08babeec457d3ec28d24d91c833fbd223ba5Ashutosh Singh
619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic class BluetoothConnectionFacade extends RpcReceiver {
629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Service mService;
6455b68b3c0456f5e96edf37845785efb4d9a9848ctturney    private final Context mContext;
659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final BluetoothAdapter mBluetoothAdapter;
6655b68b3c0456f5e96edf37845785efb4d9a9848ctturney    private final BluetoothManager mBluetoothManager;
679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final BluetoothPairingHelper mPairingHelper;
689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Map<String, BroadcastReceiver> listeningDevices;
699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final EventFacade mEventFacade;
709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mDiscoverConnectFilter;
729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mPairingFilter;
739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mBondFilter;
749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mA2dpStateChangeFilter;
757b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private final IntentFilter mA2dpSinkStateChangeFilter;
769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mHidStateChangeFilter;
7709d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang    private final IntentFilter mHidDeviceStateChangeFilter;
789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mHspStateChangeFilter;
797b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private final IntentFilter mHfpClientStateChangeFilter;
8048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    private final IntentFilter mPbapClientStateChangeFilter;
81f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal    private final IntentFilter mPanStateChangeFilter;
8275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo    private final IntentFilter mMapClientStateChangeFilter;
83fc6e4af002e75301e13ddf524c0317e3a52be858tturney    private final IntentFilter mMapStateChangeFilter;
849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Bundle mGoodNews;
869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Bundle mBadNews;
879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothA2dpFacade mA2dpProfile;
897b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private BluetoothA2dpSinkFacade mA2dpSinkProfile;
909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothHidFacade mHidProfile;
9109d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang    private BluetoothHidDeviceFacade mHidDeviceProfile;
929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothHspFacade mHspProfile;
937b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private BluetoothHfpClientFacade mHfpClientProfile;
9448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    private BluetoothPbapClientFacade mPbapClientProfile;
95f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal    private BluetoothPanFacade mPanProfile;
9675dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo    private BluetoothMapClientFacade mMapClientProfile;
97fc6e4af002e75301e13ddf524c0317e3a52be858tturney    private BluetoothMapFacade mMapProfile;
98fc6e4af002e75301e13ddf524c0317e3a52be858tturney    private ArrayList<String> mDeviceMonitorList;
999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public BluetoothConnectionFacade(FacadeManager manager) {
1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        super(manager);
1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService = manager.getService();
10355b68b3c0456f5e96edf37845785efb4d9a9848ctturney        mContext = mService.getApplicationContext();
1049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
10555b68b3c0456f5e96edf37845785efb4d9a9848ctturney        mBluetoothManager = (BluetoothManager) mContext.getSystemService(
10655b68b3c0456f5e96edf37845785efb4d9a9848ctturney                Service.BLUETOOTH_SERVICE);
107fc6e4af002e75301e13ddf524c0317e3a52be858tturney        mDeviceMonitorList = new ArrayList<String>();
1089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        // Use a synchronized map to avoid racing problems
1099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices = Collections.synchronizedMap(new HashMap<String, BroadcastReceiver>());
1109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mEventFacade = manager.getReceiver(EventFacade.class);
11281c9640b1c3fa42892c2de6a18cc65aec8de2c4etturney        mPairingHelper = new BluetoothPairingHelper(mEventFacade);
1139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mA2dpProfile = manager.getReceiver(BluetoothA2dpFacade.class);
1147b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkProfile = manager.getReceiver(BluetoothA2dpSinkFacade.class);
1159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHidProfile = manager.getReceiver(BluetoothHidFacade.class);
11609d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang        mHidDeviceProfile = manager.getReceiver(BluetoothHidDeviceFacade.class);
1179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHspProfile = manager.getReceiver(BluetoothHspFacade.class);
1187b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientProfile = manager.getReceiver(BluetoothHfpClientFacade.class);
11948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientProfile = manager.getReceiver(BluetoothPbapClientFacade.class);
120f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanProfile = manager.getReceiver(BluetoothPanFacade.class);
12175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientProfile = manager.getReceiver(BluetoothMapClientFacade.class);
122fc6e4af002e75301e13ddf524c0317e3a52be858tturney        mMapProfile = manager.getReceiver(BluetoothMapFacade.class);
1239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
1259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter.addAction(BluetoothDevice.ACTION_UUID);
1269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
1279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
1299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
13042ef337b1976d1cbd7b71d531d8cc4365df29471tturney        mPairingFilter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
1319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter.setPriority(999);
1329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
1349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter.addAction(BluetoothDevice.ACTION_FOUND);
1359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
1369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mA2dpStateChangeFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
1387b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkStateChangeFilter =
1397b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            new IntentFilter(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
1407b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHidStateChangeFilter =
14116f89b8cb5f2322ea354e18abbe0289db648a882Hansong Zhang            new IntentFilter(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
14209d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang        mHidDeviceStateChangeFilter =
14309d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang                new IntentFilter(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
1449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHspStateChangeFilter = new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
1457b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientStateChangeFilter =
1467b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            new IntentFilter(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
14748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientStateChangeFilter =
14848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            new IntentFilter(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
149f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanStateChangeFilter =
150f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal            new IntentFilter(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
15175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientStateChangeFilter =
15275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            new IntentFilter(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
153fc6e4af002e75301e13ddf524c0317e3a52be858tturney        mMapStateChangeFilter =
154fc6e4af002e75301e13ddf524c0317e3a52be858tturney            new IntentFilter(BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
1559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mGoodNews = new Bundle();
1579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mGoodNews.putBoolean("Status", true);
1589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBadNews = new Bundle();
1599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBadNews.putBoolean("Status", false);
1609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void unregisterCachedListener(String listenerId) {
1639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BroadcastReceiver listener = listeningDevices.remove(listenerId);
1649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listener != null) {
1659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mService.unregisterReceiver(listener);
1669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    /**
1709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     * Connect to a specific device upon its discovery
1719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     */
1729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class DiscoverConnectReceiver extends BroadcastReceiver {
1739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
1749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private BluetoothDevice mDevice;
1759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        /**
1779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * Constructor
1789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         *
1799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * @param deviceID Either the device alias name or mac address.
180d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi         * @param bond     If true, bond the device only.
1819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         */
1829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public DiscoverConnectReceiver(String deviceID) {
1839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            super();
1849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
1859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
1889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
1899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
1909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // The specified device is found.
1919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
1929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
1949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Found device " + device.getAliasName() + " for connection.");
1959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mBluetoothAdapter.cancelDiscovery();
1969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mDevice = device;
1979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
198d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                // After discovery stops.
1999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
2009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (mDevice == null) {
2019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Device " + mDeviceID + " not discovered.");
2029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mEventFacade.postEvent("Bond" + mDeviceID, mBadNews);
2039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    return;
2049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                boolean status = mDevice.fetchUuidsWithSdp();
2069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                Log.d("Initiated ACL connection: " + status);
2079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
2089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
2109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Initiating connections.");
2119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    connectProfile(device, mDeviceID);
2129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mService.unregisterReceiver(listeningDevices.remove("Connect" + mDeviceID));
2139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    /**
2199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     * Connect to a specific device upon its discovery
2209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     */
2219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class DiscoverBondReceiver extends BroadcastReceiver {
2229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
2239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private BluetoothDevice mDevice = null;
2249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private boolean started = false;
2259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        /**
2279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * Constructor
2289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         *
2299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * @param deviceID Either the device alias name or Mac address.
2309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         */
2319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public DiscoverBondReceiver(String deviceID) {
2329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            super();
2339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
2349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
2379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
2389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
2399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // The specified device is found.
2409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
2419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
2439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Found device " + device.getAliasName() + " for connection.");
2449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mBluetoothAdapter.cancelDiscovery();
2459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mDevice = device;
2469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
247d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                // After discovery stops.
2489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
2499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (mDevice == null) {
2509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Device " + mDeviceID + " was not discovered.");
2519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mEventFacade.postEvent("Bond", mBadNews);
2529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    return;
2539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                // Attempt to initiate bonding.
2559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (!started) {
2569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Bond with " + mDevice.getAliasName());
2579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    if (mDevice.createBond()) {
2589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        started = true;
2599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.d("Bonding started.");
2609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    } else {
2619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.e("Failed to bond with " + mDevice.getAliasName());
2629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mEventFacade.postEvent("Bond", mBadNews);
2639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mService.unregisterReceiver(listeningDevices.remove("Bond" + mDeviceID));
2649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    }
2659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
2679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                Log.d("Bond state changing.");
2689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
2709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
2719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("New state is " + state);
2729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    if (state == BluetoothDevice.BOND_BONDED) {
2739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.d("Bonding with " + mDeviceID + " successful.");
2749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mEventFacade.postEvent("Bond" + mDeviceID, mGoodNews);
2759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mService.unregisterReceiver(listeningDevices.remove("Bond" + mDeviceID));
2769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    }
2779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class ConnectStateChangeReceiver extends BroadcastReceiver {
2839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
2849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public ConnectStateChangeReceiver(String deviceID) {
2869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
2879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
2909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
291fc6e4af002e75301e13ddf524c0317e3a52be858tturney            // no matter what the action, just push it...
2929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
2935ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            Log.d("Action received: " + action);
2945ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
2959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // Check if received the specified device
2979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (!BluetoothFacade.deviceMatch(device, mDeviceID)) {
2985ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                Log.e("Action devices does match act: " + device + " exp " + mDeviceID);
2999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                return;
3009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
301d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            // Find the state.
302d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
303d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            if (state == -1) {
304d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                Log.e("Action does not have a state.");
305d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                return;
306d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
307d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
3085ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            int profile = -1;
3095ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            switch (action) {
3105ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
3115ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.A2DP;
3125ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
31316f89b8cb5f2322ea354e18abbe0289db648a882Hansong Zhang                case BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED:
31416f89b8cb5f2322ea354e18abbe0289db648a882Hansong Zhang                    profile = BluetoothProfile.HID_HOST;
3155ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3165ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
3175ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.HEADSET;
3185ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3195ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
3205ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.PAN;
3215ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3225ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
3235ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.HEADSET_CLIENT;
3245ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3255ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
3265ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.A2DP_SINK;
3275ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3285ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
3295ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.PBAP_CLIENT;
3305ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
33175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
33275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    profile = BluetoothProfile.MAP_CLIENT;
33375dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    break;
3345ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            }
3355ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
3365ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            if (profile == -1) {
3375ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                Log.e("Action does not match any given profiles " + action);
3385ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            }
3395ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
3405ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            // Post an event to Facade.
341fc6e4af002e75301e13ddf524c0317e3a52be858tturney            Bundle news = new Bundle();
342fc6e4af002e75301e13ddf524c0317e3a52be858tturney            news.putInt("profile", profile);
343fc6e4af002e75301e13ddf524c0317e3a52be858tturney            news.putInt("state", state);
344fc6e4af002e75301e13ddf524c0317e3a52be858tturney            news.putString("addr", device.getAddress());
345fc6e4af002e75301e13ddf524c0317e3a52be858tturney            news.putString("action", action);
346fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mEventFacade.postEvent("BluetoothProfileConnectionStateChanged", news);
3479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
3489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
3499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
350d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
351d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Converts a given JSONArray to an ArrayList of Integers
352d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
353d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param jsonArray the JSONArray to be converted
354d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @return <code>List<Integer></></code> the converted list of Integers
355d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
356d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private List<Integer> jsonArrayToIntegerList(JSONArray jsonArray) throws JSONException {
357d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        if (jsonArray == null) {
358d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            return null;
359d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
360d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        List<Integer> intArray = new ArrayList<Integer>();
361d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (int i = 0; i < jsonArray.length(); i++) {
362d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            intArray.add(jsonArray.getInt(i));
363d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
364d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        return intArray;
365d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
366d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
367d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
368fc6e4af002e75301e13ddf524c0317e3a52be858tturney    @Rpc(description = "Start monitoring state changes for input device.")
369fc6e4af002e75301e13ddf524c0317e3a52be858tturney    public void bluetoothStartConnectionStateChangeMonitor(
370fc6e4af002e75301e13ddf524c0317e3a52be858tturney        @RpcParameter(name = "deviceID",
371fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    description = "Name or MAC address of a bluetooth device.")
372fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    String deviceID) {
373fc6e4af002e75301e13ddf524c0317e3a52be858tturney        if (!mDeviceMonitorList.contains(deviceID)) {
374fc6e4af002e75301e13ddf524c0317e3a52be858tturney            ConnectStateChangeReceiver receiver = new ConnectStateChangeReceiver(deviceID);
375fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mA2dpStateChangeFilter);
376fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mA2dpSinkStateChangeFilter);
377fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mHidStateChangeFilter);
378fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mHspStateChangeFilter);
379fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mHfpClientStateChangeFilter);
380fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mPbapClientStateChangeFilter);
381fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mPanStateChangeFilter);
382fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mMapClientStateChangeFilter);
383fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mService.registerReceiver(receiver, mMapStateChangeFilter);
384fc6e4af002e75301e13ddf524c0317e3a52be858tturney            listeningDevices.put("StateChangeListener:" + deviceID, receiver);
385fc6e4af002e75301e13ddf524c0317e3a52be858tturney        }
386d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
387d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
388d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
389d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Connect on all the profiles to the given Bluetooth device
390d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
391d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device   The <code>BluetoothDevice</code> to connect to
392d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID Name (String) of the device to connect to
393d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
3949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void connectProfile(BluetoothDevice device, String deviceID) {
3959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(mPairingHelper, mPairingFilter);
3969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ParcelUuid[] deviceUuids = device.getUuids();
39775dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        Log.d("Device uuid is " + Arrays.toString(deviceUuids));
3989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (deviceUuids == null) {
3997b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            mEventFacade.postEvent("BluetoothProfileConnectionEvent", mBadNews);
4009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4017b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        Log.d("Connecting to " + device.getAliasName());
4029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothA2dpFacade.SINK_UUIDS, deviceUuids)) {
403fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mA2dpProfile.a2dpConnect(device);
4049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4057b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothA2dpSinkFacade.SOURCE_UUIDS, deviceUuids)) {
406fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mA2dpSinkProfile.a2dpSinkConnect(device);
4077b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        }
4089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothHidFacade.UUIDS, deviceUuids)) {
409fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mHidProfile.hidConnect(device);
4109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothHspFacade.UUIDS, deviceUuids)) {
412fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mHspProfile.hspConnect(device);
4139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4147b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothHfpClientFacade.UUIDS, deviceUuids)) {
415fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mHfpClientProfile.hfpClientConnect(device);
416fc6e4af002e75301e13ddf524c0317e3a52be858tturney        }
417fc6e4af002e75301e13ddf524c0317e3a52be858tturney        if (BluetoothUuid.containsAnyUuid(BluetoothMapClientFacade.MAP_UUIDS, deviceUuids)) {
418fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mMapClientProfile.mapClientConnect(device);
4197b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        }
42002e949859dc20c9ab6d0a79688eff87beae68d61tturney        if (BluetoothUuid.containsAnyUuid(BluetoothPanFacade.UUIDS, deviceUuids)) {
421fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mPanProfile.panConnect(device);
422bb50bfa1e057c027dda0027a08372c91b529177eSanket Agarwal        }
42348e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothPbapClientFacade.UUIDS, deviceUuids)) {
424fc6e4af002e75301e13ddf524c0317e3a52be858tturney            mPbapClientProfile.pbapClientConnect(device);
42575dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        }
4269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.unregisterReceiver(mPairingHelper);
4279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
4289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
429d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
430d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Disconnect on all available profiles from the given device
431d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
432d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device   The <code>BluetoothDevice</code> to disconnect from
433d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID Name (String) of the device to disconnect from
434d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
4357b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private void disconnectProfiles(BluetoothDevice device, String deviceID) {
4367b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        Log.d("Disconnecting device " + device);
4377b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        // Blindly disconnect all profiles. We may not have some of them connected so that will be a
4387b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        // null op.
4397b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpProfile.a2dpDisconnect(device);
4407b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkProfile.a2dpSinkDisconnect(device);
4417b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHidProfile.hidDisconnect(device);
44209d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang        mHidDeviceProfile.hidDeviceDisconnect(device);
4437b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHspProfile.hspDisconnect(device);
4447b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientProfile.hfpClientDisconnect(device);
44548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientProfile.pbapClientDisconnect(device);
446f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanProfile.panDisconnect(device);
44775dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientProfile.mapClientDisconnect(device);
4487b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    }
4497b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal
450d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
451d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Disconnect from specific profiles provided in the given List of profiles.
452d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
453d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device     The {@link BluetoothDevice} to disconnect from
454d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID   Name/BDADDR (String) of the device to disconnect from
455d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param profileIds The list of profiles we want to disconnect on.
456d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
457d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private void disconnectProfiles(BluetoothDevice device, String deviceID,
458d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            List<Integer> profileIds) {
459d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        boolean result;
460d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (int profileId : profileIds) {
461d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            switch (profileId) {
462d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.A2DP_SINK:
463fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mA2dpSinkProfile.a2dpSinkDisconnect(device);
464d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
465d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.A2DP:
466fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mA2dpProfile.a2dpDisconnect(device);
467d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
46816f89b8cb5f2322ea354e18abbe0289db648a882Hansong Zhang                case BluetoothProfile.HID_HOST:
469fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mHidProfile.hidDisconnect(device);
470d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
47109d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang                case BluetoothProfile.HID_DEVICE:
47209d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang                    mHidDeviceProfile.hidDeviceDisconnect(device);
47309d1d71d52031355d43ac30885025ef3bd36043aHansong Zhang                    break;
474d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.HEADSET:
475fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mHspProfile.hspDisconnect(device);
476d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
477d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.HEADSET_CLIENT:
478fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mHfpClientProfile.hfpClientDisconnect(device);
479fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    break;
480fc6e4af002e75301e13ddf524c0317e3a52be858tturney                case BluetoothProfile.PAN:
481fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mPanProfile.panDisconnect(device);
482d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
483d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.PBAP_CLIENT:
484fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mPbapClientProfile.pbapClientDisconnect(device);
485d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
48675dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                case BluetoothProfile.MAP_CLIENT:
487fc6e4af002e75301e13ddf524c0317e3a52be858tturney                    mMapClientProfile.mapDisconnect(device);
48875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    break;
489d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                default:
490d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Log.d("Unknown Profile Id to disconnect from. Quitting");
491d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    return; // returns on the first unknown profile  it encounters.
492d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
493d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
494d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
495d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
4969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Start intercepting all bluetooth connection pop-ups.")
497f0a094f3709187319222e64d8434f168ad8ffac9Jack He    public void bluetoothStartPairingHelper(
498f0a094f3709187319222e64d8434f168ad8ffac9Jack He        @RpcParameter(name = "autoConfirm",
499f0a094f3709187319222e64d8434f168ad8ffac9Jack He                    description = "Whether connection should be auto confirmed")
500f0a094f3709187319222e64d8434f168ad8ffac9Jack He        @RpcDefault("true") @RpcOptional
501f0a094f3709187319222e64d8434f168ad8ffac9Jack He        Boolean autoConfirm) {
502f0a094f3709187319222e64d8434f168ad8ffac9Jack He        Log.d("Staring pairing helper");
503f0a094f3709187319222e64d8434f168ad8ffac9Jack He        mPairingHelper.setAutoConfirm(autoConfirm);
5049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(mPairingHelper, mPairingFilter);
5059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
5069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
5079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Return a list of devices connected through bluetooth")
5089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public List<BluetoothDevice> bluetoothGetConnectedDevices() {
5099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ArrayList<BluetoothDevice> results = new ArrayList<BluetoothDevice>();
5109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (BluetoothDevice bd : mBluetoothAdapter.getBondedDevices()) {
5119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (bd.isConnected()) {
5129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                results.add(bd);
5139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
5149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return results;
5169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
5179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
51855b68b3c0456f5e96edf37845785efb4d9a9848ctturney    @Rpc(description = "Return a list of devices connected through bluetooth LE")
51955b68b3c0456f5e96edf37845785efb4d9a9848ctturney    public List<BluetoothDevice> bluetoothGetConnectedLeDevices(Integer profile) {
52055b68b3c0456f5e96edf37845785efb4d9a9848ctturney        return mBluetoothManager.getConnectedDevices(profile);
52155b68b3c0456f5e96edf37845785efb4d9a9848ctturney    }
52255b68b3c0456f5e96edf37845785efb4d9a9848ctturney
523b6ccc67c1081ff6bb4f3a5fc9b32af79b058e058tturney    @Rpc(description = "Bluetooth init Bond by Mac Address")
524b6ccc67c1081ff6bb4f3a5fc9b32af79b058e058tturney    public boolean bluetoothBond(@RpcParameter(name = "macAddress") String macAddress) {
525b6ccc67c1081ff6bb4f3a5fc9b32af79b058e058tturney        return mBluetoothAdapter.getRemoteDevice(macAddress).createBond();
526b6ccc67c1081ff6bb4f3a5fc9b32af79b058e058tturney    }
527b6ccc67c1081ff6bb4f3a5fc9b32af79b058e058tturney
5289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Return true if a bluetooth device is connected.")
5299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothIsDeviceConnected(String deviceID) {
5309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (BluetoothDevice bd : mBluetoothAdapter.getBondedDevices()) {
5319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (BluetoothFacade.deviceMatch(bd, deviceID)) {
5329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                return bd.isConnected();
5339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
5349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return false;
5369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
5379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
53848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    @Rpc(description = "Return list of connected bluetooth devices over a profile",
539d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "List of devices connected over the profile")
54048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    public List<BluetoothDevice> bluetoothGetConnectedDevicesOnProfile(
54148e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            @RpcParameter(name = "profileId",
542d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "profileId same as BluetoothProfile")
543d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer profileId) {
54448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        BluetoothProfile profile = null;
54548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        switch (profileId) {
54648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.A2DP_SINK:
54748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mA2dpSinkProfile.bluetoothA2dpSinkGetConnectedDevices();
54848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.HEADSET_CLIENT:
54948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mHfpClientProfile.bluetoothHfpClientGetConnectedDevices();
55048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.PBAP_CLIENT:
55148e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mPbapClientProfile.bluetoothPbapClientGetConnectedDevices();
55275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            case BluetoothProfile.MAP_CLIENT:
55375dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                return mMapClientProfile.bluetoothMapClientGetConnectedDevices();
55448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            default:
55548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                Log.w("Profile id " + profileId + " is not yet supported.");
55648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return new ArrayList<BluetoothDevice>();
55748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        }
55848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    }
55948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal
5609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Connect to a specified device once it's discovered.",
561d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether discovery started successfully.")
5629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothDiscoverAndConnect(
5639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
564d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
565d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) {
5669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter.cancelDiscovery();
5679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey(deviceID)) {
5689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("This device is already in the process of discovery and connecting.");
5699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
5709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(deviceID);
5729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.put("Connect" + deviceID, receiver);
5739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(receiver, mDiscoverConnectFilter);
5749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mBluetoothAdapter.startDiscovery();
5759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
5769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
5779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Bond to a specified device once it's discovered.",
578d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether discovery started successfully. ")
5799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothDiscoverAndBond(
5809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
581d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
582d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) {
5839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter.cancelDiscovery();
5849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey(deviceID)) {
5859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("This device is already in the process of discovery and bonding.");
5869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
5879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothFacade.deviceExists(mBluetoothAdapter.getBondedDevices(), deviceID)) {
5899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("Device " + deviceID + " is already bonded.");
5909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mEventFacade.postEvent("Bond" + deviceID, mGoodNews);
5919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
5929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        DiscoverBondReceiver receiver = new DiscoverBondReceiver(deviceID);
5949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey("Bond" + deviceID)) {
5959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mService.unregisterReceiver(listeningDevices.remove("Bond" + deviceID));
5969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
5979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.put("Bond" + deviceID, receiver);
5989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(receiver, mBondFilter);
5999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        Log.d("Start discovery for bonding.");
6009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mBluetoothAdapter.startDiscovery();
6019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Unbond a device.",
604d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether the device was successfully unbonded.")
6059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothUnbond(
6069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
607d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
608d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
6099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
6109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                deviceID);
6119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mDevice.removeBond();
6129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Connect to a device that is already bonded.")
6159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void bluetoothConnectBonded(
6169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
617d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
618d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
6199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
6209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                deviceID);
6219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        connectProfile(mDevice, deviceID);
6229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6247b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    @Rpc(description = "Disconnect from a device that is already connected.")
6257b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    public void bluetoothDisconnectConnected(
6267b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            @RpcParameter(name = "deviceID",
627d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
628d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
6297b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
6307b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal                deviceID);
6317b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        disconnectProfiles(mDevice, deviceID);
6327b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    }
6337b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal
634d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    @Rpc(description = "Disconnect on a profile from a device that is already connected.")
635d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    public void bluetoothDisconnectConnectedProfile(
636d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            @RpcParameter(name = "deviceID",
637d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
638d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID,
639d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            @RpcParameter(name = "profileSet",
640d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "List of profiles to disconnect from.")
641d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    JSONArray profileSet
642d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    ) throws Exception {
643d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
644d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                deviceID);
645d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        disconnectProfiles(mDevice, deviceID, jsonArrayToIntegerList(profileSet));
646d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
647d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
64802cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    @Rpc(description = "Change permissions for a profile.")
64902cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    public void bluetoothChangeProfileAccessPermission(
65002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "deviceID",
651d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
652d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID,
65302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "profileID",
654d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Number of Profile to change access permission")
655d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer profileID,
65602cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "access",
657d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Access level 0 = Unknown, 1 = Allowed, 2 = Rejected")
658d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer access
659d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    ) throws Exception {
66002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        if (access < 0 || access > 2) {
66102cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            Log.w("Unsupported access level.");
66202cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            return;
66302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        }
66402cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
66502cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                deviceID);
666d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        switch (profileID) {
66702cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            case BluetoothProfile.PBAP:
66802cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                mDevice.setPhonebookAccessPermission(access);
66902cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                break;
67002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            default:
67102cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                Log.w("Unsupported profile access change.");
67202cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        }
67302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    }
67402cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo
67502cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo
6769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Override
6779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void shutdown() {
678d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (BroadcastReceiver receiver : listeningDevices.values()) {
679d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            try {
680d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                mService.unregisterReceiver(receiver);
681d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            } catch (IllegalArgumentException ex) {
682d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                Log.e("Failed to unregister " + ex);
683d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
6849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.clear();
68602e949859dc20c9ab6d0a79688eff87beae68d61tturney        mService.unregisterReceiver(mPairingHelper);
6879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li}
689fc6e4af002e75301e13ddf524c0317e3a52be858tturney
690