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)) { 1653d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo if (DBG) { 1663d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo Log.d(TAG, 1673d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo "Volume changed for stream: " 1683d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo + intent.getExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE)); 1693d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo } 170aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); 1713076d2acccf5c3db0db19b622f062e259be39f3aSanket Agarwal if (streamType == AudioManager.STREAM_VOICE_CALL) { 172aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int streamValue = intent 173aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); 17493d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal int hfVol = HeadsetClientStateMachine.amToHfVol(streamValue); 1753d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo if (DBG) { 1763d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo Log.d(TAG, 1773d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo "Setting volume to audio manager: " + streamValue 1783d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo + " hands free: " + hfVol); 1793d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo } 18093d129a2679021c3275ba940405ba2609853b9eeSanket Agarwal mAudioManager.setParameters("hfp_volume=" + hfVol); 1813d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo synchronized (this) { 1823d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo for (HeadsetClientStateMachine sm : mStateMachineMap.values()) { 1833d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo if (sm != null) { 1843d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo sm.sendMessage( 1853d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo HeadsetClientStateMachine.SET_SPEAKER_VOLUME, streamValue); 1863d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo } 1873d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo } 1883d35808e7d5c704b4cc4f7fe0dc1d8cafc3f1fdaJoseph Pirozzo } 189aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 190aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 191aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 192aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 193aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 194aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta /** 195aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta * Handlers for incoming service calls 196aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta */ 1978d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static class BluetoothHeadsetClientBinder extends IBluetoothHeadsetClient.Stub 198aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta implements IProfileServiceBinder { 1998d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService mService; 200aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 2018d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public BluetoothHeadsetClientBinder(HeadsetClientService svc) { 202aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = svc; 203aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 204aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 205aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 206aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean cleanup() { 207aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta mService = null; 208aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 209aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 210aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 2118d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private HeadsetClientService getService() { 212aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (!Utils.checkCaller()) { 2138d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.w(TAG, "HeadsetClient call not allowed for non-active user"); 214aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 215aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 216aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 217aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (mService != null && mService.isAvailable()) { 218aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return mService; 219aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 22033acd2208455171249084dd86ae0ed95db1e4c49Wei Liu 22133acd2208455171249084dd86ae0ed95db1e4c49Wei Liu Log.e(TAG, "HeadsetClientService is not available."); 222aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 223aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 224aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 225aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 226aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 2278d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 228aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 229aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 230aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 231aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.connect(device); 232aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 233aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 234aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 235aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean disconnect(BluetoothDevice device) { 2368d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 237aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 238aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 239aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 240aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.disconnect(device); 241aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 242aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 243aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 244aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getConnectedDevices() { 2458d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 246aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 247aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 248aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 249aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectedDevices(); 250aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 251aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 252aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 253aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 2548d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 255aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 256aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return new ArrayList<BluetoothDevice>(0); 257aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 258aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getDevicesMatchingConnectionStates(states); 259aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 260aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 261aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 262aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getConnectionState(BluetoothDevice device) { 2638d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 264aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 265aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.STATE_DISCONNECTED; 266aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 267aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getConnectionState(device); 268aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 269aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 270aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 271aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 2728d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 273aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 274aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 275aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 276aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.setPriority(device, priority); 277aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 278aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 279aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 280aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 2818d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 282aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 283aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return BluetoothProfile.PRIORITY_UNDEFINED; 284aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 285aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getPriority(device); 286aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 287aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 288aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 289aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean startVoiceRecognition(BluetoothDevice device) { 2908d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 291aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 292aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 293aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 294aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.startVoiceRecognition(device); 295aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 296aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 297aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 298aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean stopVoiceRecognition(BluetoothDevice device) { 2998d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 300aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 301aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 302aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 303aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.stopVoiceRecognition(device); 304aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 305aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 306aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 307aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getAudioState(BluetoothDevice device) { 3088d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 309aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 3108d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED; 311aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 312aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getAudioState(device); 313aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 314aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 315aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 31684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) { 31784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "setAudioRouteAllowed API not supported"); 31822bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 31922bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 32022bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 32184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean getAudioRouteAllowed(BluetoothDevice device) { 32284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getAudioRouteAllowed API not supported"); 32322bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee return false; 32422bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 32522bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 32622bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee @Override 32784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean connectAudio(BluetoothDevice device) { 3282d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal HeadsetClientService service = getService(); 3292d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal if (service == null) { 3302d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return false; 3312d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 3322d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return service.connectAudio(device); 333aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 334aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 335aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 33684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public boolean disconnectAudio(BluetoothDevice device) { 3372d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal HeadsetClientService service = getService(); 3382d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal if (service == null) { 3392d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return false; 3402d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 3412d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal return service.disconnectAudio(device); 342aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 343aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 344aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 345aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean acceptCall(BluetoothDevice device, int flag) { 3468d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 347aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 348aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 349aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 350aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.acceptCall(device, flag); 351aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 352aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 353aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 354aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean rejectCall(BluetoothDevice device) { 3558d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 356aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 357aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 358aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 359aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.rejectCall(device); 360aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 361aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 362aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 363aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean holdCall(BluetoothDevice device) { 3648d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 365aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 366aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 367aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 368aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.holdCall(device); 369aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 370aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 371aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 372ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { 3738d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 374aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 3752a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.w(TAG, "service is null"); 376aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 377aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 378edb38dfa0ab86e2e747a6d5799138c8445013789Sanket Agarwal return service.terminateCall(device, call != null ? call.getUUID() : null); 379aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 380aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 381aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 382aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 3838d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 384aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 385aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 386aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 387aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.explicitCallTransfer(device); 388aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 389aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 390aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 391aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean enterPrivateMode(BluetoothDevice device, int index) { 3928d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 393aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 394aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 395aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 396aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.enterPrivateMode(device, index); 397aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 398aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 399aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 400ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 4018d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 402aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 403ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 404aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 405aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.dial(device, number); 406aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 407aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 408aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 4098d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 4108d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 411aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 41284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return new ArrayList<BluetoothHeadsetClientCall>(); 413aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 414aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentCalls(device); 415aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 416aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 417aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 418aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 4198d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 420aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 421aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 422aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 423aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.sendDTMF(device, code); 424aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 425aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 426aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 427aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 4288d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 429aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 430aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 431aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 432aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getLastVoiceTagNumber(device); 433aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 434aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 435aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 436aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 4378d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 438aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 439aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 440aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 441aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgEvents(device); 442aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 443aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 444aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta @Override 445aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 4468d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood HeadsetClientService service = getService(); 447aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (service == null) { 448aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 449aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 450aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return service.getCurrentAgFeatures(device); 451aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 452aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta }; 453aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 454aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta // API methods 4558d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public static synchronized HeadsetClientService getHeadsetClientService() { 4568d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService != null && sHeadsetClientService.isAvailable()) { 457aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4588d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): returning " + sHeadsetClientService); 459aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4608d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood return sHeadsetClientService; 461aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 462aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4638d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4648d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is NULL"); 4658d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!(sHeadsetClientService.isAvailable())) { 4668d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "getHeadsetClientService(): service is not available"); 467aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 468aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 469aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 470aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 471aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4728d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void setHeadsetClientService(HeadsetClientService instance) { 473aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (instance != null && instance.isAvailable()) { 474aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4758d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): set to: " + sHeadsetClientService); 476aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 4778d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = instance; 478aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } else { 479aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 4808d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood if (sHeadsetClientService == null) { 4818d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service not available"); 4828d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood } else if (!sHeadsetClientService.isAvailable()) { 4838d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood Log.d(TAG, "setHeadsetClientService(): service is cleaning up"); 484aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 485aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 486aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 487aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 488aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 4898d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood private static synchronized void clearHeadsetClientService() { 4908d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood sHeadsetClientService = null; 491aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 492aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 493aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean connect(BluetoothDevice device) { 494aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 495aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 49684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 49784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "connect " + device); 49884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 49984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 50084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 50184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 502aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 503aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 504aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 50584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 50684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "Connection not allowed: <" + device.getAddress() + "> is PRIORITY_OFF"); 507aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 508aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 509aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 51084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT, device); 511aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 512aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 513aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 514aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean disconnect(BluetoothDevice device) { 515aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 516aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH ADMIN permission"); 51784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 51884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 51984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 52084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 52184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 52284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 52384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 524aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 525aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 526aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 527aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 528aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 52984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT, device); 530aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 531aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 532aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 53384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized List<BluetoothDevice> getConnectedDevices() { 534aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 53584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 53684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>(); 53784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 53884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 53984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == BluetoothProfile.STATE_CONNECTED) { 54084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal connectedDevices.add(bd); 54184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 54384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return connectedDevices; 544aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 545aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 54684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 547aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 54884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 54984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (BluetoothDevice bd : mStateMachineMap.keySet()) { 55084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (int state : states) { 55184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(bd); 55284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null && sm.getConnectionState(bd) == state) { 55384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal devices.add(bd); 55484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 55584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 55684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 55784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return devices; 558aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 559aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 56084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized int getConnectionState(BluetoothDevice device) { 561aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 56284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 56384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 56484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getConnectionState(device); 56584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 56684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return BluetoothProfile.STATE_DISCONNECTED; 567aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 568aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 569aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean setPriority(BluetoothDevice device, int priority) { 570aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 571aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 572aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.putInt(getContentResolver(), 573aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 574aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta priority); 575aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (DBG) { 576aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Log.d(TAG, "Saved priority " + device + " = " + priority); 577aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 578aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 579aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 580aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 581aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public int getPriority(BluetoothDevice device) { 582aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 583aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta "Need BLUETOOTH_ADMIN permission"); 584aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int priority = Settings.Global.getInt(getContentResolver(), 585aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta Settings.Global.getBluetoothHeadsetPriorityKey(device.getAddress()), 586aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta BluetoothProfile.PRIORITY_UNDEFINED); 587aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return priority; 588aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 589aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 590aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean startVoiceRecognition(BluetoothDevice device) { 59184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "startVoiceRecognition API not available"); 592aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 593aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 594aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 59584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean stopVoiceRecognition(BluetoothDevice device) { 59684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "stopVoiceRecognition API not available"); 597aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 598aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 599aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 600aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta int getAudioState(BluetoothDevice device) { 60184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 60284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 60384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 60484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return -1; 60584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 60622bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 60784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getAudioState(device); 60822bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee } 60922bb39444356637fbcabd4acf04f2fdb9e3da177Bryce Lee 61084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean connectAudio(BluetoothDevice device) { 611aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 61284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 61384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 61484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 615aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 616aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 61784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 61884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isConnected()) { 61984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 62084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 62184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm.isAudioOn()) { 622aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 623aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 62484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.CONNECT_AUDIO); 625aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 626aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 627aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 62884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal boolean disconnectAudio(BluetoothDevice device) { 629aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 63084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 63184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 63284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 63384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 63484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 63584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 63684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (!sm.isAudioOn()) { 637aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 638aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 63984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(HeadsetClientStateMachine.DISCONNECT_AUDIO); 640aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 641aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 642aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 643aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean holdCall(BluetoothDevice device) { 644aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 64584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 64684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 64784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 64884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 64984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 65084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 65184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 652aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 653aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 654aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 655aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 65684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.HOLD_CALL); 65784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 658aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 659aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 660aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 661aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean acceptCall(BluetoothDevice device, int flag) { 662aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 663739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo /* Phonecalls from a single device are supported, hang up any calls on the other phone */ 664739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo synchronized (this) { 665739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry : 666739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo mStateMachineMap.entrySet()) { 66760487bf626ff69f4c603dcaba23d45318915f4bdJoseph Pirozzo if (entry.getValue() == null || entry.getKey().equals(device)) { 668739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo continue; 669739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 670739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo int connectionState = entry.getValue().getConnectionState(entry.getKey()); 671739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo if (DBG) { 672739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo Log.d(TAG, "Accepting a call on device " + device 673739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo + ". Possibly disconnecting on " + entry.getValue()); 674739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 67560487bf626ff69f4c603dcaba23d45318915f4bdJoseph Pirozzo if (connectionState == BluetoothProfile.STATE_CONNECTED) { 676739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo entry.getValue() 677739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo .obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL) 678739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo .sendToTarget(); 67960487bf626ff69f4c603dcaba23d45318915f4bdJoseph Pirozzo } 680739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 681739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 68284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 68384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 68484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 68584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 68684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 68784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 68884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 689739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo if (connectionState != BluetoothProfile.STATE_CONNECTED) { 690aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 691aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 69284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ACCEPT_CALL); 693aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = flag; 69484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 695aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 696aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 697aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 698aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean rejectCall(BluetoothDevice device) { 699aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 70084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 70184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 70284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 70384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 70484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 70584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 70684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 707aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 708aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 709aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 710aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 711aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 71284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.REJECT_CALL); 71384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 714aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 715aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 716aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 717ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal boolean terminateCall(BluetoothDevice device, UUID uuid) { 718aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 71984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 72084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 72184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 72284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 72384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 72484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 72584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 726aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 727aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 728aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 729aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 730aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 73184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); 732ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = uuid; 73384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 734aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 735aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 736aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 737aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta boolean enterPrivateMode(BluetoothDevice device, int index) { 738aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 73984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 74084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 74184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 74284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 74384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 74484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 74584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 746aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 747aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 748aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 749aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 750aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 75184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.ENTER_PRIVATE_MODE); 752aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = index; 75384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 754aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 755aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 756aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 757ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { 758aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 75984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 76084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 76184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 76284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 76384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 76484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 76584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 766aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 767aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 768ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return null; 769aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 770aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 771ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( 772ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, 773ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, 774ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal true /* outgoing */); 77584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); 776ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal msg.obj = call; 77784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 778ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return call; 779aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 780aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 781aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean sendDTMF(BluetoothDevice device, byte code) { 782aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 78384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 78484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 78584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 78684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 78784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 78884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 78984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 790aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 791aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 792aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 793aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 79484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.SEND_DTMF); 795aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta msg.arg1 = code; 79684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 797aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 798aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 799aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 800aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean getLastVoiceTagNumber(BluetoothDevice device) { 80184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 802aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 803aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 8048d536f3db19e8ea7426e98e470dc15d10ecbae87Mike Lockwood public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { 805aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 80684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 80784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 80884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 80984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 81084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 81184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 81284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 813aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 814aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 815aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 81684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentCalls(); 817aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 818aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 819aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public boolean explicitCallTransfer(BluetoothDevice device) { 820aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 82184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 82284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 82384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 82484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return false; 82584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 82684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 82784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 828aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED && 829aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta connectionState != BluetoothProfile.STATE_CONNECTING) { 830aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return false; 831aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 83284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Message msg = sm.obtainMessage(HeadsetClientStateMachine.EXPLICIT_CALL_TRANSFER); 83384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(msg); 834aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return true; 835aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 836aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 837aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgEvents(BluetoothDevice device) { 838aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 83984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 84084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 84184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 84284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 84384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 84484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 84584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 846aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 847aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 848aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 84984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgEvents(); 850aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 851aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta 852aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta public Bundle getCurrentAgFeatures(BluetoothDevice device) { 853aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 85484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(device); 85584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 85684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Cannot allocate SM for device " + device); 85784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 85884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 85984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal int connectionState = sm.getConnectionState(device); 860aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta if (connectionState != BluetoothProfile.STATE_CONNECTED) { 861aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta return null; 862aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 86384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm.getCurrentAgFeatures(); 86484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 86584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 86684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Handle messages from native (JNI) to java 86784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public void messageFromNative(StackEvent stackEvent) { 86884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = getStateMachine(stackEvent.device); 86984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm == null) { 87084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.w(TAG, "No SM found for event " + stackEvent); 87184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 87284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 87384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.sendMessage(StackEvent.STACK_EVENT, stackEvent); 87484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 87584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 87684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // State machine management 87784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal private synchronized HeadsetClientStateMachine getStateMachine(BluetoothDevice device) { 87884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (device == null) { 87984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "getStateMachine failed: Device cannot be null"); 88084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 88184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 88284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 88384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal HeadsetClientStateMachine sm = mStateMachineMap.get(device); 88484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 88584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (DBG) { 88684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Found SM for device " + device); 88784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 88884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 88984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 89084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 89184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // There is a possibility of a DOS attack if someone populates here with a lot of fake 89284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // BluetoothAddresses. If it so happens instead of blowing up we can atleast put a limit on 89384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // how long the attack would survive 89484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (mStateMachineMap.keySet().size() > MAX_STATE_MACHINES_POSSIBLE) { 89584f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.e(TAG, "Max state machines reached, possible DOS attack " + 89684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal MAX_STATE_MACHINES_POSSIBLE); 89784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return null; 89884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 89984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 90084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // Allocate a new SM 90184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal Log.d(TAG, "Creating a new state machine"); 90284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm = mSmFactory.make(this, mSmThread); 90384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mStateMachineMap.put(device, sm); 90484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return sm; 905aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta } 906838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood 907739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo // Check if any of the state machines have routed the SCO audio stream. 908739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo synchronized boolean isScoRouted() { 909739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo for (Map.Entry<BluetoothDevice, HeadsetClientStateMachine> entry : 910739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo mStateMachineMap.entrySet()) { 911739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo if (entry.getValue() != null) { 912739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo int audioState = entry.getValue().getAudioState(entry.getKey()); 913739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo if (audioState == BluetoothHeadsetClient.STATE_AUDIO_CONNECTED) { 914739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo if (DBG) { 915739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo Log.d(TAG, "Device " + entry.getKey() + " audio state " + audioState 916739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo + " Connected"); 917739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 918739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo return true; 919739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo } 9202d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 9212d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 922739d0edc69630535258722a38a4d22d26d2ccf37Joseph Pirozzo return false; 9232d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal } 9242d9c62894634e9c4aa947ddf2cc50f4482163cf1Sanket Agarwal 925838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood @Override 92684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal public synchronized void dump(StringBuilder sb) { 927838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood super.dump(sb); 92884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal for (HeadsetClientStateMachine sm : mStateMachineMap.values()) { 92984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal if (sm != null) { 93084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "State machine:"); 93184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal println(sb, "============="); 93284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal sm.dump(sb); 93384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 934838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 935838949d46a4cc054985a8cfd682004f8dd6d3bbbMike Lockwood } 93684f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 93784f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal // For testing 93884f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected synchronized Map<BluetoothDevice, HeadsetClientStateMachine> getStateMachineMap() { 93984f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal return mStateMachineMap; 94084f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 94184f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal 94284f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal protected void setSMFactory(HeadsetClientStateMachineFactory factory) { 94384f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal mSmFactory = factory; 94484f977c60b8d7feea9c9b20d60a7eb8e3e4869a9Sanket Agarwal } 945aebc726105204f8a7b977eb3556c14b5ba18a5caHemant Gupta} 946