HeadsetClientService.java revision 84f977c60b8d7feea9c9b20d60a7eb8e3e4869a9
1aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta/* 2aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Copyright (c) 2014 The Android Open Source Project 3aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * 4aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * you may not use this file except in compliance with the License. 6aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * You may obtain a copy of the License at 7aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * 8aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * http://www.apache.org/licenses/LICENSE-2.0 9aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * 10aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Unless required by applicable law or agreed to in writing, software 11aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * See the License for the specific language governing permissions and 14aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * limitations under the License. 15aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta */ 16aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 17aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptapackage com.android.bluetooth.hfpclient; 18aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 19aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.bluetooth.BluetoothDevice; 20aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.bluetooth.BluetoothProfile; 218d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwoodimport android.bluetooth.BluetoothHeadsetClient; 228d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwoodimport android.bluetooth.BluetoothHeadsetClientCall; 238d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwoodimport android.bluetooth.IBluetoothHeadsetClient; 24aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.content.BroadcastReceiver; 25aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.content.Context; 26aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.content.Intent; 27aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.content.IntentFilter; 28aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.media.AudioManager; 29aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.os.Bundle; 3084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwalimport android.os.HandlerThread; 3184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwalimport android.os.Looper; 32aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.os.Message; 33aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.provider.Settings; 34aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport android.util.Log; 35eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen 36aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport com.android.bluetooth.btservice.ProfileService; 37a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwalimport com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService; 38aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport com.android.bluetooth.Utils; 39eb7b90f5b93db1230a5b64caa3d8d05a642e33a6Marie Janssen 40aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport java.util.ArrayList; 4184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwalimport java.util.HashMap; 4284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwalimport java.util.Iterator; 43aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Guptaimport java.util.List; 4484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwalimport java.util.Map; 45ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwalimport java.util.UUID; 46a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 47aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta/** 488d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood * Provides Bluetooth Headset Client (HF Role) profile, as a service in the 49aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Bluetooth application. 50aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * 51aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * @hide 52aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta */ 538d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwoodpublic class HeadsetClientService extends ProfileService { 54aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta private static final boolean DBG = false; 558d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static final String TAG = "HeadsetClientService"; 56aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 5784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private HashMap<BluetoothDevice, HeadsetClientStateMachine> mStateMachineMap = 5884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal new HashMap<>(); 598d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static HeadsetClientService sHeadsetClientService; 6084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private NativeInterface mNativeInterface = null; 6184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private HandlerThread mSmThread = null; 6284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private HeadsetClientStateMachineFactory mSmFactory = null; 6384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Maxinum number of devices we can try connecting to in one session 6484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private static final int MAX_STATE_MACHINES_POSSIBLE = 100; 65aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 66a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal public static String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag"; 67a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 6884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal static { 6984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal NativeInterface.initializeNative(); 7084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 7184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 72aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 73aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta protected String getName() { 74aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return TAG; 75aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 76aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 77aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 78aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public IProfileServiceBinder initBinder() { 798d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return new BluetoothHeadsetClientBinder(this); 80aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 81aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 82aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 8384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized boolean start() { 8484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmFactory = new HeadsetClientStateMachineFactory(); 8584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.clear(); 8684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 87aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); 88aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta try { 89aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta registerReceiver(mBroadcastReceiver, filter); 90aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } catch (Exception e) { 91aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.w(TAG, "Unable to register broadcat receiver", e); 92aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 938d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood setHeadsetClientService(this); 9484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mNativeInterface = new NativeInterface(); 95a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 96a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // Start the HfpClientConnectionService to create connection with telecom when HFP 97a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // connection is available. 98a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal Intent startIntent = new Intent(this, HfpClientConnectionService.class); 99a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal startService(startIntent); 100a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 10184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Create the thread on which all State Machines will run 10284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread = new HandlerThread("HeadsetClient.SM"); 10384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread.start(); 10484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal NativeInterface.initializeNative(); 10584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 106aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 107aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 108aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 109aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 11084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized boolean stop() { 111aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta try { 112aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta unregisterReceiver(mBroadcastReceiver); 113aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } catch (Exception e) { 114aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.w(TAG, "Unable to unregister broadcast receiver", e); 115aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 116562547733c2dd517f3bdd30f29bfe43732fe9a13Chenjie Luo 11784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (Iterator<Map.Entry<BluetoothDevice, HeadsetClientStateMachine>> it = 11884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.entrySet().iterator(); it.hasNext(); ) { 11984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = 12084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.get((BluetoothDevice) it.next().getKey()); 12184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.doQuit(); 12284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal it.remove(); 123bebc4dd9edb40710d9588b4a2010eef227756a8eLianchao Song } 124a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 125a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // Stop the HfpClientConnectionService. 126a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal Intent stopIntent = new Intent(this, HfpClientConnectionService.class); 127a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal stopIntent.putExtra(HFP_CLIENT_STOP_TAG, true); 128a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal startService(stopIntent); 12984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mNativeInterface = null; 13084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 13184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Stop the handler thread 13284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread.quit(); 13384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread = null; 13484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 13584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal NativeInterface.cleanupNative(); 13684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 137aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 138aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 139aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 140aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 141aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta protected boolean cleanup() { 14284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine.cleanup(); 1438d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood clearHeadsetClientService(); 144aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 145aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 146aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 147aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 148aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 149aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public void onReceive(Context context, Intent intent) { 150aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta String action = intent.getAction(); 151aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1523076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // We handle the volume changes for Voice calls here since HFP audio volume control does 1533076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // not go through audio manager (audio mixer). We check if the voice call volume has 1543076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // changed and subsequently change the SCO volume see 1553076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // ({@link HeadsetClientStateMachine#SET_SPEAKER_VOLUME} in 1563076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // {@link HeadsetClientStateMachine} for details. 157aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 1583076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal Log.d(TAG, "Volume changed for stream: " + 1593076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE)); 160aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1613076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal if (streamType == AudioManager.STREAM_VOICE_CALL) { 162aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamValue = intent 163aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 164aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamPrevValue = intent.getIntExtra( 165aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1); 166aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 167aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (streamValue != -1 && streamValue != streamPrevValue) { 16884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // TODO: Fix this 16984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // sm.sendMessage(sm.obtainMessage( 17084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // HeadsetClientStateMachine.SET_SPEAKER_VOLUME, streamValue, 0)); 171aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 172aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 173aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 174aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 175aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 176aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 177aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta /** 178aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Handlers for incoming service calls 179aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta */ 1808d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub 181aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta implements IProfileServiceBinder { 1828d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService mService; 183aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1848d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public BluetoothHeadsetClientBinder(HeadsetClientService svc) { 185aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = svc; 186aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 187aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 188aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 189aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean cleanup() { 190aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = null; 191aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 192aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 193aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1948d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService getService() { 195aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (!Utils.checkCaller()) { 1968d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.w(TAG, "HeadsetClient call not allowed for non-active user"); 197aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 198aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 199aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 200aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (mService != null && mService.isAvailable()) { 201aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return mService; 202aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 20333acd2208455171249084dd86ae0ed95db1e4c49Wei Liu 20433acd2208455171249084dd86ae0ed95db1e4c49Wei Liu Log.e(TAG, "HeadsetClientService is not available."); 205aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 206aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 207aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 208aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 209aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 2108d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 211aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 212aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 213aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 214aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.connect(device); 215aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 216aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 217aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 218aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean disconnect(BluetoothDevice device) { 2198d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 220aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 221aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 222aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 223aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.disconnect(device); 224aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 225aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 226aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 227aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getConnectedDevices() { 2288d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 229aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 230aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 231aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 232aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectedDevices(); 233aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 234aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 235aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 236aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 2378d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 238aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 239aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 240aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 241aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getDevicesMatchingConnectionStates(states); 242aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 243aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 244aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 245aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getConnectionState(BluetoothDevice device) { 2468d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 247aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 248aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.STATE_DISCONNECTED; 249aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 250aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectionState(device); 251aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 252aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 253aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 254aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 2558d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 256aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 257aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 258aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 259aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.setPriority(device, priority); 260aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 261aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 262aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 263aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 2648d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 265aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 266aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.PRIORITY_UNDEFINED; 267aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 268aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getPriority(device); 269aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 270aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 271aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 272aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean startVoiceRecognition(BluetoothDevice device) { 2738d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 274aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 275aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 276aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 277aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.startVoiceRecognition(device); 278aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 279aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 280aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 281aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean stopVoiceRecognition(BluetoothDevice device) { 2828d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 283aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 284aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 285aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 286aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.stopVoiceRecognition(device); 287aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 288aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 289aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 290aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getAudioState(BluetoothDevice device) { 2918d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 292aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 2938d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 294aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 295aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getAudioState(device); 296aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 297aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 298aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 29984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { 30084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "setAudioRouteAllowed API not supported"); 30122bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 30222bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 30322bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 30484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean getAudioRouteAllowed(BluetoothDevice device) { 30584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getAudioRouteAllowed API not supported"); 30622bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee return false; 30722bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 30822bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 30922bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 31084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean connectAudio(BluetoothDevice device) { 31184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "connectAudio API not supported"); 31284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 313aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 314aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 315aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 31684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean disconnectAudio(BluetoothDevice device) { 31784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "disconnectAudio API not supported"); 31884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 319aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 320aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 321aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 322aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean acceptCall(BluetoothDevice device, int flag) { 3238d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 324aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 325aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 326aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 327aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.acceptCall(device, flag); 328aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 329aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 330aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 331aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean rejectCall(BluetoothDevice device) { 3328d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 333aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 334aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 335aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 336aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.rejectCall(device); 337aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 338aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 339aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 340aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean holdCall(BluetoothDevice device) { 3418d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 342aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 343aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 344aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 345aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.holdCall(device); 346aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 347aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 348aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 349ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { 3508d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 351aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 3522a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.w(TAG, "service is null"); 353aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 354aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 355edb38dfa0ab86e2e747a6d5799138c8445013789Sanket Agarwal return service.terminateCall(device, call != null ? call.getUUID() : null); 356aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 357aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 358aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 359aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 3608d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 361aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 362aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 363aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 364aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.explicitCallTransfer(device); 365aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 366aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 367aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 368aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean enterPrivateMode(BluetoothDevice device, int index) { 3698d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 370aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 371aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 372aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 373aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.enterPrivateMode(device, index); 374aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 375aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 376aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 377ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 3788d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 379aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 380ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 381aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 382aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.dial(device, number); 383aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 384aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 385aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 3868d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 3878d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 388aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 38984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return new ArrayList<BluetoothHeadsetClientCall>(); 390aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 391aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentCalls(device); 392aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 393aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 394aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 395aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 3968d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 397aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 398aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 399aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 400aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.sendDTMF(device, code); 401aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 402aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 403aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 404aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 4058d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 406aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 407aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 408aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 409aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getLastVoiceTagNumber(device); 410aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 411aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 412aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 413aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 4148d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 415aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 416aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 417aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 418aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgEvents(device); 419aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 420aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 421aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 422aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 4238d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 424aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 425aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 426aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 427aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgFeatures(device); 428aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 429aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 430aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 431aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta // API methods 4328d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public static synchronized HeadsetClientService getHeadsetClientService() { 4338d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) { 434aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4358d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService); 436aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4378d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return sHeadsetClientService; 438aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 439aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4408d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4418d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is NULL"); 4428d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!(sHeadsetClientService.isAvailable())) { 4438d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is not available"); 444aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 445aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 446aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 447aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 448aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4498d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void setHeadsetClientService(HeadsetClientService instance) { 450aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (instance != null && instance.isAvailable()) { 451aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4528d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService); 453aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4548d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = instance; 455aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } else { 456aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4578d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4588d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service not available"); 4598d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!sHeadsetClientService.isAvailable()) { 4608d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service is cleaning up"); 461aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 462aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 463aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 464aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 465aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4668d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void clearHeadsetClientService() { 4678d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = null; 468aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 469aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 470aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 471aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 472aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 47384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 47484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "connect " + device); 47584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 47684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 47784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 47884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 479aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 480aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 481aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 48284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 48384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "Connection not allowed: <" + device.getAddress() + "> is PRIORITY_OFF"); 484aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 485aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 486aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 48784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT, device); 488aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 489aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 490aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 491aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean disconnect(BluetoothDevice device) { 492aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 493aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 49484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 49584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 49684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 49784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 49884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 49984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 50084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 501aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 502aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 503aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 504aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 505aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 50684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT, device); 507aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 508aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 509aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 51084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized List<BluetoothDevice> getConnectedDevices() { 511aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 51284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 51384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>(); 51484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 51584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 51684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == BluetoothProfile.STATE_CONNECTED) { 51784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal connectedDevices.add(bd); 51884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 51984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 52084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return connectedDevices; 521aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 522aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 52384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 524aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 52584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 52684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 52784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (int state : states) { 52884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 52984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == state) { 53084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal devices.add(bd); 53184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 53284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 53384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 53484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return devices; 535aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 536aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 53784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized int getConnectionState(BluetoothDevice device) { 538aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 53984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 54084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 54184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getConnectionState(device); 54284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return BluetoothProfile.STATE_DISCONNECTED; 544aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 545aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 546aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 547aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 548aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 549aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.putInt(getContentResolver(), 550aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 551aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta priority); 552aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 553aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.d(TAG, "Saved priority " + device + " = " + priority); 554aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 555aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 556aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 557aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 558aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 559aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 560aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 561aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int priority = Settings.Global.getInt(getContentResolver(), 562aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 563aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta BluetoothProfile.PRIORITY_UNDEFINED); 564aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return priority; 565aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 566aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 567aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean startVoiceRecognition(BluetoothDevice device) { 56884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "startVoiceRecognition API not available"); 569aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 570aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 571aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 57284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean stopVoiceRecognition(BluetoothDevice device) { 57384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "stopVoiceRecognition API not available"); 574aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 575aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 576aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 577aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int getAudioState(BluetoothDevice device) { 57884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 57984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 58084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 58184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return -1; 58284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 58322bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 58484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getAudioState(device); 58522bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 58622bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 58784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean connectAudio(BluetoothDevice device) { 588aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 58984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 59084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 59184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 592aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 593aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 59484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 59584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isConnected()) { 59684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 59784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 59884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm.isAudioOn()) { 599aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 600aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 60184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO); 602aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 603aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 604aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 60584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean disconnectAudio(BluetoothDevice device) { 606aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 60784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 60884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 60984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 61084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 61184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 61284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 61384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isAudioOn()) { 614aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 615aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 61684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 617aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 618aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 619aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 620aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean holdCall(BluetoothDevice device) { 621aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 62284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 62384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 62484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 62584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 62684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 62784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 62884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 629aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 630aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 631aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 632aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 63384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.HOLD_CALL); 63484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 635aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 636aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 637aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 638aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean acceptCall(BluetoothDevice device, int flag) { 639aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 64084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 64184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 64284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 64384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 64484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 64584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 64684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 647aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 648aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 649aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 650aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 65184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL); 652aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = flag; 65384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 654aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 655aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 656aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 657aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean rejectCall(BluetoothDevice device) { 658aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 65984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 66084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 66184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 66284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 66384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 66484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 66584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 666aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 667aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 668aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 669aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 670aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 67184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.REJECT_CALL); 67284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 673aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 674aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 675aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 676ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal boolean terminateCall(BluetoothDevice device, UUID uuid) { 677aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 67884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 67984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 68084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 68184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 68284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 68384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 68484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 685aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 686aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 687aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 688aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 689aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 69084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); 691ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = uuid; 69284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 693aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 694aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 695aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 696aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean enterPrivateMode(BluetoothDevice device, int index) { 697aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 69884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 69984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 70084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 70184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 70284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 70384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 70484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 705aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 706aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 707aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 708aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 709aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 71084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE); 711aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = index; 71284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 713aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 714aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 715aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 716ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 717aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 71884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 71984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 72084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 72184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 72284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 72384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 72484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 725aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 726aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 727ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 728aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 729aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 730ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( 731ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, 732ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, 733ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal true /* outgoing */); 73484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); 735ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = call; 73684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 737ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return call; 738aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 739aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 740aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 741aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 74284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 74384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 74484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 74584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 74684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 74784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 74884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 749aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 750aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 751aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 752aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 75384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.SEND_DTMF); 754aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = code; 75584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 756aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 757aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 758aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 759aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 76084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 761aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 762aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 7638d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 764aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 76584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 76684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 76784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 76884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 76984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 77084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 77184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 772aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 773aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 774aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 77584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentCalls(); 776aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 777aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 778aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 779aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 78084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 78184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 78284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 78384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 78484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 78584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 78684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 787aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 788aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 789aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 790aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 79184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER); 79284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 793aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 794aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 795aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 796aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 797aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 79884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 79984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 80084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 80184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 80284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 80384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 80484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 805aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 806aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 807aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 80884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgEvents(); 809aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 810aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 811aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 812aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 81384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 81484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 81584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 81684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 81784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 81884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 819aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 820aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 821aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 82284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgFeatures(); 82384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 82484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 82584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Handle messages from native (JNI) to java 82684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void messageFromNative(StackEvent stackEvent) { 82784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(stackEvent.device); 82884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 82984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "No SM found for event " + stackEvent); 83084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 83184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 83284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(StackEvent.STACK_EVENT, stackEvent); 83384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 83484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 83584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // State machine management 83684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized HeadsetClientStateMachine getStateMachine(BluetoothDevice device) { 83784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (device == null) { 83884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getStateMachine failed: Device cannot be null"); 83984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 84084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 84284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 84384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 84484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 84584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Found SM for device " + device); 84684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 84884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 85084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // There is a possibility of a DOS attack if someone populates here with a lot of fake 85184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // BluetoothAddresses. If it so happens instead of blowing up we can atleast put a limit on 85284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // how long the attack would survive 85384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (mStateMachineMap.keySet().size() > MAX_STATE_MACHINES_POSSIBLE) { 85484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Max state machines reached, possible DOS attack " + 85584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal MAX_STATE_MACHINES_POSSIBLE); 85684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 85784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 85884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 85984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Allocate a new SM 86084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Creating a new state machine"); 86184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm = mSmFactory.make(this, mSmThread); 86284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.put(device, sm); 86384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 864aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 865838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 866838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood @Override 86784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized void dump(StringBuilder sb) { 868838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood super.dump(sb); 86984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (HeadsetClientStateMachine sm : mStateMachineMap.values()) { 87084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 87184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "State machine:"); 87284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "============="); 87384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.dump(sb); 87484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 875838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 876838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 87784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 87884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // For testing 87984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized Map<BluetoothDevice, HeadsetClientStateMachine> getStateMachineMap() { 88084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return mStateMachineMap; 88184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 88284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 88384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected void setSMFactory(HeadsetClientStateMachineFactory factory) { 88484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmFactory = factory; 88584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 886aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta} 887