16c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/* 2ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Copyright (C) 2012 The Android Open Source Project 3ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 4ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Licensed under the Apache License, Version 2.0 (the "License"); 5ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * you may not use this file except in compliance with the License. 6ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * You may obtain a copy of the License at 7ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 8ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * http://www.apache.org/licenses/LICENSE-2.0 9ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * 10ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * Unless required by applicable law or agreed to in writing, software 11ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * distributed under the License is distributed on an "AS IS" BASIS, 12ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * See the License for the specific language governing permissions and 14ede67c26e7b2564ea35db6d9b3027a269c150e13Zhihai Xu * limitations under the License. 156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */ 166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xiepackage com.android.bluetooth.hfp; 186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothDevice; 2074ae04c73312403e89db0f8e9bd9601d403b4783fredcimport android.bluetooth.BluetoothHeadset; 216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.BluetoothProfile; 226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.bluetooth.IBluetoothHeadset; 236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.BroadcastReceiver; 246c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Context; 256c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.Intent; 266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.content.IntentFilter; 2737510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport android.content.pm.PackageManager; 286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.media.AudioManager; 296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.os.Handler; 306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.os.Message; 316c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.provider.Settings; 326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport android.util.Log; 3337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.btservice.ProfileService; 3437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xuimport com.android.bluetooth.Utils; 3574ae04c73312403e89db0f8e9bd9601d403b4783fredcimport java.util.ArrayList; 366c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xieimport java.util.List; 376654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Iterator; 386654f5c903de510a70f9e72cd5ad7837b615d93ffredcimport java.util.Map; 396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie/** 416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Provides Bluetooth Headset and Handsfree profile, as a service in 426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * the Bluetooth application. 436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * @hide 446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */ 45b5cc776c9353a203cdde97e62b25f05d9633d14cfredcpublic class HeadsetService extends ProfileService { 46fd1da115cbf09b7dd9bca3c7d3a4fb816a835dc5Matthew Xie private static final boolean DBG = false; 47b5cc776c9353a203cdde97e62b25f05d9633d14cfredc private static final String TAG = "HeadsetService"; 480e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie private static final String MODIFY_PHONE_STATE = android.Manifest.permission.MODIFY_PHONE_STATE; 490e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie 506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie private HeadsetStateMachine mStateMachine; 514f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta private static HeadsetService sHeadsetService; 526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 53b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected String getName() { 54b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return TAG; 556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 5774ae04c73312403e89db0f8e9bd9601d403b4783fredc public IProfileServiceBinder initBinder() { 5874ae04c73312403e89db0f8e9bd9601d403b4783fredc return new BluetoothHeadsetBinder(this); 596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 61b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean start() { 626893668d1ccf0cc6361ef31ace52fedc2e37e35aWink Saville mStateMachine = HeadsetStateMachine.make(this); 636654f5c903de510a70f9e72cd5ad7837b615d93ffredc IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); 646654f5c903de510a70f9e72cd5ad7837b615d93ffredc filter.addAction(AudioManager.VOLUME_CHANGED_ACTION); 65405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 6674ae04c73312403e89db0f8e9bd9601d403b4783fredc try { 6774ae04c73312403e89db0f8e9bd9601d403b4783fredc registerReceiver(mHeadsetReceiver, filter); 6874ae04c73312403e89db0f8e9bd9601d403b4783fredc } catch (Exception e) { 6974ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.w(TAG,"Unable to register headset receiver",e); 7074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 714f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta setHeadsetService(this); 72b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 736654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 746654f5c903de510a70f9e72cd5ad7837b615d93ffredc 75b5cc776c9353a203cdde97e62b25f05d9633d14cfredc protected boolean stop() { 7674ae04c73312403e89db0f8e9bd9601d403b4783fredc try { 7774ae04c73312403e89db0f8e9bd9601d403b4783fredc unregisterReceiver(mHeadsetReceiver); 7874ae04c73312403e89db0f8e9bd9601d403b4783fredc } catch (Exception e) { 7974ae04c73312403e89db0f8e9bd9601d403b4783fredc Log.w(TAG,"Unable to unregister headset receiver",e); 80b5cc776c9353a203cdde97e62b25f05d9633d14cfredc } 8115d36984a79d6e35c659edb0efdf929f0b526bd5Fred mStateMachine.doQuit(); 8274ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 8374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 846654f5c903de510a70f9e72cd5ad7837b615d93ffredc 8574ae04c73312403e89db0f8e9bd9601d403b4783fredc protected boolean cleanup() { 8674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mStateMachine != null) { 876654f5c903de510a70f9e72cd5ad7837b615d93ffredc mStateMachine.cleanup(); 886654f5c903de510a70f9e72cd5ad7837b615d93ffredc } 894f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta clearHeadsetService(); 90b5cc776c9353a203cdde97e62b25f05d9633d14cfredc return true; 916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie private final BroadcastReceiver mHeadsetReceiver = new BroadcastReceiver() { 946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie @Override 956c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void onReceive(Context context, Intent intent) { 966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String action = intent.getAction(); 976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie mStateMachine.sendMessage(HeadsetStateMachine.INTENT_BATTERY_CHANGED, intent); 996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 1006c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1016c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie if (streamType == AudioManager.STREAM_BLUETOOTH_SCO) { 1026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie mStateMachine.sendMessage(HeadsetStateMachine.INTENT_SCO_VOLUME_CHANGED, 1036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie intent); 1046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 106405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T else if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { 10770be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 10870be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 10970be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz if (requestType == BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS) { 11070be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz Log.v(TAG, "Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY"); 11170be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz mStateMachine.handleAccessPermissionResult(intent); 11270be005a18a35ec5fcb46152f0dfbe82156efa3aKim Schulz } 113405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie }; 1166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie /** 1186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Handlers for incoming service calls 1196c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */ 12074ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub implements IProfileServiceBinder { 12174ae04c73312403e89db0f8e9bd9601d403b4783fredc private HeadsetService mService; 1226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 12374ae04c73312403e89db0f8e9bd9601d403b4783fredc public BluetoothHeadsetBinder(HeadsetService svc) { 12474ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = svc; 12574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 12674ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean cleanup() { 12774ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = null; 12874ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 12974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1306c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 13174ae04c73312403e89db0f8e9bd9601d403b4783fredc private HeadsetService getService() { 13237510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu if (!Utils.checkCaller()) { 13337510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu Log.w(TAG,"Headset call not allowed for non-active user"); 13437510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu return null; 13537510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu } 13637510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 13774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mService != null && mService.isAvailable()) { 13874ae04c73312403e89db0f8e9bd9601d403b4783fredc return mService; 1396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 14074ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 14174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1426c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 14374ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean connect(BluetoothDevice device) { 14474ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 14574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 14674ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connect(device); 1476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1486c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean disconnect(BluetoothDevice device) { 15074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 15174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 15269d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava if (DBG) Log.d(TAG, "disconnect in HeadsetService"); 15374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnect(device); 1546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public List<BluetoothDevice> getConnectedDevices() { 15774ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 15874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice>(0); 15974ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectedDevices(); 1606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 16374ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 16474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice>(0); 16574ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getDevicesMatchingConnectionStates(states); 1666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getConnectionState(BluetoothDevice device) { 16974ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 17074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 17174ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectionState(device); 1726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean setPriority(BluetoothDevice device, int priority) { 17574ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 17674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 17774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.setPriority(device, priority); 1786c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getPriority(BluetoothDevice device) { 18174ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 18274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 18374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getPriority(device); 1846c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean startVoiceRecognition(BluetoothDevice device) { 18774ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 18874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 18974ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.startVoiceRecognition(device); 1906c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean stopVoiceRecognition(BluetoothDevice device) { 19374ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 19474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 19574ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.stopVoiceRecognition(device); 1966c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean isAudioOn() { 19974ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 20074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 20174ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.isAudioOn(); 2026c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean isAudioConnected(BluetoothDevice device) { 20574ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 20674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 20774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.isAudioConnected(device); 2086c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getBatteryUsageHint(BluetoothDevice device) { 21174ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 21274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return 0; 21374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getBatteryUsageHint(device); 2146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean acceptIncomingConnect(BluetoothDevice device) { 21774ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 21874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 21974ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.acceptIncomingConnect(device); 2206c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean rejectIncomingConnect(BluetoothDevice device) { 22374ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 22474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 22574ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.rejectIncomingConnect(device); 2266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getAudioState(BluetoothDevice device) { 22974ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 23074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 23174ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getAudioState(device); 2326c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean connectAudio() { 23574ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 23674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 23774ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectAudio(); 2386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean disconnectAudio() { 24174ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 24274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 24374ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnectAudio(); 2446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { 24774ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 24874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 24974ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.startScoUsingVirtualVoiceCall(device); 2506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { 25374ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 25474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 25574ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.stopScoUsingVirtualVoiceCall(device); 2566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void phoneStateChanged(int numActive, int numHeld, int callState, 2596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String number, int type) { 26074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 26174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return; 26274ae04c73312403e89db0f8e9bd9601d403b4783fredc service.phoneStateChanged(numActive, numHeld, callState, number, type); 2636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void clccResponse(int index, int direction, int status, int mode, boolean mpty, 2666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String number, int type) { 26774ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 26874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return; 26974ae04c73312403e89db0f8e9bd9601d403b4783fredc service.clccResponse(index, direction, status, mode, mpty, number, type); 2706c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 271cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 272cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee public boolean sendVendorSpecificResultCode(BluetoothDevice device, 273cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String command, 274cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String arg) { 275cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee HeadsetService service = getService(); 276cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (service == null) { 277cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee return false; 278cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 279cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee return service.sendVendorSpecificResultCode(device, command, arg); 280cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 281b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 282b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie public boolean enableWBS() { 283b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie HeadsetService service = getService(); 284b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (service == null) return false; 285b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return service.enableWBS(); 286b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 287b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 288b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie public boolean disableWBS() { 289b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie HeadsetService service = getService(); 290b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (service == null) return false; 291b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return service.disableWBS(); 292b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 2936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie }; 2946c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 29574ae04c73312403e89db0f8e9bd9601d403b4783fredc //API methods 2964f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public static synchronized HeadsetService getHeadsetService(){ 2974f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService != null && sHeadsetService.isAvailable()) { 2984f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) Log.d(TAG, "getHeadsetService(): returning " + sHeadsetService); 2994f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta return sHeadsetService; 3004f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3014f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) { 3024f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService == null) { 3034f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG, "getHeadsetService(): service is NULL"); 3044f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else if (!(sHeadsetService.isAvailable())) { 3054f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG,"getHeadsetService(): service is not available"); 3064f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3074f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3084f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta return null; 3094f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3104f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 3114f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta private static synchronized void setHeadsetService(HeadsetService instance) { 3124f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (instance != null && instance.isAvailable()) { 3134f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) Log.d(TAG, "setHeadsetService(): set to: " + sHeadsetService); 3144f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta sHeadsetService = instance; 3154f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else { 3164f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) { 3174f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService == null) { 3184f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG, "setHeadsetService(): service not available"); 3194f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else if (!sHeadsetService.isAvailable()) { 3204f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG,"setHeadsetService(): service is cleaning up"); 3214f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3224f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3234f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3244f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3254f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 3264f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta private static synchronized void clearHeadsetService() { 3274f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta sHeadsetService = null; 3284f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3294f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 3304f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public boolean connect(BluetoothDevice device) { 33174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 33274ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH ADMIN permission"); 33374ae04c73312403e89db0f8e9bd9601d403b4783fredc 33474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 33574ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 33674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 33774ae04c73312403e89db0f8e9bd9601d403b4783fredc 33874ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 33969d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava Log.d(TAG,"connectionState = " + connectionState); 34074ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState == BluetoothProfile.STATE_CONNECTED || 34174ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState == BluetoothProfile.STATE_CONNECTING) { 34274ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 34374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34474ae04c73312403e89db0f8e9bd9601d403b4783fredc 34574ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.CONNECT, device); 34674ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 34774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34874ae04c73312403e89db0f8e9bd9601d403b4783fredc 34974ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnect(BluetoothDevice device) { 35074ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 35174ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH ADMIN permission"); 35274ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 35374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 35474ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 35574ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 35674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 35774ae04c73312403e89db0f8e9bd9601d403b4783fredc 35874ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT, device); 35974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 36074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 36174ae04c73312403e89db0f8e9bd9601d403b4783fredc 3624f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public List<BluetoothDevice> getConnectedDevices() { 36374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 36474ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getConnectedDevices(); 36574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 36674ae04c73312403e89db0f8e9bd9601d403b4783fredc 36774ae04c73312403e89db0f8e9bd9601d403b4783fredc private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 36874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 36974ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getDevicesMatchingConnectionStates(states); 37074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 37174ae04c73312403e89db0f8e9bd9601d403b4783fredc 37274ae04c73312403e89db0f8e9bd9601d403b4783fredc int getConnectionState(BluetoothDevice device) { 37374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 37474ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getConnectionState(device); 37574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 37674ae04c73312403e89db0f8e9bd9601d403b4783fredc 3774f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public boolean setPriority(BluetoothDevice device, int priority) { 37874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 37974ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH_ADMIN permission"); 380c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.putInt(getContentResolver(), 381c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 38274ae04c73312403e89db0f8e9bd9601d403b4783fredc priority); 38374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG, "Saved priority " + device + " = " + priority); 38474ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 38574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 38674ae04c73312403e89db0f8e9bd9601d403b4783fredc 3874f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public int getPriority(BluetoothDevice device) { 38874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 38974ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH_ADMIN permission"); 390c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey int priority = Settings.Global.getInt(getContentResolver(), 391c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 39274ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothProfile.PRIORITY_UNDEFINED); 39374ae04c73312403e89db0f8e9bd9601d403b4783fredc return priority; 39474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 39574ae04c73312403e89db0f8e9bd9601d403b4783fredc 39674ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean startVoiceRecognition(BluetoothDevice device) { 39774ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 39874ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 39974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 40074ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 40174ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 40274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 40374ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.VOICE_RECOGNITION_START); 40474ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 40574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 40674ae04c73312403e89db0f8e9bd9601d403b4783fredc 40774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean stopVoiceRecognition(BluetoothDevice device) { 40874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 40974ae04c73312403e89db0f8e9bd9601d403b4783fredc // It seem that we really need to check the AudioOn state. 41074ae04c73312403e89db0f8e9bd9601d403b4783fredc // But since we allow startVoiceRecognition in STATE_CONNECTED and 41174ae04c73312403e89db0f8e9bd9601d403b4783fredc // STATE_CONNECTING state, we do these 2 in this method 41274ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 41374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 41474ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 41574ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 41674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41774ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.VOICE_RECOGNITION_STOP); 41874ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO is this return correct when the voice recognition is not on? 41974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 42074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42174ae04c73312403e89db0f8e9bd9601d403b4783fredc 42274ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean isAudioOn() { 42374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 42474ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.isAudioOn(); 42574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42674ae04c73312403e89db0f8e9bd9601d403b4783fredc 42774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean isAudioConnected(BluetoothDevice device) { 42874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 42974ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.isAudioConnected(device); 43074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43174ae04c73312403e89db0f8e9bd9601d403b4783fredc 43274ae04c73312403e89db0f8e9bd9601d403b4783fredc int getBatteryUsageHint(BluetoothDevice device) { 43374ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) ask for BT stack support? 43474ae04c73312403e89db0f8e9bd9601d403b4783fredc return 0; 43574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43674ae04c73312403e89db0f8e9bd9601d403b4783fredc 43774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean acceptIncomingConnect(BluetoothDevice device) { 43874ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) remove it if stack does access control 43974ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 44074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44174ae04c73312403e89db0f8e9bd9601d403b4783fredc 44274ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean rejectIncomingConnect(BluetoothDevice device) { 44374ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) remove it if stack does access control 44474ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 44574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44674ae04c73312403e89db0f8e9bd9601d403b4783fredc 44774ae04c73312403e89db0f8e9bd9601d403b4783fredc int getAudioState(BluetoothDevice device) { 44874ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getAudioState(device); 44974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45074ae04c73312403e89db0f8e9bd9601d403b4783fredc 45174ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectAudio() { 45274ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 45374ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 45474ae04c73312403e89db0f8e9bd9601d403b4783fredc if (!mStateMachine.isConnected()) { 45574ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 45674ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mStateMachine.isAudioOn()) { 45874ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 45974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46074ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO); 46174ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 46274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46374ae04c73312403e89db0f8e9bd9601d403b4783fredc 46474ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnectAudio() { 46574ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 46674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 46774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (!mStateMachine.isAudioOn()) { 46874ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 46974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47074ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO); 47174ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 47274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47374ae04c73312403e89db0f8e9bd9601d403b4783fredc 47474ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { 4756b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M int connectionState = mStateMachine.getConnectionState(device); 4766b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M if (connectionState != BluetoothProfile.STATE_CONNECTED && 4776b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M connectionState != BluetoothProfile.STATE_CONNECTING) { 4786b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M return false; 4796b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } 4806b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(HeadsetStateMachine.VIRTUAL_CALL_START, device); 48174ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 48274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48374ae04c73312403e89db0f8e9bd9601d403b4783fredc 48474ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { 4856b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M int connectionState = mStateMachine.getConnectionState(device); 4866b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M if (connectionState != BluetoothProfile.STATE_CONNECTED && 4876b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M connectionState != BluetoothProfile.STATE_CONNECTING) { 4886b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M return false; 4896b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } 4906b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(HeadsetStateMachine.VIRTUAL_CALL_STOP, device); 49174ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 49274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 49374ae04c73312403e89db0f8e9bd9601d403b4783fredc 49474ae04c73312403e89db0f8e9bd9601d403b4783fredc private void phoneStateChanged(int numActive, int numHeld, int callState, 49574ae04c73312403e89db0f8e9bd9601d403b4783fredc String number, int type) { 4960e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); 4976b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M Message msg = mStateMachine.obtainMessage(HeadsetStateMachine.CALL_STATE_CHANGED); 4986b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M msg.obj = new HeadsetCallState(numActive, numHeld, callState, number, type); 4996b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M msg.arg1 = 0; // false 5006b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(msg); 50174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 50274ae04c73312403e89db0f8e9bd9601d403b4783fredc 50374ae04c73312403e89db0f8e9bd9601d403b4783fredc private void clccResponse(int index, int direction, int status, int mode, boolean mpty, 50474ae04c73312403e89db0f8e9bd9601d403b4783fredc String number, int type) { 5050e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); 50674ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.SEND_CCLC_RESPONSE, 50774ae04c73312403e89db0f8e9bd9601d403b4783fredc new HeadsetClccResponse(index, direction, status, mode, mpty, number, type)); 50874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 50974ae04c73312403e89db0f8e9bd9601d403b4783fredc 510cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee private boolean sendVendorSpecificResultCode(BluetoothDevice device, 511cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String command, 512cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee String arg) { 513cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 514cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee int connectionState = mStateMachine.getConnectionState(device); 515cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (connectionState != BluetoothProfile.STATE_CONNECTED) { 516cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee return false; 517cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 518cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee // Currently we support only "+ANDROID". 519cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee if (!command.equals(BluetoothHeadset.VENDOR_RESULT_CODE_COMMAND_ANDROID)) { 520cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee Log.w(TAG, "Disallowed unsolicited result code command: " + command); 521cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee return false; 522cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 523cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee mStateMachine.sendMessage(HeadsetStateMachine.SEND_VENDOR_SPECIFIC_RESULT_CODE, 52469d4ca45a25e86823fbdb754ca6a3995f8131d59Nitin Srivastava new HeadsetVendorSpecificResultCode(device, command, arg)); 525cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee return true; 526cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee } 527cdc8ec8d84c7f16b851238da0d80b51335c4ea07Edward Jee 528b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie boolean enableWBS() { 529b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 530b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 531b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (!mStateMachine.isConnected()) { 532b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return false; 533b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 534b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (mStateMachine.isAudioOn()) { 535b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return false; 536b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 537b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 538b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie for (BluetoothDevice device: getConnectedDevices()) { 539b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie mStateMachine.sendMessage(HeadsetStateMachine.ENABLE_WBS,device); 540b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 541b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 542b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return true; 543b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 544b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 545b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie boolean disableWBS() { 546b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 547b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 548b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (!mStateMachine.isConnected()) { 549b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return false; 550b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 551b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie if (mStateMachine.isAudioOn()) { 552b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return false; 553b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 554b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie for (BluetoothDevice device: getConnectedDevices()) { 555b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie mStateMachine.sendMessage(HeadsetStateMachine.DISABLE_WBS,device); 556b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 557b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie return true; 558b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie } 559b6132733b6e386cc8c93b5598c72ed8efe04bf3eMatthew Xie 5606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie} 561