1b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/* 2b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 3b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 4b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * you may not use this file except in compliance with the License. 6b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * You may obtain a copy of the License at 7b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 8b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * 10b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * See the License for the specific language governing permissions and 14b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * limitations under the License. 15b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 16b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 17b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpackage com.android.phone; 18b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 19b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.app.Service; 20db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pellyimport android.bluetooth.BluetoothAdapter; 21b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganeshimport android.bluetooth.BluetoothAudioGateway; 22b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganeshimport android.bluetooth.BluetoothAudioGateway.IncomingConnectionInfo; 23b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.BluetoothDevice; 24b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.BluetoothHeadset; 251d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganeshimport android.bluetooth.BluetoothProfile; 2627a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganeshimport android.bluetooth.BluetoothUuid; 27b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.HeadsetBase; 28b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganeshimport android.bluetooth.IBluetooth; 29b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.bluetooth.IBluetoothHeadset; 30b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.BroadcastReceiver; 31b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Context; 32b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.Intent; 33b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.content.IntentFilter; 34b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.media.AudioManager; 35b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Handler; 36b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.IBinder; 37b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.Message; 38b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganeshimport android.os.ParcelUuid; 39b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.PowerManager; 40b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.os.RemoteException; 41b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganeshimport android.os.ServiceManager; 42b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.provider.Settings; 43b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectimport android.util.Log; 44b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 451d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganeshimport java.util.ArrayList; 467893303ffaf4c2e1dee13fb7cf06525502c03ba1Jaikumar Ganeshimport java.util.List; 47d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xieimport java.util.concurrent.ConcurrentHashMap; 48b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 49b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project/** 50b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Provides Bluetooth Headset and Handsfree profile, as a service in 51b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * the Phone application. 52b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * @hide 53b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 54b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Projectpublic class BluetoothHeadsetService extends Service { 551d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private static final String TAG = "Bluetooth HSHFP"; 56b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final boolean DBG = true; 57b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 58b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String PREF_NAME = BluetoothHeadsetService.class.getSimpleName(); 59b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String PREF_LAST_HEADSET = "lastHeadsetAddress"; 60b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 61b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final int PHONE_STATE_CHANGED = 1; 62b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 63b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 64b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 65b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 66b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static boolean sHasStarted = false; 67b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 68a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh private BluetoothDevice mDeviceSdpQuery; 69db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly private BluetoothAdapter mAdapter; 70b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private IBluetooth mBluetoothService; 71b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private PowerManager mPowerManager; 72b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private BluetoothAudioGateway mAg; 73b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private BluetoothHandsfree mBtHandsfree; 74d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie private ConcurrentHashMap<BluetoothDevice, BluetoothRemoteHeadset> mRemoteHeadsets; 751d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private BluetoothDevice mAudioConnectedDevice; 76b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 77b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 78b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void onCreate() { 79b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project super.onCreate(); 80cec56587c1d3c90014848d7adfe817bef9c325eaNick Pelly mAdapter = BluetoothAdapter.getDefaultAdapter(); 81db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); 82b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mBtHandsfree = PhoneApp.getInstance().getBluetoothHandsfree(); 83db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly mAg = new BluetoothAudioGateway(mAdapter); 84b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project IntentFilter filter = new IntentFilter( 8518e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); 867e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 87b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 88a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh filter.addAction(BluetoothDevice.ACTION_UUID); 897e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly registerReceiver(mBluetoothReceiver, filter); 90b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 91b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); 92b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (b == null) { 93b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh throw new RuntimeException("Bluetooth service not available"); 94b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 95b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBluetoothService = IBluetooth.Stub.asInterface(b); 96d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie mRemoteHeadsets = new ConcurrentHashMap<BluetoothDevice, BluetoothRemoteHeadset>(); 97b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 98b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 99b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private class BluetoothRemoteHeadset { 100b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private int mState; 101912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh private int mAudioState; 102b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private int mHeadsetType; 103b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private HeadsetBase mHeadset; 104b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private IncomingConnectionInfo mIncomingInfo; 105b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 106b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset() { 1071d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mState = BluetoothProfile.STATE_DISCONNECTED; 108b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; 109b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mHeadset = null; 110b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mIncomingInfo = null; 111912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 112b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 113b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 114b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset(int headsetType, IncomingConnectionInfo incomingInfo) { 1151d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mState = BluetoothProfile.STATE_DISCONNECTED; 116b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mHeadsetType = headsetType; 117b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mHeadset = null; 118b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mIncomingInfo = incomingInfo; 119912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh mAudioState = BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 120b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 121b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 122b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 123b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized private BluetoothDevice getCurrentDevice() { 124b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh for (BluetoothDevice device : mRemoteHeadsets.keySet()) { 125b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int state = mRemoteHeadsets.get(device).mState; 1261d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (state == BluetoothProfile.STATE_CONNECTING || 1271d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh state == BluetoothProfile.STATE_CONNECTED) { 128b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return device; 129b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 130b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 131b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return null; 1326fd5d0533471dcb151401e2f0264ca7d77f32f7dJaikumar Ganesh } 133b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 134b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 135b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void onStart(Intent intent, int startId) { 136db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly if (mAdapter == null) { 137b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.w(TAG, "Stopping BluetoothHeadsetService: device does not have BT"); 138b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project stopSelf(); 139b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 140b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (!sHasStarted) { 141b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("Starting BluetoothHeadsetService"); 142db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly if (mAdapter.isEnabled()) { 143b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mAg.start(mIncomingConnectionHandler); 144b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mBtHandsfree.onBluetoothEnabled(); 145b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 146b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sHasStarted = true; 147b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 148b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 149b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 150b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 151b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final Handler mIncomingConnectionHandler = new Handler() { 152b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 153b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void handleMessage(Message msg) { 154b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized(BluetoothHeadsetService.this) { 155b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh IncomingConnectionInfo info = (IncomingConnectionInfo)msg.obj; 156b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int type = BluetoothHandsfree.TYPE_UNKNOWN; 157b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh switch(msg.what) { 158b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh case BluetoothAudioGateway.MSG_INCOMING_HEADSET_CONNECTION: 159b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh type = BluetoothHandsfree.TYPE_HEADSET; 160b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 161b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh case BluetoothAudioGateway.MSG_INCOMING_HANDSFREE_CONNECTION: 162b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh type = BluetoothHandsfree.TYPE_HANDSFREE; 163b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 164b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 165b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 166b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.i(TAG, "Incoming rfcomm (" + BluetoothHandsfree.typeToString(type) + 167b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh ") connection from " + info.mRemoteDevice + "on channel " + 168b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh info.mRfcommChan); 169b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 1701d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int priority = BluetoothProfile.PRIORITY_OFF; 171b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh HeadsetBase headset; 172b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh priority = getPriority(info.mRemoteDevice); 1731d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (priority <= BluetoothProfile.PRIORITY_OFF) { 174b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.i(TAG, "Rejecting incoming connection because priority = " + priority); 17527a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh 1761498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek headset = new HeadsetBase(mPowerManager, mAdapter, 1771498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek info.mRemoteDevice, 1781498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek info.mSocketFd, info.mRfcommChan, 1791498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek null); 180f28ab7c8b2dcaeb1520a920979c0238c60fafd25Nick Pelly headset.disconnect(); 181cf6512686414b26f28554598364c501e38923f21Matthew Xie try { 182cf6512686414b26f28554598364c501e38923f21Matthew Xie mBluetoothService.notifyIncomingConnection(info.mRemoteDevice.getAddress(), 183cf6512686414b26f28554598364c501e38923f21Matthew Xie true); 184cf6512686414b26f28554598364c501e38923f21Matthew Xie } catch (RemoteException e) { 185cf6512686414b26f28554598364c501e38923f21Matthew Xie Log.e(TAG, "notifyIncomingConnection", e); 186cf6512686414b26f28554598364c501e38923f21Matthew Xie } 187b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return; 188b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 189b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 190b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset remoteHeadset; 191b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice device = getCurrentDevice(); 192b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 1931d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int state = BluetoothProfile.STATE_DISCONNECTED; 194b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device != null) { 195b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh state = mRemoteHeadsets.get(device).mState; 196b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 197b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 198b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh switch (state) { 1991d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh case BluetoothProfile.STATE_DISCONNECTED: 200b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // headset connecting us, lets join 201b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh remoteHeadset = new BluetoothRemoteHeadset(type, info); 202b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.put(info.mRemoteDevice, remoteHeadset); 203b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 204b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 205b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBluetoothService.notifyIncomingConnection( 206cf6512686414b26f28554598364c501e38923f21Matthew Xie info.mRemoteDevice.getAddress(), false); 207b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 208b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "notifyIncomingConnection"); 209b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 210b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 2111d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh case BluetoothProfile.STATE_CONNECTING: 212b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (!info.mRemoteDevice.equals(device)) { 213b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // different headset, ignoring 214b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.i(TAG, "Already attempting connect to " + device + 215b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh ", disconnecting " + info.mRemoteDevice); 216b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 217870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru headset = new HeadsetBase(mPowerManager, mAdapter, 218870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru info.mRemoteDevice, 219870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru info.mSocketFd, info.mRfcommChan, 220870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru null); 221b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh headset.disconnect(); 222b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 223b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 224b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 225b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // Incoming and Outgoing connections to the same headset. 226b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // The state machine manager will cancel outgoing and accept the incoming one. 227b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // Update the state 228b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(info.mRemoteDevice).mHeadsetType = type; 229b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(info.mRemoteDevice).mIncomingInfo = info; 23027a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh 231b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 232b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBluetoothService.notifyIncomingConnection( 233cf6512686414b26f28554598364c501e38923f21Matthew Xie info.mRemoteDevice.getAddress(), false); 234b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 235b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "notifyIncomingConnection"); 236b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 237b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 2381d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh case BluetoothProfile.STATE_CONNECTED: 239b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.i(TAG, "Already connected to " + device + ", disconnecting " + 240b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh info.mRemoteDevice); 2417d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie rejectIncomingConnection(info); 242b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 243b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 244b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 245b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 246b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 247b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 2487d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie private void rejectIncomingConnection(IncomingConnectionInfo info) { 2497d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie HeadsetBase headset = new HeadsetBase(mPowerManager, mAdapter, 2507d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie info.mRemoteDevice, info.mSocketFd, info.mRfcommChan, null); 2517d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie headset.disconnect(); 2527d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } 2537d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie 2547d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie 2557e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly private final BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() { 256a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh 257b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 258b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void onReceive(Context context, Intent intent) { 259b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project String action = intent.getAction(); 260db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly BluetoothDevice device = 26118e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 262db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly 263b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice currDevice = getCurrentDevice(); 2641d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int state = BluetoothProfile.STATE_DISCONNECTED; 265b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (currDevice != null) { 266b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh state = mRemoteHeadsets.get(currDevice).mState; 267b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 268b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 2691d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if ((state == BluetoothProfile.STATE_CONNECTED || 2701d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh state == BluetoothProfile.STATE_CONNECTING) && 27118e0a07cc700234f5a02fe10eee9b3ea10db58b3Nick Pelly action.equals(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED) && 272b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh device.equals(currDevice)) { 273b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project try { 2741d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mBinder.disconnect(currDevice); 275b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } catch (RemoteException e) {} 2767e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 2777e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly switch (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 2787593c785145a1b4c19fc2cb46560d5a29731d0caNick Pelly BluetoothAdapter.ERROR)) { 2797e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly case BluetoothAdapter.STATE_ON: 2804b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project mAg.start(mIncomingConnectionHandler); 2814b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project mBtHandsfree.onBluetoothEnabled(); 2824b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project break; 2837e4d71c713bba5afea4cbe3e9bd1952ff1725415Nick Pelly case BluetoothAdapter.STATE_TURNING_OFF: 2844b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project mBtHandsfree.onBluetoothDisabled(); 2854b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project mAg.stop(); 286b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (currDevice != null) { 287fda63603b954dd7672b002cf3e1ba67c259f15bbJaikumar Ganesh try { 288fda63603b954dd7672b002cf3e1ba67c259f15bbJaikumar Ganesh mBinder.disconnect(currDevice); 289fda63603b954dd7672b002cf3e1ba67c259f15bbJaikumar Ganesh } catch (RemoteException e) {} 290b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 2914b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project break; 2924b8337277ec2e375c3536b97c40e6617a7b12990The Android Open Source Project } 293b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 294b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 295b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) { 296b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mBtHandsfree.sendScoGainUpdate(intent.getIntExtra( 297b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0)); 298b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 299b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 300a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh } else if (action.equals(BluetoothDevice.ACTION_UUID)) { 301b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device.equals(mDeviceSdpQuery) && device.equals(currDevice)) { 302a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh // We have got SDP records for the device we are interested in. 303b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh getSdpRecordsAndConnect(device); 304a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh } 305b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 306b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 307b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 308b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 309b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private static final int CONNECT_HEADSET_DELAYED = 1; 310b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private Handler mHandler = new Handler() { 311b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 312b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void handleMessage(Message msg) { 313b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (msg.what) { 314b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh case CONNECT_HEADSET_DELAYED: 315b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice device = (BluetoothDevice) msg.obj; 316b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh getSdpRecordsAndConnect(device); 317b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh break; 318b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 319b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 320b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 321b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 322b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 323b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public IBinder onBind(Intent intent) { 324b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return mBinder; 325b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 326b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 327b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // ------------------------------------------------------------------ 328b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // Bluetooth Headset Connect 329b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project // ------------------------------------------------------------------ 33027a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh private static final int RFCOMM_CONNECTED = 1; 33127a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh private static final int RFCOMM_ERROR = 2; 332b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 333b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private long mTimestamp; 334b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 335b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 336b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Thread for RFCOMM connection 337b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Messages are sent to mConnectingStatusHandler as connection progresses. 338b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 339b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private RfcommConnectThread mConnectThread; 340b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private class RfcommConnectThread extends Thread { 341db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly private BluetoothDevice device; 342b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int channel; 343b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private int type; 34456a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh 34556a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh private static final int EINTERRUPT = -1000; 346a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh private static final int ECONNREFUSED = -111; 34756a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh 348db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly public RfcommConnectThread(BluetoothDevice device, int channel, int type) { 349b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project super(); 350db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly this.device = device; 351b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project this.channel = channel; 352b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project this.type = type; 353b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 354b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 35556a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh private int waitForConnect(HeadsetBase headset) { 35656a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh // Try to connect for 20 seconds 357b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh int result = 0; 358b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh for (int i=0; i < 40 && result == 0; i++) { 359b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh // waitForAsyncConnect returns 0 on timeout, 1 on success, < 0 on error. 36056a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh result = headset.waitForAsyncConnect(500, mConnectedStatusHandler); 36156a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh if (isInterrupted()) { 36256a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh headset.disconnect(); 36356a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh return EINTERRUPT; 36456a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh } 36556a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh } 36656a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh return result; 36756a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh } 36856a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh 369b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 370b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void run() { 371b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project long timestamp; 372b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 373b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project timestamp = System.currentTimeMillis(); 3741498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek HeadsetBase headset = new HeadsetBase(mPowerManager, mAdapter, 3751498a77b9d76318817fe5a1e3a961070ead26fadHerb Jellinek device, channel); 376b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 37756a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh int result = waitForConnect(headset); 37856a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh 379c36c9d5d0b168318cce0df0c7316efc7054a5b04Jaikumar Ganesh if (result != EINTERRUPT && result != 1) { 380a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh if (result == ECONNREFUSED && mDeviceSdpQuery == null) { 381a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh // The rfcomm channel number might have changed, do SDP 382a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh // query and try to connect again. 383b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mDeviceSdpQuery = getCurrentDevice(); 384a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh device.fetchUuidsWithSdp(); 385a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh mConnectThread = null; 386a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh return; 387a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh } else { 388a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh Log.i(TAG, "Trying to connect to rfcomm socket again after 1 sec"); 389a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh try { 390a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh sleep(1000); // 1 second 3918ef8f988f35aa07cf681cb9ee9f5d6acebb2df2aMatthew Xie } catch (InterruptedException e) { 3928ef8f988f35aa07cf681cb9ee9f5d6acebb2df2aMatthew Xie return; 3938ef8f988f35aa07cf681cb9ee9f5d6acebb2df2aMatthew Xie } 394a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh } 39556a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh result = waitForConnect(headset); 396b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 397a1b11e1bafaaebeb4720d9c90a416c3af694d1a1Jaikumar Ganesh mDeviceSdpQuery = null; 39856a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh if (result == EINTERRUPT) return; 39956a7c8d33a5b551aee4ee327762b68063d483914Jaikumar Ganesh 400b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("RFCOMM connection attempt took " + 401b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project (System.currentTimeMillis() - timestamp) + " ms"); 402b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (isInterrupted()) { 403b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project headset.disconnect(); 404b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return; 405b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 406b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (result < 0) { 407b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.w(TAG, "headset.waitForAsyncConnect() error: " + result); 408b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget(); 409b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return; 410b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh } else if (result == 0) { 411b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh mConnectingStatusHandler.obtainMessage(RFCOMM_ERROR).sendToTarget(); 412b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh Log.w(TAG, "mHeadset.waitForAsyncConnect() error: " + result + "(timeout)"); 413b8be32875b681e8d4727ecddfa3d6a4116adb656Jaikumar Ganesh return; 414b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } else { 415b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget(); 416b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 417b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 418b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 419b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 420b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 421b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Receives events from mConnectThread back in the main thread. 422b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 423b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final Handler mConnectingStatusHandler = new Handler() { 424b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 425b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void handleMessage(Message msg) { 426b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice device = getCurrentDevice(); 427b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device == null || 4281d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTING) { 429b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return; // stale events 430b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 431b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 432b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (msg.what) { 433b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case RFCOMM_ERROR: 434b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("Rfcomm error"); 435b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mConnectThread = null; 4361d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 437b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 438b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case RFCOMM_CONNECTED: 439b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project if (DBG) log("Rfcomm connected"); 440b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project mConnectThread = null; 441b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh HeadsetBase headset = (HeadsetBase)msg.obj; 4421d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_CONNECTED); 443b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 444b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadset = headset; 445b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBtHandsfree.connectHeadset(headset, mRemoteHeadsets.get(device).mHeadsetType); 446b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 447b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 448b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 449b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 450b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 451b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 452b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Receives events from a connected RFCOMM socket back in the main thread. 453b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 454b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final Handler mConnectedStatusHandler = new Handler() { 455b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project @Override 456b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project public void handleMessage(Message msg) { 457b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project switch (msg.what) { 458b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project case HeadsetBase.RFCOMM_DISCONNECTED: 459bfc44512504ebc93c101ddb394719840f2d25072Jaikumar Ganesh mBtHandsfree.resetAtState(); 460a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh mBtHandsfree.setVirtualCallInProgress(false); 461b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice device = getCurrentDevice(); 462b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device != null) { 4631d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 464b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 465b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project break; 466b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 467b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 468b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project }; 469b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 4701d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh private synchronized void setState(BluetoothDevice device, int state) { 471b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int prevState = mRemoteHeadsets.get(device).mState; 472b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (state != prevState) { 473b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (DBG) log("Device: " + device + 4741d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh " Headset state" + prevState + " -> " + state); 4751d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (prevState == BluetoothProfile.STATE_CONNECTED) { 4761d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh // Headset is disconnecting, stop the parser. 477a1478a9074b126d13124c99b7543b2518b3de3b7Eric Laurent mBtHandsfree.disconnectHeadset(); 478b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 4791d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 4801d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 4811d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh intent.putExtra(BluetoothProfile.EXTRA_STATE, state); 482b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 4831d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (state == BluetoothProfile.STATE_DISCONNECTED) { 484b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadset = null; 485b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadsetType = BluetoothHandsfree.TYPE_UNKNOWN; 4864c61a147b28d44c7faa73e75ed55d1aa1aa86a39Jaikumar Ganesh } 487b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 488b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mState = state; 489b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 490b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project sendBroadcast(intent, BLUETOOTH_PERM); 491c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh if (state == BluetoothHeadset.STATE_CONNECTED) { 492a501a53a7d0cfc15ddb25d204b0a813ca77518f5Jaikumar Ganesh // Set the priority to AUTO_CONNECT 493b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT); 494c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh adjustOtherHeadsetPriorities(device); 495b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 4965500557aeeec455481c30e1f054abb758a92f8a1Jaikumar Ganesh try { 497c08aaca9ef1d34c83ffed95409f216034335fa40Jaikumar Ganesh mBluetoothService.sendConnectionStateChange(device, BluetoothProfile.HEADSET, 498c08aaca9ef1d34c83ffed95409f216034335fa40Jaikumar Ganesh state, prevState); 4995500557aeeec455481c30e1f054abb758a92f8a1Jaikumar Ganesh } catch (RemoteException e) { 5005500557aeeec455481c30e1f054abb758a92f8a1Jaikumar Ganesh Log.e(TAG, "sendConnectionStateChange: exception"); 5015500557aeeec455481c30e1f054abb758a92f8a1Jaikumar Ganesh } 502b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 503b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 504b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 505c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh private void adjustOtherHeadsetPriorities(BluetoothDevice connectedDevice) { 506c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh for (BluetoothDevice device : mAdapter.getBondedDevices()) { 507c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh if (getPriority(device) >= BluetoothHeadset.PRIORITY_AUTO_CONNECT && 508c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh !device.equals(connectedDevice)) { 509c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh setPriority(device, BluetoothHeadset.PRIORITY_ON); 510c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh } 511c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh } 512c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh } 513c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh 514b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private void setPriority(BluetoothDevice device, int priority) { 515b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 516b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBinder.setPriority(device, priority); 517b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 518b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "Error while setting priority for: " + device); 519b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 520b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 521b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 522b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private int getPriority(BluetoothDevice device) { 523b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 524b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return mBinder.getPriority(device); 525b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 526b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "Error while getting priority for: " + device); 527b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 5281d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return BluetoothProfile.PRIORITY_UNDEFINED; 529b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 530b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 531b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh private synchronized void getSdpRecordsAndConnect(BluetoothDevice device) { 532b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (!device.equals(getCurrentDevice())) { 533b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // stale 534b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return; 535b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 5368931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh 5378931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh // Check if incoming connection has already connected. 5388931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh if (mRemoteHeadsets.get(device).mState == BluetoothProfile.STATE_CONNECTED) { 5398931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh return; 5408931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh } 5418931676029826b35b9857bf03889fc1f2ff2fda3Jaikumar Ganesh 542b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh ParcelUuid[] uuids = device.getUuids(); 5437d059ff40fa0850c2cbec50abeaa30193c4a2cfdJaikumar Ganesh ParcelUuid[] localUuids = mAdapter.getUuids(); 544b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int type = BluetoothHandsfree.TYPE_UNKNOWN; 54527a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh if (uuids != null) { 5467d059ff40fa0850c2cbec50abeaa30193c4a2cfdJaikumar Ganesh if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree) && 5477d059ff40fa0850c2cbec50abeaa30193c4a2cfdJaikumar Ganesh BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG)) { 54827a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh log("SDP UUID: TYPE_HANDSFREE"); 549b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh type = BluetoothHandsfree.TYPE_HANDSFREE; 550b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadsetType = type; 551b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int channel = device.getServiceChannel(BluetoothUuid.Handsfree); 552b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectThread = new RfcommConnectThread(device, channel, type); 55331d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat if (mAdapter.isDiscovering()) { 55431d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat mAdapter.cancelDiscovery(); 55531d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat } 55627a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh mConnectThread.start(); 557c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh if (getPriority(device) < BluetoothHeadset.PRIORITY_AUTO_CONNECT) { 558c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT); 559c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh } 56027a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh return; 5617d059ff40fa0850c2cbec50abeaa30193c4a2cfdJaikumar Ganesh } else if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP) && 5627d059ff40fa0850c2cbec50abeaa30193c4a2cfdJaikumar Ganesh BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG)) { 56327a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh log("SDP UUID: TYPE_HEADSET"); 564b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh type = BluetoothHandsfree.TYPE_HEADSET; 565b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadsetType = type; 566b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int channel = device.getServiceChannel(BluetoothUuid.HSP); 567b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectThread = new RfcommConnectThread(device, channel, type); 56831d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat if (mAdapter.isDiscovering()) { 56931d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat mAdapter.cancelDiscovery(); 57031d8a2e6052729250f9baddf7a31b357a59ffc69Rafal Garbat } 57127a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh mConnectThread.start(); 572c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh if (getPriority(device) < BluetoothHeadset.PRIORITY_AUTO_CONNECT) { 573c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh setPriority(device, BluetoothHeadset.PRIORITY_AUTO_CONNECT); 574c9bbb06825360558b81f0595c072194b0ab4a78bJaikumar Ganesh } 57527a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh return; 57627a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh } 57727a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh } 57827a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh log("SDP UUID: TYPE_UNKNOWN"); 579b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadsetType = type; 5801d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 58127a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh return; 58227a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh } 58327a51be4c5df0423533b9e976bc9ec7c39c53017Jaikumar Ganesh 584b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project /** 585b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project * Handlers for incoming service calls 586b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project */ 587b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private final IBluetoothHeadset.Stub mBinder = new IBluetoothHeadset.Stub() { 5881d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public int getConnectionState(BluetoothDevice device) { 589b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 590b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); 591b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (headset == null) { 5921d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return BluetoothProfile.STATE_DISCONNECTED; 593b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 594b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return headset.mState; 595b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 596b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 5977893303ffaf4c2e1dee13fb7cf06525502c03ba1Jaikumar Ganesh public List<BluetoothDevice> getConnectedDevices() { 598b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 5991d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return getDevicesMatchingConnectionStates( 6001d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh new int[] {BluetoothProfile.STATE_CONNECTED}); 601b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 602b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6031d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public boolean connect(BluetoothDevice device) { 604b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 605b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 606b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project synchronized (BluetoothHeadsetService.this) { 6071d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothDevice currDevice = getCurrentDevice(); 6081d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 6091d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (currDevice == device || 6101d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 6111d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return false; 6121d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 6131d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (currDevice != null) { 6141d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh disconnect(currDevice); 6151d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 616b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 617b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return mBluetoothService.connectHeadset(device.getAddress()); 618b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 619b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "connectHeadset"); 620b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 621b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 622b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 623b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 624b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6251d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public boolean disconnect(BluetoothDevice device) { 626b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 627b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project "Need BLUETOOTH_ADMIN permission"); 628b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project synchronized (BluetoothHeadsetService.this) { 6291d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); 6301d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (headset == null || 6311d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh headset.mState == BluetoothProfile.STATE_DISCONNECTED || 6321d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh headset.mState == BluetoothProfile.STATE_DISCONNECTING) { 6331d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return false; 6341d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 635b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 6361d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return mBluetoothService.disconnectHeadset(device.getAddress()); 637b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (RemoteException e) { 638b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "disconnectHeadset"); 6391d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh return false; 640b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 641b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 642b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 643b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6441d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public synchronized boolean isAudioConnected(BluetoothDevice device) { 645b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 646b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (device.equals(mAudioConnectedDevice)) return true; 647b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 6481d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 649b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6507893303ffaf4c2e1dee13fb7cf06525502c03ba1Jaikumar Ganesh public synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 651b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 6527893303ffaf4c2e1dee13fb7cf06525502c03ba1Jaikumar Ganesh List<BluetoothDevice> headsets = new ArrayList<BluetoothDevice>(); 6531d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh for (BluetoothDevice device: mRemoteHeadsets.keySet()) { 6541d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh int headsetState = getConnectionState(device); 6551d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh for (int state : states) { 6561d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (state == headsetState) { 6571d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh headsets.add(device); 6581d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh break; 6591d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 6601d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 6611d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 6627893303ffaf4c2e1dee13fb7cf06525502c03ba1Jaikumar Ganesh return headsets; 663b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 664b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6651d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public boolean startVoiceRecognition(BluetoothDevice device) { 666b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 667b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project synchronized (BluetoothHeadsetService.this) { 668b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device == null || 6691d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mRemoteHeadsets.get(device) == null || 6701d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED) { 671b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 672b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 673b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return mBtHandsfree.startVoiceRecognition(); 674b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 675b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 676b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6771d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public boolean stopVoiceRecognition(BluetoothDevice device) { 678b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 679b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project synchronized (BluetoothHeadsetService.this) { 680b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device == null || 6811d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mRemoteHeadsets.get(device) == null || 6821d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED) { 683b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return false; 684b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 685b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 686b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project return mBtHandsfree.stopVoiceRecognition(); 687b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 688b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 689b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 6901d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public int getBatteryUsageHint(BluetoothDevice device) { 691b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 692b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 693b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return HeadsetBase.getAtInputCount(); 694b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 695b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 696b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public int getPriority(BluetoothDevice device) { 697b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 698b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 699b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 700b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh int priority = Settings.Secure.getInt(getContentResolver(), 701b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), 7021d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothProfile.PRIORITY_UNDEFINED); 703b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return priority; 704b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 705b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 706db065e9834bcad9b0cb16c272b4b272dee8bdf62Nick Pelly 707b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean setPriority(BluetoothDevice device, int priority) { 708b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 709b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh "Need BLUETOOTH_ADMIN permission"); 710b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 711b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Settings.Secure.putInt(getContentResolver(), 712b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Settings.Secure.getBluetoothHeadsetPriorityKey(device.getAddress()), 713b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh priority); 714b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (DBG) log("Saved priority " + device + " = " + priority); 715b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 716b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 717b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 718b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 719b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean createIncomingConnect(BluetoothDevice device) { 720b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 721b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh HeadsetBase headset; 7221d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_CONNECTING); 723243575cc326b81d558ee0fa3c243e0121fd6f7f6Nick Pelly 724b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh IncomingConnectionInfo info = mRemoteHeadsets.get(device).mIncomingInfo; 725870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru headset = new HeadsetBase(mPowerManager, mAdapter, 726870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru device, 727870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru info.mSocketFd, info.mRfcommChan, 728870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru mConnectedStatusHandler); 729b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 730b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(device).mHeadset = headset; 731b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 732b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectingStatusHandler.obtainMessage(RFCOMM_CONNECTED, headset).sendToTarget(); 733b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 734b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 735b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 736b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 737a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { 738b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 739b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 740b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (device == null || 741b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mRemoteHeadsets.get(device) == null || 742a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED || 743a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh getAudioState(device) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 744b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 745b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 746a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh return mBtHandsfree.initiateScoUsingVirtualVoiceCall(); 747b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 748b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 749b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 750a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { 751b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 752b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 753b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh if (device == null || 754b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh mRemoteHeadsets.get(device) == null || 755a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh mRemoteHeadsets.get(device).mState != BluetoothProfile.STATE_CONNECTED || 756a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh getAudioState(device) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 757b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh return false; 758b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 759a8b5afa3f830a05fd6679642a6a29dd3265cd273Jaikumar Ganesh return mBtHandsfree.terminateScoUsingVirtualVoiceCall(); 760b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 761b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh } 762b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 7637d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie public boolean rejectIncomingConnect(BluetoothDevice device) { 7647d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie synchronized (BluetoothHeadsetService.this) { 7657d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); 7667d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie if (headset != null) { 7677d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie IncomingConnectionInfo info = headset.mIncomingInfo; 7687d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie rejectIncomingConnection(info); 7697d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } else { 7707d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie Log.e(TAG, "Error no record of remote headset"); 7717d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } 7727d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie return true; 7737d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } 7747d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie } 7757d9521b93cadfde1e7fb2e7904641982f1a65bb6Matthew Xie 776b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean acceptIncomingConnect(BluetoothDevice device) { 777b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 778b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh HeadsetBase headset; 779b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset cachedHeadset = mRemoteHeadsets.get(device); 780b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (cachedHeadset == null) { 781b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "Cached Headset is Null in acceptIncomingConnect"); 782b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return false; 783b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 784b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh IncomingConnectionInfo info = cachedHeadset.mIncomingInfo; 785870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru headset = new HeadsetBase(mPowerManager, mAdapter, 786870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru device, 787870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru info.mSocketFd, info.mRfcommChan, 788870bd7f09582278afaf7447a3be72653a742b1bdJean-Baptiste Queru mConnectedStatusHandler); 789b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 7901d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_CONNECTED); 791b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 792b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh cachedHeadset.mHeadset = headset; 793b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBtHandsfree.connectHeadset(headset, cachedHeadset.mHeadsetType); 794b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 795b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (DBG) log("Successfully used incoming connection"); 796b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 797b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 798b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 799b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 800b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean cancelConnectThread() { 801b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 802b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (mConnectThread != null) { 803b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // cancel the connection thread 804b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectThread.interrupt(); 805b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh try { 806b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectThread.join(); 807b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } catch (InterruptedException e) { 808b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.e(TAG, "Connection cancelled twice?", e); 809b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 810b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mConnectThread = null; 811b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 812b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 813b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 814b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 815b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 816b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean connectHeadsetInternal(BluetoothDevice device) { 817b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 818b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothDevice currDevice = getCurrentDevice(); 819b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (currDevice == null) { 820b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset headset = new BluetoothRemoteHeadset(); 821b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.put(device, headset); 822b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 8231d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_CONNECTING); 824b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (device.getUuids() == null) { 825b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // We might not have got the UUID change notification from 826b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // Bluez yet, if we have just paired. Try after 1.5 secs. 827b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Message msg = new Message(); 828b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh msg.what = CONNECT_HEADSET_DELAYED; 829b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh msg.obj = device; 830b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mHandler.sendMessageDelayed(msg, 1500); 831b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } else { 832b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh getSdpRecordsAndConnect(device); 833b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 834b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 835b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } else { 836b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh Log.w(TAG, "connectHeadset(" + device + "): failed: already in state " + 837b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mRemoteHeadsets.get(currDevice).mState + 838b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh " with headset " + currDevice); 839b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 840b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return false; 841b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 842b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 843b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 844b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public boolean disconnectHeadsetInternal(BluetoothDevice device) { 845b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh synchronized (BluetoothHeadsetService.this) { 846b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh BluetoothRemoteHeadset remoteHeadset = mRemoteHeadsets.get(device); 847b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (remoteHeadset == null) return false; 848b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 8491d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (remoteHeadset.mState == BluetoothProfile.STATE_CONNECTED) { 850b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // Send a dummy battery level message to force headset 851b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // out of sniff mode so that it will immediately notice 852b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // the disconnection. We are currently sending it for 853b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // handsfree only. 854b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // TODO: Call hci_conn_enter_active_mode() from 855b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // rfcomm_send_disc() in the kernel instead. 856b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // See http://b/1716887 8571d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTING); 8581d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh 859b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh HeadsetBase headset = remoteHeadset.mHeadset; 860b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (remoteHeadset.mHeadsetType == BluetoothHandsfree.TYPE_HANDSFREE) { 861b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh headset.sendURC("+CIEV: 7,3"); 862b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 863b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 864b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (headset != null) { 865b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh headset.disconnect(); 866b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh headset = null; 867b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 8681d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 869b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 8701d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } else if (remoteHeadset.mState == BluetoothProfile.STATE_CONNECTING) { 871b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // The state machine would have canceled the connect thread. 872b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh // Just set the state here. 8731d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 874b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return true; 875b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 876b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh return false; 877b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 878b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh } 879b5d4288b3b4f336601bf6ebf16861d399a4d83a9Jaikumar Ganesh 8801d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh public boolean setAudioState(BluetoothDevice device, int state) { 881d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie // mRemoteHeadsets handles put/get concurrency by itself 882d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie int prevState = mRemoteHeadsets.get(device).mAudioState; 883d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie mRemoteHeadsets.get(device).mAudioState = state; 884d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 885d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie mAudioConnectedDevice = device; 886d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 887d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie mAudioConnectedDevice = null; 888d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie } 889d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie Intent intent = new Intent(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 890d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie intent.putExtra(BluetoothHeadset.EXTRA_STATE, state); 891d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie intent.putExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, prevState); 892d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 893d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie sendBroadcast(intent, android.Manifest.permission.BLUETOOTH); 894d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie if (DBG) log("AudioStateIntent: " + device + " State: " + state 895d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie + " PrevState: " + prevState); 896d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie return true; 8971d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh } 898912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 899912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh public int getAudioState(BluetoothDevice device) { 900d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie // mRemoteHeadsets handles put/get concurrency by itself 901d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie BluetoothRemoteHeadset headset = mRemoteHeadsets.get(device); 902d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie if (headset == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 903912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh 904d9cd25a4dde8ec303893815d0a6a61c824c0bc5cMatthew Xie return headset.mAudioState; 905912186b04d22881fd025a7cbe586228b85721a05Jaikumar Ganesh } 906b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh }; 907b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh 908b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh @Override 909b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh public void onDestroy() { 910b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh super.onDestroy(); 911b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh if (DBG) log("Stopping BluetoothHeadsetService"); 912b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh unregisterReceiver(mBluetoothReceiver); 913b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mBtHandsfree.onBluetoothDisabled(); 914b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh mAg.stop(); 915b77350c34a4cc1a5ac9d27d20d4c925524bc3ba1Jaikumar Ganesh sHasStarted = false; 9161d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh BluetoothDevice device = getCurrentDevice(); 9171d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh if (device != null) { 9181d417d7ede71bbcf72a7edebf528efbfcf9b82bbJaikumar Ganesh setState(device, BluetoothProfile.STATE_DISCONNECTED); 919b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 920b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 921b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 922b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 923b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project 924b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project private static void log(String msg) { 925b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project Log.d(TAG, msg); 926b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project } 927b16363f5fc191b769e88c364243e34b92eb22688The Android Open Source Project} 928