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)) { 107405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T Log.v(TAG, "HeadsetService - Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY"); 108405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T mStateMachine.handleAccessPermissionResult(intent); 109405b6148a168c05f9c9eac6a80db68b9a58392e2Sreenidhi T } 1106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie }; 1126c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1136c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie /** 1146c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie * Handlers for incoming service calls 1156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie */ 11674ae04c73312403e89db0f8e9bd9601d403b4783fredc private static class BluetoothHeadsetBinder extends IBluetoothHeadset.Stub implements IProfileServiceBinder { 11774ae04c73312403e89db0f8e9bd9601d403b4783fredc private HeadsetService mService; 1186c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 11974ae04c73312403e89db0f8e9bd9601d403b4783fredc public BluetoothHeadsetBinder(HeadsetService svc) { 12074ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = svc; 12174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 12274ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean cleanup() { 12374ae04c73312403e89db0f8e9bd9601d403b4783fredc mService = null; 12474ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 12574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1266c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 12774ae04c73312403e89db0f8e9bd9601d403b4783fredc private HeadsetService getService() { 12837510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu if (!Utils.checkCaller()) { 12937510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu Log.w(TAG,"Headset call not allowed for non-active user"); 13037510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu return null; 13137510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu } 13237510150ee738ccfa5913f7120e28f25ae7768dfZhihai Xu 13374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mService != null && mService.isAvailable()) { 13474ae04c73312403e89db0f8e9bd9601d403b4783fredc return mService; 1356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 13674ae04c73312403e89db0f8e9bd9601d403b4783fredc return null; 13774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 1386c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 13974ae04c73312403e89db0f8e9bd9601d403b4783fredc public boolean connect(BluetoothDevice device) { 14074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 14174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 14274ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connect(device); 1436c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1446c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean disconnect(BluetoothDevice device) { 14674ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 14774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 14874ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnect(device); 1496c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1506c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public List<BluetoothDevice> getConnectedDevices() { 15274ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 15374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice>(0); 15474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectedDevices(); 1556c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1566c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1576c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 15874ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 15974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return new ArrayList<BluetoothDevice>(0); 16074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getDevicesMatchingConnectionStates(states); 1616c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1626c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1636c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getConnectionState(BluetoothDevice device) { 16474ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 16574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 16674ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getConnectionState(device); 1676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1686c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1696c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean setPriority(BluetoothDevice device, int priority) { 17074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 17174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 17274ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.setPriority(device, priority); 1736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1746c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1756c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getPriority(BluetoothDevice device) { 17674ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 17774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 17874ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getPriority(device); 1796c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1806c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1816c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean startVoiceRecognition(BluetoothDevice device) { 18274ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 18374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 18474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.startVoiceRecognition(device); 1856c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1866c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1876c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean stopVoiceRecognition(BluetoothDevice device) { 18874ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 18974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 19074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.stopVoiceRecognition(device); 1916c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1926c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean isAudioOn() { 19474ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 19574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 19674ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.isAudioOn(); 1976c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 1986c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 1996c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean isAudioConnected(BluetoothDevice device) { 20074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 20174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 20274ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.isAudioConnected(device); 2036c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2046c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2056c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getBatteryUsageHint(BluetoothDevice device) { 20674ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 20774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return 0; 20874ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getBatteryUsageHint(device); 2096c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2106c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2116c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean acceptIncomingConnect(BluetoothDevice device) { 21274ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 21374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 21474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.acceptIncomingConnect(device); 2156c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2166c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2176c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean rejectIncomingConnect(BluetoothDevice device) { 21874ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 21974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 22074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.rejectIncomingConnect(device); 2216c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2226c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2236c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public int getAudioState(BluetoothDevice device) { 22474ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 22574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return BluetoothHeadset.STATE_AUDIO_DISCONNECTED; 22674ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.getAudioState(device); 2276c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2286c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2296c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean connectAudio() { 23074ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 23174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 23274ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.connectAudio(); 2336c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2346c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2356c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean disconnectAudio() { 23674ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 23774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 23874ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.disconnectAudio(); 2396c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2406c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2416c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { 24274ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 24374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 24474ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.startScoUsingVirtualVoiceCall(device); 2456c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2466c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2476c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { 24874ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 24974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return false; 25074ae04c73312403e89db0f8e9bd9601d403b4783fredc return service.stopScoUsingVirtualVoiceCall(device); 2516c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2526c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2536c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void phoneStateChanged(int numActive, int numHeld, int callState, 2546c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String number, int type) { 25574ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 25674ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return; 25774ae04c73312403e89db0f8e9bd9601d403b4783fredc service.phoneStateChanged(numActive, numHeld, callState, number, type); 2586c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2596c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2606c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void roamChanged(boolean roam) { 26174ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 26274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return; 26374ae04c73312403e89db0f8e9bd9601d403b4783fredc service.roamChanged(roam); 2646c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2656c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 2666c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie public void clccResponse(int index, int direction, int status, int mode, boolean mpty, 2676c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie String number, int type) { 26874ae04c73312403e89db0f8e9bd9601d403b4783fredc HeadsetService service = getService(); 26974ae04c73312403e89db0f8e9bd9601d403b4783fredc if (service == null) return; 27074ae04c73312403e89db0f8e9bd9601d403b4783fredc service.clccResponse(index, direction, status, mode, mpty, number, type); 2716c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie } 2726c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie }; 2736c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie 27474ae04c73312403e89db0f8e9bd9601d403b4783fredc //API methods 2754f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public static synchronized HeadsetService getHeadsetService(){ 2764f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService != null && sHeadsetService.isAvailable()) { 2774f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) Log.d(TAG, "getHeadsetService(): returning " + sHeadsetService); 2784f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta return sHeadsetService; 2794f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 2804f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) { 2814f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService == null) { 2824f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG, "getHeadsetService(): service is NULL"); 2834f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else if (!(sHeadsetService.isAvailable())) { 2844f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG,"getHeadsetService(): service is not available"); 2854f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 2864f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 2874f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta return null; 2884f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 2894f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 2904f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta private static synchronized void setHeadsetService(HeadsetService instance) { 2914f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (instance != null && instance.isAvailable()) { 2924f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) Log.d(TAG, "setHeadsetService(): set to: " + sHeadsetService); 2934f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta sHeadsetService = instance; 2944f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else { 2954f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (DBG) { 2964f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta if (sHeadsetService == null) { 2974f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG, "setHeadsetService(): service not available"); 2984f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } else if (!sHeadsetService.isAvailable()) { 2994f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta Log.d(TAG,"setHeadsetService(): service is cleaning up"); 3004f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3014f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3024f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3034f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3044f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 3054f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta private static synchronized void clearHeadsetService() { 3064f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta sHeadsetService = null; 3074f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta } 3084f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta 3094f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public boolean connect(BluetoothDevice device) { 31074ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 31174ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH ADMIN permission"); 31274ae04c73312403e89db0f8e9bd9601d403b4783fredc 31374ae04c73312403e89db0f8e9bd9601d403b4783fredc if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 31474ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 31574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 31674ae04c73312403e89db0f8e9bd9601d403b4783fredc 31774ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 31874ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState == BluetoothProfile.STATE_CONNECTED || 31974ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState == BluetoothProfile.STATE_CONNECTING) { 32074ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 32174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 32274ae04c73312403e89db0f8e9bd9601d403b4783fredc 32374ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.CONNECT, device); 32474ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 32574ae04c73312403e89db0f8e9bd9601d403b4783fredc } 32674ae04c73312403e89db0f8e9bd9601d403b4783fredc 32774ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnect(BluetoothDevice device) { 32874ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 32974ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH ADMIN permission"); 33074ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 33174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 33274ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 33374ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 33474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 33574ae04c73312403e89db0f8e9bd9601d403b4783fredc 33674ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT, device); 33774ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 33874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 33974ae04c73312403e89db0f8e9bd9601d403b4783fredc 3404f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public List<BluetoothDevice> getConnectedDevices() { 34174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 34274ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getConnectedDevices(); 34374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34474ae04c73312403e89db0f8e9bd9601d403b4783fredc 34574ae04c73312403e89db0f8e9bd9601d403b4783fredc private List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 34674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 34774ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getDevicesMatchingConnectionStates(states); 34874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 34974ae04c73312403e89db0f8e9bd9601d403b4783fredc 35074ae04c73312403e89db0f8e9bd9601d403b4783fredc int getConnectionState(BluetoothDevice device) { 35174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 35274ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getConnectionState(device); 35374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 35474ae04c73312403e89db0f8e9bd9601d403b4783fredc 3554f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public boolean setPriority(BluetoothDevice device, int priority) { 35674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 35774ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH_ADMIN permission"); 358c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.putInt(getContentResolver(), 359c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 36074ae04c73312403e89db0f8e9bd9601d403b4783fredc priority); 36174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (DBG) Log.d(TAG, "Saved priority " + device + " = " + priority); 36274ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 36374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 36474ae04c73312403e89db0f8e9bd9601d403b4783fredc 3654f5430babbc5a8f870e5a578a4ea3452f41dd97aGanesh Ganapathi Batta public int getPriority(BluetoothDevice device) { 36674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 36774ae04c73312403e89db0f8e9bd9601d403b4783fredc "Need BLUETOOTH_ADMIN permission"); 368c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey int priority = Settings.Global.getInt(getContentResolver(), 369c7ead6d5827f3832b9210e92fab7597142059852Jeff Sharkey Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 37074ae04c73312403e89db0f8e9bd9601d403b4783fredc BluetoothProfile.PRIORITY_UNDEFINED); 37174ae04c73312403e89db0f8e9bd9601d403b4783fredc return priority; 37274ae04c73312403e89db0f8e9bd9601d403b4783fredc } 37374ae04c73312403e89db0f8e9bd9601d403b4783fredc 37474ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean startVoiceRecognition(BluetoothDevice device) { 37574ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 37674ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 37774ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 37874ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 37974ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 38074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 38174ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.VOICE_RECOGNITION_START); 38274ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 38374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 38474ae04c73312403e89db0f8e9bd9601d403b4783fredc 38574ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean stopVoiceRecognition(BluetoothDevice device) { 38674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 38774ae04c73312403e89db0f8e9bd9601d403b4783fredc // It seem that we really need to check the AudioOn state. 38874ae04c73312403e89db0f8e9bd9601d403b4783fredc // But since we allow startVoiceRecognition in STATE_CONNECTED and 38974ae04c73312403e89db0f8e9bd9601d403b4783fredc // STATE_CONNECTING state, we do these 2 in this method 39074ae04c73312403e89db0f8e9bd9601d403b4783fredc int connectionState = mStateMachine.getConnectionState(device); 39174ae04c73312403e89db0f8e9bd9601d403b4783fredc if (connectionState != BluetoothProfile.STATE_CONNECTED && 39274ae04c73312403e89db0f8e9bd9601d403b4783fredc connectionState != BluetoothProfile.STATE_CONNECTING) { 39374ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 39474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 39574ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.VOICE_RECOGNITION_STOP); 39674ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO is this return correct when the voice recognition is not on? 39774ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 39874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 39974ae04c73312403e89db0f8e9bd9601d403b4783fredc 40074ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean isAudioOn() { 40174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 40274ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.isAudioOn(); 40374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 40474ae04c73312403e89db0f8e9bd9601d403b4783fredc 40574ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean isAudioConnected(BluetoothDevice device) { 40674ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 40774ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.isAudioConnected(device); 40874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 40974ae04c73312403e89db0f8e9bd9601d403b4783fredc 41074ae04c73312403e89db0f8e9bd9601d403b4783fredc int getBatteryUsageHint(BluetoothDevice device) { 41174ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) ask for BT stack support? 41274ae04c73312403e89db0f8e9bd9601d403b4783fredc return 0; 41374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41474ae04c73312403e89db0f8e9bd9601d403b4783fredc 41574ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean acceptIncomingConnect(BluetoothDevice device) { 41674ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) remove it if stack does access control 41774ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 41874ae04c73312403e89db0f8e9bd9601d403b4783fredc } 41974ae04c73312403e89db0f8e9bd9601d403b4783fredc 42074ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean rejectIncomingConnect(BluetoothDevice device) { 42174ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) remove it if stack does access control 42274ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 42374ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42474ae04c73312403e89db0f8e9bd9601d403b4783fredc 42574ae04c73312403e89db0f8e9bd9601d403b4783fredc int getAudioState(BluetoothDevice device) { 42674ae04c73312403e89db0f8e9bd9601d403b4783fredc return mStateMachine.getAudioState(device); 42774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 42874ae04c73312403e89db0f8e9bd9601d403b4783fredc 42974ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean connectAudio() { 43074ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 43174ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 43274ae04c73312403e89db0f8e9bd9601d403b4783fredc if (!mStateMachine.isConnected()) { 43374ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 43474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (mStateMachine.isAudioOn()) { 43674ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 43774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 43874ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO); 43974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 44074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44174ae04c73312403e89db0f8e9bd9601d403b4783fredc 44274ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean disconnectAudio() { 44374ae04c73312403e89db0f8e9bd9601d403b4783fredc // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission 44474ae04c73312403e89db0f8e9bd9601d403b4783fredc enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 44574ae04c73312403e89db0f8e9bd9601d403b4783fredc if (!mStateMachine.isAudioOn()) { 44674ae04c73312403e89db0f8e9bd9601d403b4783fredc return false; 44774ae04c73312403e89db0f8e9bd9601d403b4783fredc } 44874ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO); 44974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 45074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 45174ae04c73312403e89db0f8e9bd9601d403b4783fredc 45274ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean startScoUsingVirtualVoiceCall(BluetoothDevice device) { 4536b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M int connectionState = mStateMachine.getConnectionState(device); 4546b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M if (connectionState != BluetoothProfile.STATE_CONNECTED && 4556b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M connectionState != BluetoothProfile.STATE_CONNECTING) { 4566b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M return false; 4576b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } 4586b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(HeadsetStateMachine.VIRTUAL_CALL_START, device); 45974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 46074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 46174ae04c73312403e89db0f8e9bd9601d403b4783fredc 46274ae04c73312403e89db0f8e9bd9601d403b4783fredc boolean stopScoUsingVirtualVoiceCall(BluetoothDevice device) { 4636b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M int connectionState = mStateMachine.getConnectionState(device); 4646b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M if (connectionState != BluetoothProfile.STATE_CONNECTED && 4656b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M connectionState != BluetoothProfile.STATE_CONNECTING) { 4666b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M return false; 4676b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M } 4686b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(HeadsetStateMachine.VIRTUAL_CALL_STOP, device); 46974ae04c73312403e89db0f8e9bd9601d403b4783fredc return true; 47074ae04c73312403e89db0f8e9bd9601d403b4783fredc } 47174ae04c73312403e89db0f8e9bd9601d403b4783fredc 47274ae04c73312403e89db0f8e9bd9601d403b4783fredc private void phoneStateChanged(int numActive, int numHeld, int callState, 47374ae04c73312403e89db0f8e9bd9601d403b4783fredc String number, int type) { 4740e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); 4756b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M Message msg = mStateMachine.obtainMessage(HeadsetStateMachine.CALL_STATE_CHANGED); 4766b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M msg.obj = new HeadsetCallState(numActive, numHeld, callState, number, type); 4776b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M msg.arg1 = 0; // false 4786b19b0e94877ae8f0803133f8cfb4885acff2763Syed Ibrahim M mStateMachine.sendMessage(msg); 47974ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48074ae04c73312403e89db0f8e9bd9601d403b4783fredc 48174ae04c73312403e89db0f8e9bd9601d403b4783fredc private void roamChanged(boolean roam) { 4820e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); 48374ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.ROAM_CHANGED, roam); 48474ae04c73312403e89db0f8e9bd9601d403b4783fredc } 48574ae04c73312403e89db0f8e9bd9601d403b4783fredc 48674ae04c73312403e89db0f8e9bd9601d403b4783fredc private void clccResponse(int index, int direction, int status, int mode, boolean mpty, 48774ae04c73312403e89db0f8e9bd9601d403b4783fredc String number, int type) { 4880e46362107a23fcfe829b270f3ff987d911cd102Matthew Xie enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null); 48974ae04c73312403e89db0f8e9bd9601d403b4783fredc mStateMachine.sendMessage(HeadsetStateMachine.SEND_CCLC_RESPONSE, 49074ae04c73312403e89db0f8e9bd9601d403b4783fredc new HeadsetClccResponse(index, direction, status, mode, mpty, number, type)); 49174ae04c73312403e89db0f8e9bd9601d403b4783fredc } 49274ae04c73312403e89db0f8e9bd9601d403b4783fredc 4936c91bc0a163cc7600c40d7fb979777fd911d1ef1Matthew Xie} 494