HeadsetClientService.java revision 93d129a2679021c3275ba940405ba2609853b9ee
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; 6393d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal private AudioManager mAudioManager = null; 6484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Maxinum number of devices we can try connecting to in one session 6584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private static final int MAX_STATE_MACHINES_POSSIBLE = 100; 66aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 67a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal public static String HFP_CLIENT_STOP_TAG = "hfp_client_stop_tag"; 68a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 6984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal static { 70727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal NativeInterface.classInitNative(); 7184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 7284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 73aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 74aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta protected String getName() { 75aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return TAG; 76aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 77aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 78aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 79aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public IProfileServiceBinder initBinder() { 808d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return new BluetoothHeadsetClientBinder(this); 81aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 82aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 83aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 8484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized boolean start() { 85727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal if (DBG) { 86727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal Log.d(TAG, "start()"); 87727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal } 88727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal // Setup the JNI service 89727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal NativeInterface.initializeNative(); 9093d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 91727dc7918318d01b5f2308e55038b7fcba7765f8Sanket Agarwal 9284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmFactory = new HeadsetClientStateMachineFactory(); 9384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.clear(); 9484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 95aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION); 96aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta try { 97aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta registerReceiver(mBroadcastReceiver, filter); 98aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } catch (Exception e) { 99aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.w(TAG, "Unable to register broadcat receiver", e); 100aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 1018d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood setHeadsetClientService(this); 10284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mNativeInterface = new NativeInterface(); 103a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 104a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // Start the HfpClientConnectionService to create connection with telecom when HFP 105a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // connection is available. 106a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal Intent startIntent = new Intent(this, HfpClientConnectionService.class); 107a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal startService(startIntent); 108a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 10984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Create the thread on which all State Machines will run 11084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread = new HandlerThread("HeadsetClient.SM"); 11184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread.start(); 11284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal NativeInterface.initializeNative(); 11384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 114aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 115aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 116aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 117aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 11884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized boolean stop() { 119aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta try { 120aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta unregisterReceiver(mBroadcastReceiver); 121aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } catch (Exception e) { 122aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.w(TAG, "Unable to unregister broadcast receiver", e); 123aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 124562547733c2dd517f3bdd30f29bfe43732fe9a13Chenjie Luo 12584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (Iterator<Map.Entry<BluetoothDevice, HeadsetClientStateMachine>> it = 12684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.entrySet().iterator(); it.hasNext(); ) { 12784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = 12884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.get((BluetoothDevice) it.next().getKey()); 12984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.doQuit(); 13084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal it.remove(); 131bebc4dd9edb40710d9588b4a2010eef227756a8eLianchao Song } 132a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal 133a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal // Stop the HfpClientConnectionService. 134a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal Intent stopIntent = new Intent(this, HfpClientConnectionService.class); 135a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal stopIntent.putExtra(HFP_CLIENT_STOP_TAG, true); 136a8fc504fed7dcb5dc074980b9d4cfa7a56445424Sanket Agarwal startService(stopIntent); 13784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mNativeInterface = null; 13884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 13984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Stop the handler thread 14084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread.quit(); 14184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmThread = null; 14284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 14384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal NativeInterface.cleanupNative(); 14484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 145aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 146aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 147aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 148aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 149aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta protected boolean cleanup() { 15084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine.cleanup(); 1518d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood clearHeadsetClientService(); 152aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 153aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 154aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 155aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 156aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 157aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public void onReceive(Context context, Intent intent) { 158aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta String action = intent.getAction(); 159aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1603076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // We handle the volume changes for Voice calls here since HFP audio volume control does 16193d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal // not go through audio manager (audio mixer). see 1623076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // ({@link HeadsetClientStateMachine#SET_SPEAKER_VOLUME} in 1633076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal // {@link HeadsetClientStateMachine} for details. 164aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) { 1653076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal Log.d(TAG, "Volume changed for stream: " + 1663076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE)); 167aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1683076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal if (streamType == AudioManager.STREAM_VOICE_CALL) { 169aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamValue = intent 170aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 17193d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal int hfVol = HeadsetClientStateMachine.amToHfVol(streamValue); 17293d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal Log.d(TAG, "Setting volume to audio manager: " + streamValue + " hands free: " 17393d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal + hfVol); 17493d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal mAudioManager.setParameters("hfp_volume=" + hfVol); 175aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 176aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 177aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 178aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 179aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 180aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta /** 181aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Handlers for incoming service calls 182aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta */ 1838d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub 184aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta implements IProfileServiceBinder { 1858d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService mService; 186aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1878d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public BluetoothHeadsetClientBinder(HeadsetClientService svc) { 188aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = svc; 189aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 190aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 191aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 192aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean cleanup() { 193aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = null; 194aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 195aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 196aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 1978d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService getService() { 198aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (!Utils.checkCaller()) { 1998d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.w(TAG, "HeadsetClient call not allowed for non-active user"); 200aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 201aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 202aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 203aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (mService != null && mService.isAvailable()) { 204aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return mService; 205aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 20633acd2208455171249084dd86ae0ed95db1e4c49Wei Liu 20733acd2208455171249084dd86ae0ed95db1e4c49Wei Liu Log.e(TAG, "HeadsetClientService is not available."); 208aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 209aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 210aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 211aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 212aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 2138d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 214aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 215aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 216aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 217aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.connect(device); 218aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 219aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 220aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 221aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean disconnect(BluetoothDevice device) { 2228d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 223aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 224aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 225aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 226aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.disconnect(device); 227aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 228aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 229aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 230aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getConnectedDevices() { 2318d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 232aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 233aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 234aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 235aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectedDevices(); 236aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 237aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 238aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 239aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 2408d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 241aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 242aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 243aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 244aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getDevicesMatchingConnectionStates(states); 245aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 246aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 247aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 248aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getConnectionState(BluetoothDevice device) { 2498d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 250aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 251aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.STATE_DISCONNECTED; 252aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 253aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectionState(device); 254aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 255aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 256aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 257aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 2588d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 259aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 260aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 261aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 262aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.setPriority(device, priority); 263aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 264aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 265aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 266aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 2678d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 268aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 269aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.PRIORITY_UNDEFINED; 270aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 271aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getPriority(device); 272aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 273aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 274aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 275aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean startVoiceRecognition(BluetoothDevice device) { 2768d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 277aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 278aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 279aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 280aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.startVoiceRecognition(device); 281aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 282aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 283aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 284aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean stopVoiceRecognition(BluetoothDevice device) { 2858d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 286aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 287aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 288aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 289aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.stopVoiceRecognition(device); 290aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 291aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 292aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 293aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getAudioState(BluetoothDevice device) { 2948d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 295aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 2968d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 297aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 298aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getAudioState(device); 299aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 300aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 301aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 30284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { 30384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "setAudioRouteAllowed API not supported"); 30422bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 30522bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 30622bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 30784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean getAudioRouteAllowed(BluetoothDevice device) { 30884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getAudioRouteAllowed API not supported"); 30922bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee return false; 31022bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 31122bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 31222bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 31384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean connectAudio(BluetoothDevice device) { 3142d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal HeadsetClientService service = getService(); 3152d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal if (service == null) { 3162d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return false; 3172d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 3182d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return service.connectAudio(device); 319aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 320aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 321aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 32284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean disconnectAudio(BluetoothDevice device) { 3232d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal HeadsetClientService service = getService(); 3242d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal if (service == null) { 3252d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return false; 3262d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 3272d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return service.disconnectAudio(device); 328aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 329aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 330aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 331aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean acceptCall(BluetoothDevice device, int flag) { 3328d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 333aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 334aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 335aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 336aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.acceptCall(device, flag); 337aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 338aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 339aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 340aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean rejectCall(BluetoothDevice device) { 3418d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 342aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 343aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 344aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 345aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.rejectCall(device); 346aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 347aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 348aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 349aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean holdCall(BluetoothDevice device) { 3508d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 351aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 352aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 353aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 354aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.holdCall(device); 355aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 356aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 357aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 358ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { 3598d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 360aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 3612a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.w(TAG, "service is null"); 362aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 363aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 364edb38dfa0ab86e2e747a6d5799138c8445013789Sanket Agarwal return service.terminateCall(device, call != null ? call.getUUID() : null); 365aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 366aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 367aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 368aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 3698d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 370aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 371aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 372aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 373aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.explicitCallTransfer(device); 374aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 375aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 376aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 377aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean enterPrivateMode(BluetoothDevice device, int index) { 3788d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 379aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 380aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 381aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 382aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.enterPrivateMode(device, index); 383aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 384aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 385aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 386ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 3878d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 388aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 389ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 390aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 391aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.dial(device, number); 392aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 393aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 394aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 3958d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 3968d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 397aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 39884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return new ArrayList<BluetoothHeadsetClientCall>(); 399aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 400aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentCalls(device); 401aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 402aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 403aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 404aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 4058d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 406aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 407aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 408aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 409aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.sendDTMF(device, code); 410aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 411aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 412aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 413aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 4148d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 415aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 416aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 417aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 418aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getLastVoiceTagNumber(device); 419aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 420aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 421aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 422aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 4238d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 424aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 425aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 426aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 427aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgEvents(device); 428aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 429aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 430aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 431aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 4328d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 433aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 434aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 435aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 436aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgFeatures(device); 437aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 438aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 439aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 440aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta // API methods 4418d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public static synchronized HeadsetClientService getHeadsetClientService() { 4428d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) { 443aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4448d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService); 445aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4468d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return sHeadsetClientService; 447aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 448aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4498d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4508d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is NULL"); 4518d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!(sHeadsetClientService.isAvailable())) { 4528d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is not available"); 453aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 454aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 455aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 456aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 457aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4588d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void setHeadsetClientService(HeadsetClientService instance) { 459aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (instance != null && instance.isAvailable()) { 460aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4618d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService); 462aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4638d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = instance; 464aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } else { 465aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4668d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4678d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service not available"); 4688d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!sHeadsetClientService.isAvailable()) { 4698d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service is cleaning up"); 470aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 471aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 472aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 473aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 474aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4758d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void clearHeadsetClientService() { 4768d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = null; 477aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 478aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 479aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 480aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 481aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 48284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 48384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "connect " + device); 48484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 48584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 48684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 48784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 488aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 489aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 490aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 49184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 49284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "Connection not allowed: <" + device.getAddress() + "> is PRIORITY_OFF"); 493aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 494aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 495aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 49684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT, device); 497aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 498aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 499aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 500aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean disconnect(BluetoothDevice device) { 501aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 502aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 50384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 50484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 50584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 50684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 50784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 50884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 50984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 510aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 511aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 512aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 513aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 514aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 51584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT, device); 516aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 517aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 518aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 51984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized List<BluetoothDevice> getConnectedDevices() { 520aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 52184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 52284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>(); 52384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 52484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 52584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == BluetoothProfile.STATE_CONNECTED) { 52684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal connectedDevices.add(bd); 52784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 52884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 52984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return connectedDevices; 530aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 531aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 53284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 533aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 53484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 53584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 53684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (int state : states) { 53784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 53884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == state) { 53984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal devices.add(bd); 54084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return devices; 544aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 545aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 54684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized int getConnectionState(BluetoothDevice device) { 547aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 54884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 54984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 55084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getConnectionState(device); 55184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 55284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return BluetoothProfile.STATE_DISCONNECTED; 553aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 554aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 555aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 556aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 557aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 558aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.putInt(getContentResolver(), 559aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 560aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta priority); 561aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 562aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.d(TAG, "Saved priority " + device + " = " + priority); 563aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 564aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 565aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 566aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 567aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 568aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 569aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 570aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int priority = Settings.Global.getInt(getContentResolver(), 571aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 572aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta BluetoothProfile.PRIORITY_UNDEFINED); 573aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return priority; 574aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 575aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 576aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean startVoiceRecognition(BluetoothDevice device) { 57784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "startVoiceRecognition API not available"); 578aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 579aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 580aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 58184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean stopVoiceRecognition(BluetoothDevice device) { 58284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "stopVoiceRecognition API not available"); 583aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 584aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 585aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 586aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int getAudioState(BluetoothDevice device) { 58784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 58884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 58984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 59084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return -1; 59184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 59222bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 59384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getAudioState(device); 59422bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 59522bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 59684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean connectAudio(BluetoothDevice device) { 597aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 59884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 59984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 60084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 601aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 602aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 60384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 60484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isConnected()) { 60584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 60684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 60784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm.isAudioOn()) { 608aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 609aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 61084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO); 611aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 612aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 613aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 61484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean disconnectAudio(BluetoothDevice device) { 615aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 61684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 61784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 61884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 61984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 62084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 62184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 62284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isAudioOn()) { 623aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 624aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 62584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 626aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 627aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 628aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 629aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean holdCall(BluetoothDevice device) { 630aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 63184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 63284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 63384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 63484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 63584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 63684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 63784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 638aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 639aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 640aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 641aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 64284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.HOLD_CALL); 64384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 644aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 645aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 646aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 647aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean acceptCall(BluetoothDevice device, int flag) { 648aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 64984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 65084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 65184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 65284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 65384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 65484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 65584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 656aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 657aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 658aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 659aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 66084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL); 661aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = flag; 66284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 663aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 664aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 665aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 666aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean rejectCall(BluetoothDevice device) { 667aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 66884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 66984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 67084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 67184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 67284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 67384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 67484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 675aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 676aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 677aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 678aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 679aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 68084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.REJECT_CALL); 68184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 682aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 683aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 684aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 685ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal boolean terminateCall(BluetoothDevice device, UUID uuid) { 686aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 68784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 68884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 68984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 69084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 69184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 69284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 69384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 694aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 695aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 696aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 697aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 698aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 69984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); 700ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = uuid; 70184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 702aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 703aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 704aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 705aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean enterPrivateMode(BluetoothDevice device, int index) { 706aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 70784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 70884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 70984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 71084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 71184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 71284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 71384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 714aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 715aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 716aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 717aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 718aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 71984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE); 720aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = index; 72184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 722aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 723aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 724aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 725ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 726aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 72784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 72884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 72984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 73084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 73184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 73284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 73384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 734aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 735aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 736ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 737aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 738aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 739ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( 740ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, 741ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, 742ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal true /* outgoing */); 74384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); 744ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = call; 74584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 746ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return call; 747aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 748aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 749aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 750aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 75184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 75284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 75384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 75484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 75584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 75684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 75784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 758aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 759aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 760aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 761aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 76284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.SEND_DTMF); 763aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = code; 76484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 765aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 766aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 767aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 768aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 76984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 770aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 771aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 7728d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 773aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 77484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 77584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 77684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 77784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 77884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 77984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 78084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 781aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 782aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 783aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 78484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentCalls(); 785aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 786aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 787aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 788aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 78984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 79084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 79184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 79284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 79384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 79484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 79584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 796aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 797aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 798aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 799aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 80084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER); 80184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 802aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 803aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 804aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 805aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 806aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 80784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 80884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 80984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 81084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 81184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 81284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 81384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 814aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 815aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 816aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 81784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgEvents(); 818aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 819aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 820aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 821aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 82284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 82384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 82484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 82584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 82684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 82784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 828aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 829aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 830aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 83184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgFeatures(); 83284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 83384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 83484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Handle messages from native (JNI) to java 83584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void messageFromNative(StackEvent stackEvent) { 83684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(stackEvent.device); 83784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 83884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "No SM found for event " + stackEvent); 83984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 84184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(StackEvent.STACK_EVENT, stackEvent); 84284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 84484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // State machine management 84584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized HeadsetClientStateMachine getStateMachine(BluetoothDevice device) { 84684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (device == null) { 84784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getStateMachine failed: Device cannot be null"); 84884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 84984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 85084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 85184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 85284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 85384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 85484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Found SM for device " + device); 85584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 85684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 85784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 85884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 85984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // There is a possibility of a DOS attack if someone populates here with a lot of fake 86084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // BluetoothAddresses. If it so happens instead of blowing up we can atleast put a limit on 86184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // how long the attack would survive 86284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (mStateMachineMap.keySet().size() > MAX_STATE_MACHINES_POSSIBLE) { 86384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Max state machines reached, possible DOS attack " + 86484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal MAX_STATE_MACHINES_POSSIBLE); 86584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 86684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 86784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 86884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Allocate a new SM 86984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Creating a new state machine"); 87084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm = mSmFactory.make(this, mSmThread); 87184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.put(device, sm); 87284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 873aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 874838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 8752d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal // Check if any of the state machines are currently holding the SCO audio stream 8762d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal // This function is *only* called from the SMs which are themselves run the same thread and 8772d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal // hence we do not need synchronization here 8782d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal boolean isScoAvailable() { 8792d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 8802d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 8812d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal int audioState = sm.getAudioState(bd); 8822d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal if (audioState != BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED) { 8832d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal Log.w(TAG, "Device " + bd + " audio state " + audioState + " not disconnected"); 8842d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return false; 8852d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 8862d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 8872d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return true; 8882d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 8892d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal 890838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood @Override 89184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized void dump(StringBuilder sb) { 892838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood super.dump(sb); 89384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (HeadsetClientStateMachine sm : mStateMachineMap.values()) { 89484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 89584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "State machine:"); 89684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "============="); 89784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.dump(sb); 89884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 899838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 900838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 90184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 90284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // For testing 90384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized Map<BluetoothDevice, HeadsetClientStateMachine> getStateMachineMap() { 90484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return mStateMachineMap; 90584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 90684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 90784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected void setSMFactory(HeadsetClientStateMachineFactory factory) { 90884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmFactory = factory; 90984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 910aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta} 911