1a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal/* 2a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * Copyright (C) 2016 The Android Open Source Project 3a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * 4a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * Licensed under the Apache License, Version 2.0 (the "License"); 5a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * you may not use this file except in compliance with the License. 6a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * You may obtain a copy of the License at 7a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * 8a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * http://www.apache.org/licenses/LICENSE-2.0 9a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * 10a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * Unless required by applicable law or agreed to in writing, software 11a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * distributed under the License is distributed on an "AS IS" BASIS, 12a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * See the License for the specific language governing permissions and 14a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal * limitations under the License. 15a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal */ 16a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalpackage com.android.bluetooth.hfpclient.connserv; 17a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 18a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.bluetooth.BluetoothDevice; 19a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.bluetooth.BluetoothHeadsetClient; 20a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.bluetooth.BluetoothHeadsetClientCall; 21a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.content.Context; 22a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.net.Uri; 23a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.telecom.Connection; 24a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.telecom.DisconnectCause; 252a32ce991573191acde4d5d2f875658ada301874Sanket Agarwalimport android.telecom.PhoneAccount; 26a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.telecom.TelecomManager; 27a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalimport android.util.Log; 28a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 29ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwalimport java.util.UUID; 30ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal 31a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwalpublic class HfpClientConnection extends Connection { 32a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private static final String TAG = "HfpClientConnection"; 33763f0e3db67879294d045fbca0f55b3b0244b266Sanket Agarwal private static final boolean DBG = false; 34a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 35a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private final Context mContext; 36a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private final BluetoothDevice mDevice; 37a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private BluetoothHeadsetClient mHeadsetProfile; 382a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal 39a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private BluetoothHeadsetClientCall mCurrentCall; 40322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo private int mPreviousCallState = -1; 41a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private boolean mClosed; 42b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal private boolean mClosing = false; 43a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private boolean mLocalDisconnect; 44a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private boolean mClientHasEcc; 45a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal private boolean mAdded; 46a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 472a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal // Constructor to be used when there's an existing call (such as that created on the AG or 482a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal // when connection happens and we see calls for the first time). 49ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public HfpClientConnection(Context context, BluetoothDevice device, 502a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal BluetoothHeadsetClient client, BluetoothHeadsetClientCall call) { 51a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mDevice = device; 52a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mContext = context; 53a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile = client; 54ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal 552a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (call == null) { 562a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal throw new IllegalStateException("Call is null"); 572a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 582a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal 592a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal mCurrentCall = call; 602a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal handleCallChanged(); 612a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal finishInitializing(); 622a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 632a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal 642a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal // Constructor to be used when a call is intiated on the HF. The call handle is obtained by 652a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal // using the dial() command. 662a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal public HfpClientConnection(Context context, BluetoothDevice device, 672a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal BluetoothHeadsetClient client, Uri number) { 682a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal mDevice = device; 692a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal mContext = context; 702a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal mHeadsetProfile = client; 71ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal 722a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (mHeadsetProfile == null) { 732a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal throw new IllegalStateException("HeadsetProfile is null, returning"); 74ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal } 75ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal 76c4fbd756e2645147470c486ae96f2253f5e13a52Jack He mCurrentCall = mHeadsetProfile.dial(mDevice, number.getSchemeSpecificPart()); 772a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (mCurrentCall == null) { 782a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal close(DisconnectCause.ERROR); 792a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.e(TAG, "Failed to create the call, dial failed."); 802a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal return; 81a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 822a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal 83e74c2decb35910e70cc984510b04af7cc87bd5bfJoseph Pirozzo mHeadsetProfile.connectAudio(device); 842a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal setInitializing(); 852a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal setDialing(); 862a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal finishInitializing(); 872a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 882a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal 892a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal void finishInitializing() { 902a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); 91a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setAudioModeIsVoip(false); 922a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Uri number = Uri.fromParts(PhoneAccount.SCHEME_TEL, mCurrentCall.getNumber(), null); 93a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setAddress(number, TelecomManager.PRESENTATION_ALLOWED); 94c4fbd756e2645147470c486ae96f2253f5e13a52Jack He setConnectionCapabilities( 95c4fbd756e2645147470c486ae96f2253f5e13a52Jack He CAPABILITY_SUPPORT_HOLD | CAPABILITY_MUTE | CAPABILITY_SEPARATE_FROM_CONFERENCE 96c4fbd756e2645147470c486ae96f2253f5e13a52Jack He | CAPABILITY_DISCONNECT_FROM_CONFERENCE | ( 97c4fbd756e2645147470c486ae96f2253f5e13a52Jack He getState() == STATE_ACTIVE || getState() == STATE_HOLDING ? CAPABILITY_HOLD 98c4fbd756e2645147470c486ae96f2253f5e13a52Jack He : 0)); 99ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal } 100a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 101ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public UUID getUUID() { 102ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal return mCurrentCall.getUUID(); 103a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 104a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 105a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public void onHfpDisconnected() { 106a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile = null; 107a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal close(DisconnectCause.ERROR); 108a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 109a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 110a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public void onAdded() { 111a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mAdded = true; 112a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 113a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 114a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public BluetoothHeadsetClientCall getCall() { 115a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal return mCurrentCall; 116a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 117a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 118a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public boolean inConference() { 119c4fbd756e2645147470c486ae96f2253f5e13a52Jack He return mAdded && mCurrentCall != null && mCurrentCall.isMultiParty() 120c4fbd756e2645147470c486ae96f2253f5e13a52Jack He && getState() != Connection.STATE_DISCONNECTED; 121a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 122a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 123a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public void enterPrivateMode() { 124a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.enterPrivateMode(mDevice, mCurrentCall.getId()); 125a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setActive(); 126a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 127a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 128ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public void updateCall(BluetoothHeadsetClientCall call) { 1292a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (call == null) { 1302a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.e(TAG, "Updating call to a null value."); 1312a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal return; 1322a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 133a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mCurrentCall = call; 134ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal } 1352b48337c2b9a20298bd5cbf363366b16bc4b917cSanket Agarwal 136ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal public void handleCallChanged() { 137ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal HfpClientConference conference = (HfpClientConference) getConference(); 138ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal int state = mCurrentCall.getState(); 1392b48337c2b9a20298bd5cbf363366b16bc4b917cSanket Agarwal 1402a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 1412a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "Got call state change to " + state); 1422a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 143a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal switch (state) { 144a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: 145a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setActive(); 146a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (conference != null) { 147a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal conference.setActive(); 148a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 149a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal break; 150a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: 151a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_HELD: 152a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setOnHold(); 153a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (conference != null) { 154a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal conference.setOnHold(); 155a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 156a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal break; 157a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_DIALING: 158a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_ALERTING: 159a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setDialing(); 160a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal break; 161a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_INCOMING: 162a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_WAITING: 163a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setRinging(); 164a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal break; 165a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal case BluetoothHeadsetClientCall.CALL_STATE_TERMINATED: 166322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo if (mPreviousCallState == BluetoothHeadsetClientCall.CALL_STATE_INCOMING 167322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo || mPreviousCallState == BluetoothHeadsetClientCall.CALL_STATE_WAITING) { 168322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo close(DisconnectCause.MISSED); 169322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo } else if (mLocalDisconnect) { 170322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo close(DisconnectCause.LOCAL); 171322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo } else { 172322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo close(DisconnectCause.REMOTE); 173322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo } 174a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal break; 175a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal default: 176a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal Log.wtf(TAG, "Unexpected phone state " + state); 177a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 178322e4d5fdfe6f9b9f754852a23aa82bb84bbd2e3Joseph Pirozzo mPreviousCallState = state; 179a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 180a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 181b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void close(int cause) { 1822a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 183b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal Log.d(TAG, "Closing call " + mCurrentCall + "state: " + mClosed); 1842a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 185a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (mClosed) { 186a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal return; 187a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 1886b7afaa650ff89cc8f6a6580760307dc2657df92Sanket Agarwal Log.d(TAG, "Setting " + mCurrentCall + " to disconnected " + getTelecomCallId()); 189a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal setDisconnected(new DisconnectCause(cause)); 190a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 191a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mClosed = true; 192a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mCurrentCall = null; 193a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 194a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal destroy(); 195a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 196a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 197b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized boolean isClosing() { 198b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal return mClosing; 199b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal } 200b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal 201515626a94a01807a5a9d49af9a8cdb1be6251808Sanket Agarwal public synchronized BluetoothDevice getDevice() { 202515626a94a01807a5a9d49af9a8cdb1be6251808Sanket Agarwal return mDevice; 203515626a94a01807a5a9d49af9a8cdb1be6251808Sanket Agarwal } 204515626a94a01807a5a9d49af9a8cdb1be6251808Sanket Agarwal 205a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 206b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void onPlayDtmfTone(char c) { 2072a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2082a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onPlayDtmfTone " + c + " " + mCurrentCall); 2092a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 2102a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (!mClosed) { 211a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.sendDTMF(mDevice, (byte) c); 212a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 213a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 214a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 215a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 2162b48337c2b9a20298bd5cbf363366b16bc4b917cSanket Agarwal public synchronized void onDisconnect() { 2172a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2182a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onDisconnect call: " + mCurrentCall + " state: " + mClosed); 2192a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 2202a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal // The call is not closed so we should send a terminate here. 2212a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (!mClosed) { 222ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal mHeadsetProfile.terminateCall(mDevice, mCurrentCall); 223ca6e7c65b87c52f5e81b273d7ad979a81b52f991Sanket Agarwal mLocalDisconnect = true; 224b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal mClosing = true; 225a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 226a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 227a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 228a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 229a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public void onAbort() { 2302a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2312a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onAbort " + mCurrentCall); 2322a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 233a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal onDisconnect(); 234a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 235a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 236a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 237b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void onHold() { 2382a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2392a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onHold " + mCurrentCall); 2402a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 2412a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (!mClosed) { 242a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.holdCall(mDevice); 243a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 244a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 245a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 246a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 247b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void onUnhold() { 248a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (getConnectionService().getAllConnections().size() > 1) { 249a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal Log.w(TAG, "Ignoring unhold; call hold on the foreground call"); 250a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal return; 251a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 2522a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2532a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onUnhold " + mCurrentCall); 2542a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 2552a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (!mClosed) { 256a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD); 257a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 258a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 259a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 260a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 261b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void onAnswer() { 2622a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2632a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onAnswer " + mCurrentCall); 2642a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 265a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (!mClosed) { 266a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE); 267a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 268e74c2decb35910e70cc984510b04af7cc87bd5bfJoseph Pirozzo mHeadsetProfile.connectAudio(mDevice); 269a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 270a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 271a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 272b88c0d7495471f3986844e8c8b2aca7f7f2f4c8eSanket Agarwal public synchronized void onReject() { 2732a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal if (DBG) { 2742a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal Log.d(TAG, "onReject " + mCurrentCall); 2752a32ce991573191acde4d5d2f875658ada301874Sanket Agarwal } 276a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (!mClosed) { 277a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal mHeadsetProfile.rejectCall(mDevice); 278a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 279a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 280a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 281a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 282a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public boolean equals(Object o) { 283a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal if (!(o instanceof HfpClientConnection)) { 284a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal return false; 285a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 286a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal Uri otherAddr = ((HfpClientConnection) o).getAddress(); 287a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal return getAddress() == otherAddr || otherAddr != null && otherAddr.equals(getAddress()); 288a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 289a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal 290a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal @Override 291a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal public String toString() { 292c4fbd756e2645147470c486ae96f2253f5e13a52Jack He return "HfpClientConnection{" + getAddress() + "," + stateToString(getState()) + "," 293c4fbd756e2645147470c486ae96f2253f5e13a52Jack He + mCurrentCall + "}"; 294a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal } 295a9ad98ec1222093baecd70b32611c3a74ba7f2d8Sanket Agarwal} 296