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