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