BluetoothConnectionFacade.java revision 42ef337b1976d1cbd7b71d531d8cc4365df29471
19f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li/*
29f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Copyright (C) 2016 Google Inc.
39f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
49f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Licensed under the Apache License, Version 2.0 (the "License"); you may not
59f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * use this file except in compliance with the License. You may obtain a copy of
69f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * the License at
79f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
89f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * http://www.apache.org/licenses/LICENSE-2.0
99f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li *
109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * Unless required by applicable law or agreed to in writing, software
119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * License for the specific language governing permissions and limitations under
149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li * the License.
159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li */
169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipackage com.googlecode.android_scripting.facade.bluetooth;
189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.ArrayList;
2075dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzoimport java.util.Arrays;
219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Collections;
229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.HashMap;
239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.List;
249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport java.util.Map;
259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.app.Service;
279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothA2dp;
287b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwalimport android.bluetooth.BluetoothA2dpSink;
299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothAdapter;
309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothDevice;
3155b68b3c0456f5e96edf37845785efb4d9a9848ctturneyimport android.bluetooth.BluetoothManager;
329f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothHeadset;
337b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwalimport android.bluetooth.BluetoothHeadsetClient;
349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothInputDevice;
3575dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzoimport android.bluetooth.BluetoothMapClient;
3648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwalimport android.bluetooth.BluetoothPbapClient;
3748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwalimport android.bluetooth.BluetoothProfile;
38f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwalimport android.bluetooth.BluetoothPan;
399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.bluetooth.BluetoothUuid;
409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.BroadcastReceiver;
419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.Context;
429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.Intent;
439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.content.IntentFilter;
449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.os.Bundle;
459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport android.os.ParcelUuid;
469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.Log;
489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.EventFacade;
499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.facade.FacadeManager;
5081c9640b1c3fa42892c2de6a18cc65aec8de2c4etturneyimport com.googlecode.android_scripting.facade.bluetooth.BluetoothPairingHelper;
519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.jsonrpc.RpcReceiver;
529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.Rpc;
539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Liimport com.googlecode.android_scripting.rpc.RpcParameter;
549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
55d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadiimport org.json.JSONArray;
56d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadiimport org.json.JSONException;
57d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Lipublic class BluetoothConnectionFacade extends RpcReceiver {
599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Service mService;
6155b68b3c0456f5e96edf37845785efb4d9a9848ctturney    private final Context mContext;
629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final BluetoothAdapter mBluetoothAdapter;
6355b68b3c0456f5e96edf37845785efb4d9a9848ctturney    private final BluetoothManager mBluetoothManager;
649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final BluetoothPairingHelper mPairingHelper;
659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Map<String, BroadcastReceiver> listeningDevices;
669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final EventFacade mEventFacade;
679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mDiscoverConnectFilter;
699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mPairingFilter;
709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mBondFilter;
719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mA2dpStateChangeFilter;
727b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private final IntentFilter mA2dpSinkStateChangeFilter;
739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mHidStateChangeFilter;
749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final IntentFilter mHspStateChangeFilter;
757b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private final IntentFilter mHfpClientStateChangeFilter;
7648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    private final IntentFilter mPbapClientStateChangeFilter;
77f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal    private final IntentFilter mPanStateChangeFilter;
7875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo    private final IntentFilter mMapClientStateChangeFilter;
799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Bundle mGoodNews;
819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private final Bundle mBadNews;
829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothA2dpFacade mA2dpProfile;
847b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private BluetoothA2dpSinkFacade mA2dpSinkProfile;
859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothHidFacade mHidProfile;
869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private BluetoothHspFacade mHspProfile;
877b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private BluetoothHfpClientFacade mHfpClientProfile;
8848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    private BluetoothPbapClientFacade mPbapClientProfile;
89f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal    private BluetoothPanFacade mPanProfile;
9075dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo    private BluetoothMapClientFacade mMapClientProfile;
919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public BluetoothConnectionFacade(FacadeManager manager) {
939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        super(manager);
949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService = manager.getService();
9555b68b3c0456f5e96edf37845785efb4d9a9848ctturney        mContext = mService.getApplicationContext();
969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
9755b68b3c0456f5e96edf37845785efb4d9a9848ctturney        mBluetoothManager = (BluetoothManager) mContext.getSystemService(
9855b68b3c0456f5e96edf37845785efb4d9a9848ctturney                Service.BLUETOOTH_SERVICE);
999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        // Use a synchronized map to avoid racing problems
1009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices = Collections.synchronizedMap(new HashMap<String, BroadcastReceiver>());
1019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mEventFacade = manager.getReceiver(EventFacade.class);
10381c9640b1c3fa42892c2de6a18cc65aec8de2c4etturney        mPairingHelper = new BluetoothPairingHelper(mEventFacade);
1049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mA2dpProfile = manager.getReceiver(BluetoothA2dpFacade.class);
1057b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkProfile = manager.getReceiver(BluetoothA2dpSinkFacade.class);
1069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHidProfile = manager.getReceiver(BluetoothHidFacade.class);
1079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHspProfile = manager.getReceiver(BluetoothHspFacade.class);
1087b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientProfile = manager.getReceiver(BluetoothHfpClientFacade.class);
10948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientProfile = manager.getReceiver(BluetoothPbapClientFacade.class);
110f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanProfile = manager.getReceiver(BluetoothPanFacade.class);
11175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientProfile = manager.getReceiver(BluetoothMapClientFacade.class);
1129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
1149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter.addAction(BluetoothDevice.ACTION_UUID);
1159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mDiscoverConnectFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
1169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter = new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST);
1189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
11942ef337b1976d1cbd7b71d531d8cc4365df29471tturney        mPairingFilter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
1209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mPairingFilter.setPriority(999);
1219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
1239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter.addAction(BluetoothDevice.ACTION_FOUND);
1249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBondFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
1259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mA2dpStateChangeFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
1277b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkStateChangeFilter =
1287b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            new IntentFilter(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
1297b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHidStateChangeFilter =
1307b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            new IntentFilter(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
1319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mHspStateChangeFilter = new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
1327b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientStateChangeFilter =
1337b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            new IntentFilter(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
13448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientStateChangeFilter =
13548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            new IntentFilter(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
136f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanStateChangeFilter =
137f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal            new IntentFilter(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
13875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientStateChangeFilter =
13975dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            new IntentFilter(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
1409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mGoodNews = new Bundle();
1429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mGoodNews.putBoolean("Status", true);
1439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBadNews = new Bundle();
1449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBadNews.putBoolean("Status", false);
1459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void unregisterCachedListener(String listenerId) {
1489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BroadcastReceiver listener = listeningDevices.remove(listenerId);
1499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listener != null) {
1509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mService.unregisterReceiver(listener);
1519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
1539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    /**
1559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     * Connect to a specific device upon its discovery
1569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     */
1579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class DiscoverConnectReceiver extends BroadcastReceiver {
1589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
1599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private BluetoothDevice mDevice;
1609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        /**
1629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * Constructor
1639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         *
1649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * @param deviceID Either the device alias name or mac address.
165d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi         * @param bond     If true, bond the device only.
1669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         */
1679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public DiscoverConnectReceiver(String deviceID) {
1689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            super();
1699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
1709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
1719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
1729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
1739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
1749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
1759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // The specified device is found.
1769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
1779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
1799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Found device " + device.getAliasName() + " for connection.");
1809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mBluetoothAdapter.cancelDiscovery();
1819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mDevice = device;
1829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
183d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                // After discovery stops.
1849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
1859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (mDevice == null) {
1869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Device " + mDeviceID + " not discovered.");
1879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mEventFacade.postEvent("Bond" + mDeviceID, mBadNews);
1889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    return;
1899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
1909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                boolean status = mDevice.fetchUuidsWithSdp();
1919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                Log.d("Initiated ACL connection: " + status);
1929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
1939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
1949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
1959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Initiating connections.");
1969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    connectProfile(device, mDeviceID);
1979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mService.unregisterReceiver(listeningDevices.remove("Connect" + mDeviceID));
1989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
1999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    /**
2049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     * Connect to a specific device upon its discovery
2059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li     */
2069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class DiscoverBondReceiver extends BroadcastReceiver {
2079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
2089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private BluetoothDevice mDevice = null;
2099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private boolean started = false;
2109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        /**
2129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * Constructor
2139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         *
2149f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         * @param deviceID Either the device alias name or Mac address.
2159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li         */
2169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public DiscoverBondReceiver(String deviceID) {
2179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            super();
2189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
2199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
2229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
2239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
2249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // The specified device is found.
2259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (action.equals(BluetoothDevice.ACTION_FOUND)) {
2269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
2289f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Found device " + device.getAliasName() + " for connection.");
2299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mBluetoothAdapter.cancelDiscovery();
2309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mDevice = device;
2319f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
232d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                // After discovery stops.
2339f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
2349f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (mDevice == null) {
2359f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Device " + mDeviceID + " was not discovered.");
2369f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    mEventFacade.postEvent("Bond", mBadNews);
2379f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    return;
2389f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2399f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                // Attempt to initiate bonding.
2409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (!started) {
2419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("Bond with " + mDevice.getAliasName());
2429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    if (mDevice.createBond()) {
2439f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        started = true;
2449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.d("Bonding started.");
2459f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    } else {
2469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.e("Failed to bond with " + mDevice.getAliasName());
2479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mEventFacade.postEvent("Bond", mBadNews);
2489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mService.unregisterReceiver(listeningDevices.remove("Bond" + mDeviceID));
2499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    }
2509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
2529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                Log.d("Bond state changing.");
2539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                if (BluetoothFacade.deviceMatch(device, mDeviceID)) {
2559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
2569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    Log.d("New state is " + state);
2579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    if (state == BluetoothDevice.BOND_BONDED) {
2589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        Log.d("Bonding with " + mDeviceID + " successful.");
2599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mEventFacade.postEvent("Bond" + mDeviceID, mGoodNews);
2609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                        mService.unregisterReceiver(listeningDevices.remove("Bond" + mDeviceID));
2619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                    }
2629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                }
2639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
2649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
2669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public class ConnectStateChangeReceiver extends BroadcastReceiver {
2689f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        private final String mDeviceID;
2699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public ConnectStateChangeReceiver(String deviceID) {
2719f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mDeviceID = deviceID;
2729f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
2739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
2749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        @Override
2759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        public void onReceive(Context context, Intent intent) {
2769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            String action = intent.getAction();
2775ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            Log.d("Action received: " + action);
2785ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
2799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
2809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            // Check if received the specified device
2819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (!BluetoothFacade.deviceMatch(device, mDeviceID)) {
2825ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                Log.e("Action devices does match act: " + device + " exp " + mDeviceID);
2839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                return;
2849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
285d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            // Find the state.
286d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
287d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            if (state == -1) {
288d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                Log.e("Action does not have a state.");
289d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                return;
290d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
291d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
292d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            String connState = "";
293d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            if (state == BluetoothProfile.STATE_CONNECTED) {
294d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                connState = "Connecting";
295d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            } else if (state == BluetoothProfile.STATE_DISCONNECTED) {
296d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                connState = "Disconnecting";
297d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
2985ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
2995ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            int profile = -1;
3005ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            String listener = "";
3015ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            switch (action) {
3025ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED:
3035ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.A2DP;
304d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "A2dp" + connState + mDeviceID;
3055ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3065ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED:
3075ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.INPUT_DEVICE;
308d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "Hid" + connState + mDeviceID;
3095ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3105ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
3115ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.HEADSET;
312d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "Hsp" + connState + mDeviceID;
3135ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3145ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothPan.ACTION_CONNECTION_STATE_CHANGED:
3155ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.PAN;
316d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "Pan" + connState + mDeviceID;
3175ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3185ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED:
3195ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.HEADSET_CLIENT;
320d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "HfpClient" + connState + mDeviceID;
3215ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3225ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED:
3235ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.A2DP_SINK;
324d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "A2dpSink" + connState + mDeviceID;
3255ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
3265ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                case BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED:
3275ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    profile = BluetoothProfile.PBAP_CLIENT;
328d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    listener = "PbapClient" + connState + mDeviceID;
3295ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                    break;
33075dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                case BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED:
33175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    profile = BluetoothProfile.MAP_CLIENT;
33275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    listener = "MapClient" + connState + mDeviceID;
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                return;
3395ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            }
3405ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
3415ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal
3425ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal            // Post an event to Facade.
343d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            if ((state == BluetoothProfile.STATE_CONNECTED) || (state
344d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    == BluetoothProfile.STATE_DISCONNECTED)) {
3455ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                Bundle news = new Bundle();
3465ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                news.putInt("profile", profile);
3475ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                news.putInt("state", state);
3485ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                news.putString("addr", device.getAddress());
3495ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                mEventFacade.postEvent("BluetoothProfileConnectionStateChanged", news);
3505ecdad6eafb5085b4527e56a4916d624cbeb84f0Sanket Agarwal                unregisterCachedListener(listener);
3519f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
3529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
3539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
3549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
355d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
356d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Converts a given JSONArray to an ArrayList of Integers
357d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
358d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param jsonArray the JSONArray to be converted
359d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @return <code>List<Integer></></code> the converted list of Integers
360d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
361d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private List<Integer> jsonArrayToIntegerList(JSONArray jsonArray) throws JSONException {
362d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        if (jsonArray == null) {
363d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            return null;
364d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
365d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        List<Integer> intArray = new ArrayList<Integer>();
366d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (int i = 0; i < jsonArray.length(); i++) {
367d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            intArray.add(jsonArray.getInt(i));
368d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
369d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        return intArray;
370d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
371d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
372d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
373d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
374d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Helper function used by{@link connectProfile} & {@link disconnectProfiles} to handle a
375d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * successful return from a profile connect/disconnect call
376d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
377d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID      The device id string
378d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param profile       String representation of the profile - used to create keys in the
379d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *                      <code>listeningDevices</code> hashMap.
380d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param connState     String that denotes if this is called after a connect or disconnect
381d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *                      call.  Helps to share code between connect & disconnect
382d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param profileFilter The <code>IntentFilter</code> for this profile that we want to listen
383d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *                      on.
384d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
385d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private void handleConnectionStateChanged(String deviceID, String profile, String connState,
386d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            IntentFilter profileFilter) {
387d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        Log.d(connState + " " + profile);
388d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        ConnectStateChangeReceiver receiver = new ConnectStateChangeReceiver(deviceID);
389d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        mService.registerReceiver(receiver, profileFilter);
390d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        listeningDevices.put(profile + connState + deviceID, receiver);
391d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
392d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
393d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
394d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Helper function used by{@link connectProfile} & {@link disconnectProfiles} to handle a
395d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * unsuccessful return from a profile connect/disconnect call
396d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
397d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param profile   String representation of the profile - used to post an Event on the
398d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *                  <code>mEventFacade</code>
399d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param connState String that denotes if this is called after a connect or disconnect call.
400d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *                  Helps to share code between connect & disconnect
401d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
402d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private void handleConnectionStateChangeFailed(String profile, String connState) {
403d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        Log.d("Failed Starting " + profile + " " + connState);
404d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        Bundle badNews = (Bundle) mBadNews.clone();
405d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        badNews.putString("Type", profile);
406d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        mEventFacade.postEvent(connState, badNews);
407d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
408d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
409d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
410d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Connect on all the profiles to the given Bluetooth device
411d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
412d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device   The <code>BluetoothDevice</code> to connect to
413d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID Name (String) of the device to connect to
414d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
4159f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    private void connectProfile(BluetoothDevice device, String deviceID) {
4169f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(mPairingHelper, mPairingFilter);
4179f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ParcelUuid[] deviceUuids = device.getUuids();
41875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        Log.d("Device uuid is " + Arrays.toString(deviceUuids));
4199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (deviceUuids == null) {
4207b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            mEventFacade.postEvent("BluetoothProfileConnectionEvent", mBadNews);
4219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4227b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        Log.d("Connecting to " + device.getAliasName());
4239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothA2dpFacade.SINK_UUIDS, deviceUuids)) {
4249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            boolean status = mA2dpProfile.a2dpConnect(device);
4259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (status) {
426d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "A2dp", "Connecting", mA2dpStateChangeFilter);
4279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else {
428d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("a2dp", "Connect");
4299f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
4309f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4317b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothA2dpSinkFacade.SOURCE_UUIDS, deviceUuids)) {
4327b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            boolean status = mA2dpSinkProfile.a2dpSinkConnect(device);
4337b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            if (status) {
434d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "A2dpSink", "Connecting",
435d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        mA2dpSinkStateChangeFilter);
4367b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            } else {
437d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("a2dpsink", "Connect");
4387b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            }
4397b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        }
4409f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothHidFacade.UUIDS, deviceUuids)) {
4419f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            boolean status = mHidProfile.hidConnect(device);
4429f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (status) {
443d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "Hid", "Connecting", mHidStateChangeFilter);
4449f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else {
445d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("Hid", "Connect");
4469f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
4479f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4489f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothUuid.containsAnyUuid(BluetoothHspFacade.UUIDS, deviceUuids)) {
4499f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            boolean status = mHspProfile.hspConnect(device);
4509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (status) {
451d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "Hsp", "Connecting", mHspStateChangeFilter);
4529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            } else {
453d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("Hsp", "Connect");
4549f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
4559f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
4567b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothHfpClientFacade.UUIDS, deviceUuids)) {
4577b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            boolean status = mHfpClientProfile.hfpClientConnect(device);
4587b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            if (status) {
459d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "HfpClient", "Connecting",
460d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        mHfpClientStateChangeFilter);
4617b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            } else {
462d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("HfpClient", "Connect");
4637b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            }
4647b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        }
46502e949859dc20c9ab6d0a79688eff87beae68d61tturney        if (BluetoothUuid.containsAnyUuid(BluetoothPanFacade.UUIDS, deviceUuids)) {
46602e949859dc20c9ab6d0a79688eff87beae68d61tturney            boolean status = mPanProfile.panConnect(device);
46702e949859dc20c9ab6d0a79688eff87beae68d61tturney            if (status) {
468d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "Pan", "Connecting",
4699a632371bf1ace747eb6fde291eb0f8a0c28c215Ram Periathiruvadi                        mPanStateChangeFilter);
47002e949859dc20c9ab6d0a79688eff87beae68d61tturney            } else {
471d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("Pan", "Connect");
472bb50bfa1e057c027dda0027a08372c91b529177eSanket Agarwal            }
473bb50bfa1e057c027dda0027a08372c91b529177eSanket Agarwal        }
47448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        if (BluetoothUuid.containsAnyUuid(BluetoothPbapClientFacade.UUIDS, deviceUuids)) {
47548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            boolean status = mPbapClientProfile.pbapClientConnect(device);
47648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            if (status) {
477d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChanged(deviceID, "PbapClient", "Connecting",
478d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        mPbapClientStateChangeFilter);
47948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            } else {
480d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                handleConnectionStateChangeFailed("PbapClient", "Connect");
48102e949859dc20c9ab6d0a79688eff87beae68d61tturney            }
48202e949859dc20c9ab6d0a79688eff87beae68d61tturney        }
48375dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        if (BluetoothUuid.containsAnyUuid(BluetoothMapClientFacade.MAP_UUIDS, deviceUuids)) {
48475dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            boolean status = mMapClientProfile.mapClientConnect(device);
48575dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            if (status) {
48675dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                handleConnectionStateChanged(deviceID, "MapClient", "Connecting",
48775dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                        mMapClientStateChangeFilter);
48875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            } else {
48975dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                handleConnectionStateChangeFailed("MapClient", "Connect");
49075dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            }
49175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        }
4929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.unregisterReceiver(mPairingHelper);
4939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
4949f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
495d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
496d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Disconnect on all available profiles from the given device
497d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
498d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device   The <code>BluetoothDevice</code> to disconnect from
499d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID Name (String) of the device to disconnect from
500d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
5017b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    private void disconnectProfiles(BluetoothDevice device, String deviceID) {
5027b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        Log.d("Disconnecting device " + device);
5037b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        // Blindly disconnect all profiles. We may not have some of them connected so that will be a
5047b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        // null op.
5057b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpProfile.a2dpDisconnect(device);
5067b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mA2dpSinkProfile.a2dpSinkDisconnect(device);
5077b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHidProfile.hidDisconnect(device);
5087b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHspProfile.hspDisconnect(device);
5097b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        mHfpClientProfile.hfpClientDisconnect(device);
51048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        mPbapClientProfile.pbapClientDisconnect(device);
511f855841b2fe6ed4a5835bc7c7cb7e79bbccfec71Sanket Agarwal        mPanProfile.panDisconnect(device);
51275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo        mMapClientProfile.mapClientDisconnect(device);
5137b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    }
5147b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal
515d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    /**
516d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * Disconnect from specific profiles provided in the given List of profiles.
517d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     *
518d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param device     The {@link BluetoothDevice} to disconnect from
519d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param deviceID   Name/BDADDR (String) of the device to disconnect from
520d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     * @param profileIds The list of profiles we want to disconnect on.
521d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi     */
522d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    private void disconnectProfiles(BluetoothDevice device, String deviceID,
523d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            List<Integer> profileIds) {
524d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        boolean result;
525d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (int profileId : profileIds) {
526d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            switch (profileId) {
527d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.A2DP_SINK:
528d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mA2dpSinkProfile.a2dpSinkDisconnect(device);
529d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
530d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "A2dpSink", "Disconnecting",
531d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mA2dpSinkStateChangeFilter);
532d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
533d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("a2dpsink", "Disconnect");
534d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
535d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
536d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.A2DP:
537d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mA2dpProfile.a2dpDisconnect(device);
538d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
539d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "A2dp", "Disconnecting",
540d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mA2dpStateChangeFilter);
541d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
542d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("a2dp", "Disconnect");
543d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
544d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
545d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.INPUT_DEVICE:
546d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mHidProfile.hidDisconnect(device);
547d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
548d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "Hid", "Disconnecting",
549d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mHidStateChangeFilter);
550d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
551d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("Hid", "Disconnect");
552d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
553d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
554d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.HEADSET:
555d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mHspProfile.hspDisconnect(device);
556d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
557d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "Hsp", "Disconnecting",
558d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mHspStateChangeFilter);
559d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
560d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("Hsp", "Disconnect");
561d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
562d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
563d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.HEADSET_CLIENT:
564d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mHfpClientProfile.hfpClientDisconnect(device);
565d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
566d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "HfpClient", "Disconnecting",
567d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mHfpClientStateChangeFilter);
568d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
569d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("HfpClient", "Disconnect");
570d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
571d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
572d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                case BluetoothProfile.PBAP_CLIENT:
573d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    result = mPbapClientProfile.pbapClientDisconnect(device);
574d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    if (result) {
575d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChanged(deviceID, "PbapClient", "Disconnecting",
576d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                                mPbapClientStateChangeFilter);
577d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    } else {
578d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                        handleConnectionStateChangeFailed("PbapClient", "Disconnect");
579d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    }
580d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    break;
58175dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                case BluetoothProfile.MAP_CLIENT:
58275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    result = mMapClientProfile.mapDisconnect(device);
58375dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    if (result) {
58475dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                        handleConnectionStateChanged(deviceID, "MapClient", "Disconnecting",
58575dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                                mMapClientStateChangeFilter);
58675dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    } else {
58775dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                        handleConnectionStateChangeFailed("MapClient", "Disconnect");
58875dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    }
58975dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                    break;
590d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                default:
591d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Log.d("Unknown Profile Id to disconnect from. Quitting");
592d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    return; // returns on the first unknown profile  it encounters.
593d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
594d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        }
595d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
596d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
5979f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Start intercepting all bluetooth connection pop-ups.")
5989f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void bluetoothStartPairingHelper() {
5999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(mPairingHelper, mPairingFilter);
6009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Return a list of devices connected through bluetooth")
6039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public List<BluetoothDevice> bluetoothGetConnectedDevices() {
6049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        ArrayList<BluetoothDevice> results = new ArrayList<BluetoothDevice>();
6059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (BluetoothDevice bd : mBluetoothAdapter.getBondedDevices()) {
6069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (bd.isConnected()) {
6079f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                results.add(bd);
6089f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
6099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return results;
6119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
61355b68b3c0456f5e96edf37845785efb4d9a9848ctturney    @Rpc(description = "Return a list of devices connected through bluetooth LE")
61455b68b3c0456f5e96edf37845785efb4d9a9848ctturney    public List<BluetoothDevice> bluetoothGetConnectedLeDevices(Integer profile) {
61555b68b3c0456f5e96edf37845785efb4d9a9848ctturney        return mBluetoothManager.getConnectedDevices(profile);
61655b68b3c0456f5e96edf37845785efb4d9a9848ctturney    }
61755b68b3c0456f5e96edf37845785efb4d9a9848ctturney
6189f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Return true if a bluetooth device is connected.")
6199f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothIsDeviceConnected(String deviceID) {
6209f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        for (BluetoothDevice bd : mBluetoothAdapter.getBondedDevices()) {
6219f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            if (BluetoothFacade.deviceMatch(bd, deviceID)) {
6229f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                return bd.isConnected();
6239f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            }
6249f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6259f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return false;
6269f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6279f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
62848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    @Rpc(description = "Return list of connected bluetooth devices over a profile",
629d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "List of devices connected over the profile")
63048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    public List<BluetoothDevice> bluetoothGetConnectedDevicesOnProfile(
63148e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            @RpcParameter(name = "profileId",
632d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "profileId same as BluetoothProfile")
633d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer profileId) {
63448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        BluetoothProfile profile = null;
63548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        switch (profileId) {
63648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.A2DP_SINK:
63748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mA2dpSinkProfile.bluetoothA2dpSinkGetConnectedDevices();
63848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.HEADSET_CLIENT:
63948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mHfpClientProfile.bluetoothHfpClientGetConnectedDevices();
64048e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            case BluetoothProfile.PBAP_CLIENT:
64148e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return mPbapClientProfile.bluetoothPbapClientGetConnectedDevices();
64275dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo            case BluetoothProfile.MAP_CLIENT:
64375dc79a06c15dae01b07f09cfda374c828b45b4bJoseph Pirozzo                return mMapClientProfile.bluetoothMapClientGetConnectedDevices();
64448e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal            default:
64548e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                Log.w("Profile id " + profileId + " is not yet supported.");
64648e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal                return new ArrayList<BluetoothDevice>();
64748e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal        }
64848e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal    }
64948e46479b58eff2b6cf67b459f68f918375b5567Sanket Agarwal
6509f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Connect to a specified device once it's discovered.",
651d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether discovery started successfully.")
6529f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothDiscoverAndConnect(
6539f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
654d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
655d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) {
6569f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter.cancelDiscovery();
6579f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey(deviceID)) {
6589f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("This device is already in the process of discovery and connecting.");
6599f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
6609f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6619f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        DiscoverConnectReceiver receiver = new DiscoverConnectReceiver(deviceID);
6629f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.put("Connect" + deviceID, receiver);
6639f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(receiver, mDiscoverConnectFilter);
6649f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mBluetoothAdapter.startDiscovery();
6659f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Bond to a specified device once it's discovered.",
668d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether discovery started successfully. ")
6699f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothDiscoverAndBond(
6709f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
671d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
672d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) {
6739f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mBluetoothAdapter.cancelDiscovery();
6749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey(deviceID)) {
6759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("This device is already in the process of discovery and bonding.");
6769f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
6779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (BluetoothFacade.deviceExists(mBluetoothAdapter.getBondedDevices(), deviceID)) {
6799f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            Log.d("Device " + deviceID + " is already bonded.");
6809f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mEventFacade.postEvent("Bond" + deviceID, mGoodNews);
6819f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            return true;
6829f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6839f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        DiscoverBondReceiver receiver = new DiscoverBondReceiver(deviceID);
6849f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        if (listeningDevices.containsKey("Bond" + deviceID)) {
6859f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            mService.unregisterReceiver(listeningDevices.remove("Bond" + deviceID));
6869f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
6879f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.put("Bond" + deviceID, receiver);
6889f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        mService.registerReceiver(receiver, mBondFilter);
6899f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        Log.d("Start discovery for bonding.");
6909f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mBluetoothAdapter.startDiscovery();
6919f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
6929f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
6939f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Unbond a device.",
694d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            returns = "Whether the device was successfully unbonded.")
6959f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public Boolean bluetoothUnbond(
6969f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
697d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
698d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
6999f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
7009f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                deviceID);
7019f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        return mDevice.removeBond();
7029f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
7039f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
7049f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Rpc(description = "Connect to a device that is already bonded.")
7059f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void bluetoothConnectBonded(
7069f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li            @RpcParameter(name = "deviceID",
707d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
708d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
7099f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
7109f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li                deviceID);
7119f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        connectProfile(mDevice, deviceID);
7129f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
7139f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li
7147b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    @Rpc(description = "Disconnect from a device that is already connected.")
7157b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    public void bluetoothDisconnectConnected(
7167b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal            @RpcParameter(name = "deviceID",
717d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
718d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID) throws Exception {
7197b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
7207b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal                deviceID);
7217b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal        disconnectProfiles(mDevice, deviceID);
7227b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal    }
7237b8c49f4f5af2182a25f866a279270ccd72f080fSanket Agarwal
724d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    @Rpc(description = "Disconnect on a profile from a device that is already connected.")
725d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    public void bluetoothDisconnectConnectedProfile(
726d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            @RpcParameter(name = "deviceID",
727d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
728d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID,
729d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            @RpcParameter(name = "profileSet",
730d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "List of profiles to disconnect from.")
731d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    JSONArray profileSet
732d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    ) throws Exception {
733d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
734d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                deviceID);
735d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        disconnectProfiles(mDevice, deviceID, jsonArrayToIntegerList(profileSet));
736d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    }
737d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi
73802cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    @Rpc(description = "Change permissions for a profile.")
73902cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    public void bluetoothChangeProfileAccessPermission(
74002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "deviceID",
741d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Name or MAC address of a bluetooth device.")
742d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    String deviceID,
74302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "profileID",
744d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Number of Profile to change access permission")
745d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer profileID,
74602cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            @RpcParameter(name = "access",
747d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    description = "Access level 0 = Unknown, 1 = Allowed, 2 = Rejected")
748d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                    Integer access
749d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi    ) throws Exception {
75002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        if (access < 0 || access > 2) {
75102cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            Log.w("Unsupported access level.");
75202cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            return;
75302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        }
75402cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        BluetoothDevice mDevice = BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(),
75502cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                deviceID);
756d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        switch (profileID) {
75702cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            case BluetoothProfile.PBAP:
75802cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                mDevice.setPhonebookAccessPermission(access);
75902cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                break;
76002cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo            default:
76102cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo                Log.w("Unsupported profile access change.");
76202cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo        }
76302cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo    }
76402cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo
76502cd37e8066812cd73abe71f060e39cfac74f9a7Joseph Pirozzo
7669f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    @Override
7679f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    public void shutdown() {
768d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi        for (BroadcastReceiver receiver : listeningDevices.values()) {
769d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            try {
770d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                mService.unregisterReceiver(receiver);
771d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            } catch (IllegalArgumentException ex) {
772d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi                Log.e("Failed to unregister " + ex);
773d9a81edc88a6ffdecebaa306279557bc18b71c7dRam Periathiruvadi            }
7749f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        }
7759f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li        listeningDevices.clear();
77602e949859dc20c9ab6d0a79688eff87beae68d61tturney        mService.unregisterReceiver(mPairingHelper);
7779f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li    }
7789f32db87b486c93a0ea71eb1781ee45676b8bf8bXin Li}
779