168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon/*
268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Copyright (C) 2014 The Android Open Source Project
368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon *
468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License");
568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * you may not use this file except in compliance with the License.
668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * You may obtain a copy of the License at
768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon *
868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon *      http://www.apache.org/licenses/LICENSE-2.0
968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon *
1068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Unless required by applicable law or agreed to in writing, software
1168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS,
1268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * See the License for the specific language governing permissions and
1468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * limitations under the License.
1568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */
1668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
1768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonpackage com.android.server.telecom;
1868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
1968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothAdapter;
2068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothHeadset;
2168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothProfile;
2268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.IBluetoothHeadsetPhone;
2368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.BroadcastReceiver;
2468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.Context;
2568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.Intent;
2668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.IntentFilter;
2768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.net.Uri;
28ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordonimport android.os.Binder;
2968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.IBinder;
3068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.RemoteException;
3107bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awadimport android.telecom.Connection;
32953e1af643b66df6f931d76c23bcc54147668cd4Brad Ebingerimport android.telecom.Log;
3368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telecom.PhoneAccount;
343cab92aa08063db6f63e3bc032332c377eac1de5Hall Liuimport android.telecom.VideoProfile;
3568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telephony.PhoneNumberUtils;
3668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telephony.TelephonyManager;
3768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.text.TextUtils;
3868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
395385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebingerimport com.android.internal.annotations.VisibleForTesting;
4068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport com.android.server.telecom.CallsManager.CallsManagerListener;
4168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordonimport java.util.Collection;
4333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordonimport java.util.HashMap;
4468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport java.util.List;
4533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordonimport java.util.Map;
4668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon/**
4868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Bluetooth headset manager for Telecom. This class shares the call state with the bluetooth device
4968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * and accepts call-related commands to perform on behalf of the BT device.
5068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */
51b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liupublic class BluetoothPhoneServiceImpl {
52b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu
53b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu    public interface BluetoothPhoneServiceImplFactory {
54b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu        BluetoothPhoneServiceImpl makeBluetoothPhoneServiceImpl(Context context,
55b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu                TelecomSystem.SyncRoot lock, CallsManager callsManager,
56b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu                PhoneAccountRegistrar phoneAccountRegistrar);
57b3979ee8e636820cc5e68f26562bc02987e5d489Hall Liu    }
5868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
5968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final String TAG = "BluetoothPhoneService";
6068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
6168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // match up with bthf_call_state_t of bt_hf.h
6268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_ACTIVE = 0;
6368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_HELD = 1;
6468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_DIALING = 2;
6568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_ALERTING = 3;
6668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_INCOMING = 4;
6768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_WAITING = 5;
6868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CALL_STATE_IDLE = 6;
69b3ccbb31fc30056ba45559659391313c27605cabHonggang    private static final int CALL_STATE_DISCONNECTED = 7;
7068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
7168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // match up with bthf_call_state_t of bt_hf.h
7268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // Terminate all held or set UDUB("busy") to a waiting call
7368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CHLD_TYPE_RELEASEHELD = 0;
7468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // Terminate all active calls and accepts a waiting/held call
7568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
7668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // Hold all active calls and accepts a waiting/held call
7768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
7868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    // Add all held calls to a conference
7968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
8068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
81a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon    private int mNumActiveCalls = 0;
82a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon    private int mNumHeldCalls = 0;
836a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu    private int mNumChildrenOfActiveCall = 0;
84a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon    private int mBluetoothCallState = CALL_STATE_IDLE;
85a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon    private String mRingingAddress = null;
86a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon    private int mRingingAddressType = 0;
87c0ca76ee6dc2d21cf1e9f310f2d16662c8ceb25eSantos Cordon    private Call mOldHeldCall = null;
88b3ccbb31fc30056ba45559659391313c27605cabHonggang    private boolean mIsDisconnectedTonePlaying = false;
89a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon
9068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    /**
9168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * Binder implementation of IBluetoothHeadsetPhone. Implements the command interface that the
9268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * bluetooth headset code uses to control call.
9368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     */
945385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    @VisibleForTesting
955385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    public final IBluetoothHeadsetPhone.Stub mBinder = new IBluetoothHeadsetPhone.Stub() {
9668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
9768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean answerCall() throws RemoteException {
988d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
998d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
1003165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.aC");
101ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
102ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
103ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "BT - answering call");
104ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Call call = mCallsManager.getRingingCall();
105ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (call != null) {
1063cab92aa08063db6f63e3bc032332c377eac1de5Hall Liu                        mCallsManager.answerCall(call, VideoProfile.STATE_AUDIO_ONLY);
107ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        return true;
108ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
109ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return false;
110ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
111ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
1123165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
1138d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
114ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon
1158d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
11668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
11768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
11868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
11968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean hangupCall() throws RemoteException {
1208d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
1218d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
1223165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.hC");
123ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
124ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
125ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "BT - hanging up call");
126ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Call call = mCallsManager.getForegroundCall();
127ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (call != null) {
128ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        mCallsManager.disconnectCall(call);
129ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        return true;
130ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
131ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return false;
132ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
133ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
1343165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
1358d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
1368d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
13768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
13868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
13968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
14068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean sendDtmf(int dtmf) throws RemoteException {
1418d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
1428d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
1433165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.sD");
144ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
145ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
146ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "BT - sendDtmf %c", Log.DEBUG ? dtmf : '.');
147ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Call call = mCallsManager.getForegroundCall();
148ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (call != null) {
149ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        // TODO: Consider making this a queue instead of starting/stopping
150ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        // in quick succession.
151ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        mCallsManager.playDtmfTone(call, (char) dtmf);
152ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        mCallsManager.stopDtmfTone(call);
153ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        return true;
154ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
155ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return false;
156ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
157ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
1583165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
1598d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
1608d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
16168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
16268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
16368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
16468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public String getNetworkOperator() throws RemoteException {
1658d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
1668d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
1673165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.gNO");
168ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
169ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
170ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "getNetworkOperator");
171ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    PhoneAccount account = getBestPhoneAccount();
17222403a76d81aa26fa7407a4070765e92a69d6cd0Santos Cordon                    if (account != null && account.getLabel() != null) {
173ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        return account.getLabel().toString();
174ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    } else {
175ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        // Finally, just get the network name from telephony.
176ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        return TelephonyManager.from(mContext)
177ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                                .getNetworkOperatorName();
178ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
179ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
180ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
1813165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
1828d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
1838d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
18468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
18568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
18668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
18768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public String getSubscriberNumber() throws RemoteException {
1888d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
1898d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
1903165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.gSN");
191ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
192ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
193ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "getSubscriberNumber");
194ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    String address = null;
195ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    PhoneAccount account = getBestPhoneAccount();
196ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (account != null) {
197ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        Uri addressUri = account.getAddress();
198ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        if (addressUri != null) {
199ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                            address = addressUri.getSchemeSpecificPart();
200ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        }
2018d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                    }
202ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (TextUtils.isEmpty(address)) {
203ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        address = TelephonyManager.from(mContext).getLine1Number();
2043109262f814309b0c93464006ba29d6a53b3145bAndre Eisenbach                        if (address == null) address = "";
205ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
206ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return address;
207ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
208ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
2093165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
2108d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
2118d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
21268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
21368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
21468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
21568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean listCurrentCalls() throws RemoteException {
2168d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
2178d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
2183165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.lCC");
219ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
220ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
221ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    // only log if it is after we recently updated the headset state or else it can
222ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    // clog the android log since this can be queried every second.
223ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    boolean logQuery = mHeadsetUpdatedRecently;
224ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    mHeadsetUpdatedRecently = false;
22588a4a60284de8e1222488667b810b098c16d22acSantos Cordon
226ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    if (logQuery) {
227ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                        Log.i(TAG, "listcurrentCalls");
228ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    }
229ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon
230ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    sendListOfCalls(logQuery);
231ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return true;
232ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
233ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
2343165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
235ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                }
23688a4a60284de8e1222488667b810b098c16d22acSantos Cordon            }
23768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
23868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
23968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
24068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean queryPhoneState() throws RemoteException {
2418d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
2428d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
2433165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.qPS");
244ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
245ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
246ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "queryPhoneState");
247ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    updateHeadsetWithCallState(true /* force */);
248ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return true;
249ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
250ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
2513165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
252ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                }
2538d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
25468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
25568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
25668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
25768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public boolean processChld(int chld) throws RemoteException {
2588d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
2598d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                enforceModifyPermission();
2603165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                Log.startSession("BPSI.pC");
261ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                long token = Binder.clearCallingIdentity();
262ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                try {
263ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Log.i(TAG, "processChld %d", chld);
264ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    return BluetoothPhoneServiceImpl.this.processChld(chld);
265ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                } finally {
266ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                    Binder.restoreCallingIdentity(token);
2673165d50d3fc688d632faecfae9c2f987e537941fBrad Ebinger                    Log.endSession();
268ebf2d0f2b4f17e958b0b23d94edc6b0d05334e43Santos Cordon                }
2698d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            }
27068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
27168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
27268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
27368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void updateBtHandsfreeAfterRadioTechnologyChange() throws RemoteException {
2748d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            Log.d(TAG, "RAT change - deprecated");
27568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            // deprecated
27668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
27768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
27868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
27968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void cdmaSetSecondCallState(boolean state) throws RemoteException {
2808d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            Log.d(TAG, "cdma 1 - deprecated");
28168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            // deprecated
28268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
28368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
28468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
28568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void cdmaSwapSecondCallState() throws RemoteException {
2868d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            Log.d(TAG, "cdma 2 - deprecated");
28768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            // deprecated
28868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
28968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    };
29068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
29168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    /**
29268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * Listens to call changes from the CallsManager and calls into methods to update the bluetooth
29368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * headset with the new states.
29468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     */
2955385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    @VisibleForTesting
2965385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    public CallsManagerListener mCallsManagerListener = new CallsManagerListenerBase() {
29768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
29868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void onCallAdded(Call call) {
299f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            if (call.isExternalCall()) {
300f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn                return;
301f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            }
302cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn            updateHeadsetWithCallState(false /* force */);
30368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
30468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
30568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
30668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void onCallRemoved(Call call) {
307f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            if (call.isExternalCall()) {
308f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn                return;
309f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            }
31033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            mClccIndexMap.remove(call);
311cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn            updateHeadsetWithCallState(false /* force */);
31268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
31368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
3141a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn        /**
3151a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         * Where a call which was external becomes a regular call, or a regular call becomes
3161a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         * external, treat as an add or remove, respectively.
3171a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         *
3181a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         * @param call The call.
3191a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         * @param isExternalCall {@code True} if the call became external, {@code false} otherwise.
3201a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn         */
3211a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn        @Override
3221a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn        public void onExternalCallChanged(Call call, boolean isExternalCall) {
3231a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn            if (isExternalCall) {
3241a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn                onCallRemoved(call);
3251a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn            } else {
3261a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn                onCallAdded(call);
3271a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn            }
3281a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn        }
3291a40c4f4daf2cdfba3f67383c726f93b85a98b00Tyler Gunn
33068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
33168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void onCallStateChanged(Call call, int oldState, int newState) {
332f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            if (call.isExternalCall()) {
333f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn                return;
334f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            }
335720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // If a call is being put on hold because of a new connecting call, ignore the
336720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // CONNECTING since the BT state update needs to send out the numHeld = 1 + dialing
337720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // state atomically.
338720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // When the call later transitions to DIALING/DISCONNECTED we will then send out the
339720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // aggregated update.
340720bcbe344a3e907393026f7019d590306c92194Yorke Lee            if (oldState == CallState.ACTIVE && newState == CallState.ON_HOLD) {
34178a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad                for (Call otherCall : mCallsManager.getCalls()) {
342720bcbe344a3e907393026f7019d590306c92194Yorke Lee                    if (otherCall.getState() == CallState.CONNECTING) {
343720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        return;
344720bcbe344a3e907393026f7019d590306c92194Yorke Lee                    }
345720bcbe344a3e907393026f7019d590306c92194Yorke Lee                }
346720bcbe344a3e907393026f7019d590306c92194Yorke Lee            }
347720bcbe344a3e907393026f7019d590306c92194Yorke Lee
348720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // To have an active call and another dialing at the same time is an invalid BT
349720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // state. We can assume that the active call will be automatically held which will
350720bcbe344a3e907393026f7019d590306c92194Yorke Lee            // send another update at which point we will be in the right state.
35178a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad            if (mCallsManager.getActiveCall() != null
3521e37be5dd86a51b90e461f09dc8a89effe4aee21Tyler Gunn                    && oldState == CallState.CONNECTING &&
3531e37be5dd86a51b90e461f09dc8a89effe4aee21Tyler Gunn                    (newState == CallState.DIALING || newState == CallState.PULLING)) {
354720bcbe344a3e907393026f7019d590306c92194Yorke Lee                return;
355720bcbe344a3e907393026f7019d590306c92194Yorke Lee            }
356cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn            updateHeadsetWithCallState(false /* force */);
35768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
35868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
35968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
36068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void onIsConferencedChanged(Call call) {
361f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            if (call.isExternalCall()) {
362f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn                return;
363f15dc33f87f88e21ef745952a68af65c86e1bf1eTyler Gunn            }
364720bcbe344a3e907393026f7019d590306c92194Yorke Lee            /*
365720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * Filter certain onIsConferencedChanged callbacks. Unfortunately this needs to be done
366720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * because conference change events are not atomic and multiple callbacks get fired
367720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * when two calls are conferenced together. This confuses updateHeadsetWithCallState
368720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * if it runs in the middle of two calls being conferenced and can cause spurious and
369720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * incorrect headset state updates. One of the scenarios is described below for CDMA
370720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * conference calls.
371720bcbe344a3e907393026f7019d590306c92194Yorke Lee             *
372720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * 1) Call 1 and Call 2 are being merged into conference Call 3.
373720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * 2) Call 1 has its parent set to Call 3, but Call 2 does not have a parent yet.
374720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * 3) updateHeadsetWithCallState now thinks that there are two active calls (Call 2 and
375720bcbe344a3e907393026f7019d590306c92194Yorke Lee             * Call 3) when there is actually only one active call (Call 3).
376720bcbe344a3e907393026f7019d590306c92194Yorke Lee             */
377720bcbe344a3e907393026f7019d590306c92194Yorke Lee            if (call.getParentCall() != null) {
378720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // If this call is newly conferenced, ignore the callback. We only care about the
379720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // one sent for the parent conference call.
380720bcbe344a3e907393026f7019d590306c92194Yorke Lee                Log.d(this, "Ignoring onIsConferenceChanged from child call with new parent");
381720bcbe344a3e907393026f7019d590306c92194Yorke Lee                return;
382720bcbe344a3e907393026f7019d590306c92194Yorke Lee            }
383720bcbe344a3e907393026f7019d590306c92194Yorke Lee            if (call.getChildCalls().size() == 1) {
384720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // If this is a parent call with only one child, ignore the callback as well since
385720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // the minimum number of child calls to start a conference call is 2. We expect
386720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // this to be called again when the parent call has another child call added.
387720bcbe344a3e907393026f7019d590306c92194Yorke Lee                Log.d(this, "Ignoring onIsConferenceChanged from parent with only one child call");
388720bcbe344a3e907393026f7019d590306c92194Yorke Lee                return;
389720bcbe344a3e907393026f7019d590306c92194Yorke Lee            }
390cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn            updateHeadsetWithCallState(false /* force */);
39168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
392b3ccbb31fc30056ba45559659391313c27605cabHonggang
393b3ccbb31fc30056ba45559659391313c27605cabHonggang        @Override
394b3ccbb31fc30056ba45559659391313c27605cabHonggang        public void onDisconnectedTonePlaying(boolean isTonePlaying) {
395b3ccbb31fc30056ba45559659391313c27605cabHonggang            mIsDisconnectedTonePlaying = isTonePlaying;
396b3ccbb31fc30056ba45559659391313c27605cabHonggang            updateHeadsetWithCallState(false /* force */);
397b3ccbb31fc30056ba45559659391313c27605cabHonggang        }
39868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    };
39968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
40068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    /**
40168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * Listens to connections and disconnections of bluetooth headsets.  We need to save the current
40268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * bluetooth headset so that we know where to send call updates.
40368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     */
4045385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    @VisibleForTesting
4055385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    public BluetoothProfile.ServiceListener mProfileListener =
40668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            new BluetoothProfile.ServiceListener() {
4075385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                @Override
4085385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                public void onServiceConnected(int profile, BluetoothProfile proxy) {
4095385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                    synchronized (mLock) {
4105385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                        setBluetoothHeadset(new BluetoothHeadsetProxy((BluetoothHeadset) proxy));
4115385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                    }
4125385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                }
41368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4145385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                @Override
4155385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                public void onServiceDisconnected(int profile) {
4165385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                    synchronized (mLock) {
4175385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                        mBluetoothHeadset = null;
4185385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                    }
4195385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                }
4205385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger            };
42168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
42268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    /**
42368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * Receives events for global state changes of the bluetooth adapter.
42468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     */
425712860276af91b649f2787a9a793521b16f091beBrad Ebinger    @VisibleForTesting
426712860276af91b649f2787a9a793521b16f091beBrad Ebinger    public final BroadcastReceiver mBluetoothAdapterReceiver = new BroadcastReceiver() {
42768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        @Override
42868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        public void onReceive(Context context, Intent intent) {
4298d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            synchronized (mLock) {
4308d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                int state = intent
4318d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                        .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
4328d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                Log.d(TAG, "Bluetooth Adapter state: %d", state);
4338d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                if (state == BluetoothAdapter.STATE_ON) {
4348d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                    try {
4358d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                        mBinder.queryPhoneState();
4368d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                    } catch (RemoteException e) {
4378d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                        // Remote exception not expected
4388d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                    }
4398d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                }
44068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
44168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
44268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    };
44368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4447948f5b5aeae8e508ee4310595669c484c786dd7Hall Liu    private BluetoothAdapterProxy mBluetoothAdapter;
4455385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    private BluetoothHeadsetProxy mBluetoothHeadset;
44668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
44733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls).
44833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    private Map<Call, Integer> mClccIndexMap = new HashMap<>();
44933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
45088a4a60284de8e1222488667b810b098c16d22acSantos Cordon    private boolean mHeadsetUpdatedRecently = false;
45188a4a60284de8e1222488667b810b098c16d22acSantos Cordon
4528d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad    private final Context mContext;
4538d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad    private final TelecomSystem.SyncRoot mLock;
4548d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad    private final CallsManager mCallsManager;
4558d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad    private final PhoneAccountRegistrar mPhoneAccountRegistrar;
45668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
45778a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad    public IBinder getBinder() {
45868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        return mBinder;
45968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
46068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
46178a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad    public BluetoothPhoneServiceImpl(
46278a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad            Context context,
4638d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad            TelecomSystem.SyncRoot lock,
46478a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad            CallsManager callsManager,
4657948f5b5aeae8e508ee4310595669c484c786dd7Hall Liu            BluetoothAdapterProxy bluetoothAdapter,
46678a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad            PhoneAccountRegistrar phoneAccountRegistrar) {
46778a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        Log.d(this, "onCreate");
46878a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad
46978a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mContext = context;
4708d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        mLock = lock;
47178a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mCallsManager = callsManager;
47278a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mPhoneAccountRegistrar = phoneAccountRegistrar;
47368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4747948f5b5aeae8e508ee4310595669c484c786dd7Hall Liu        mBluetoothAdapter = bluetoothAdapter;
47568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (mBluetoothAdapter == null) {
47678a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad            Log.d(this, "BluetoothPhoneService shutting down, no BT Adapter found.");
47768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            return;
47868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
47978a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
48068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
48168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
48278a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        context.registerReceiver(mBluetoothAdapterReceiver, intentFilter);
48368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
48478a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mCallsManager.addListener(mCallsManagerListener);
485cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn        updateHeadsetWithCallState(false /* force */);
48668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
48768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
4885385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    @VisibleForTesting
4895385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    public void setBluetoothHeadset(BluetoothHeadsetProxy bluetoothHeadset) {
4905385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger        mBluetoothHeadset = bluetoothHeadset;
4915385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger    }
4925385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger
49368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private boolean processChld(int chld) {
4948d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call activeCall = mCallsManager.getActiveCall();
4958d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call ringingCall = mCallsManager.getRingingCall();
4968d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call heldCall = mCallsManager.getHeldCall();
49768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
49866fe882a6437de1010af0dc8cd7350f81f2e028aSantos Cordon        // TODO: Keeping as Log.i for now.  Move to Log.d after L release if BT proves stable.
49966fe882a6437de1010af0dc8cd7350f81f2e028aSantos Cordon        Log.i(TAG, "Active: %s\nRinging: %s\nHeld: %s", activeCall, ringingCall, heldCall);
50088a4a60284de8e1222488667b810b098c16d22acSantos Cordon
50168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (chld == CHLD_TYPE_RELEASEHELD) {
50268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            if (ringingCall != null) {
5038d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                mCallsManager.rejectCall(ringingCall, false, null);
50468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
50568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            } else if (heldCall != null) {
5068d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                mCallsManager.disconnectCall(heldCall);
50768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
50868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
50968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) {
510f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala            if (activeCall == null && ringingCall == null && heldCall == null)
511f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala                return false;
51268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            if (activeCall != null) {
5138d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                mCallsManager.disconnectCall(activeCall);
51468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                if (ringingCall != null) {
5153cab92aa08063db6f63e3bc032332c377eac1de5Hall Liu                    mCallsManager.answerCall(ringingCall, VideoProfile.STATE_AUDIO_ONLY);
51668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                } else if (heldCall != null) {
5178d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                    mCallsManager.unholdCall(heldCall);
51868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                }
51968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
52068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
521f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala            if (ringingCall != null) {
522f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala                mCallsManager.answerCall(ringingCall, ringingCall.getVideoState());
523f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala            } else if (heldCall != null) {
524f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala                mCallsManager.unholdCall(heldCall);
525f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala            }
526f5bdfb5aa24df7b9d6be01d10fe58342cc5bcc59Satish Kodishala            return true;
52768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) {
52807bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            if (activeCall != null && activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
52988a4a60284de8e1222488667b810b098c16d22acSantos Cordon                activeCall.swapConference();
5300ae2df8877ab703fbdeb33c89bc7a694af5611edMallikarjuna GB                Log.i(TAG, "CDMA calls in conference swapped, updating headset");
5310ae2df8877ab703fbdeb33c89bc7a694af5611edMallikarjuna GB                updateHeadsetWithCallState(true /* force */);
53288a4a60284de8e1222488667b810b098c16d22acSantos Cordon                return true;
53388a4a60284de8e1222488667b810b098c16d22acSantos Cordon            } else if (ringingCall != null) {
5343cab92aa08063db6f63e3bc032332c377eac1de5Hall Liu                mCallsManager.answerCall(ringingCall, VideoProfile.STATE_AUDIO_ONLY);
53568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
53668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            } else if (heldCall != null) {
53768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                // CallsManager will hold any active calls when unhold() is called on a
53868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                // currently-held call.
5398d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                mCallsManager.unholdCall(heldCall);
54068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
54107bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            } else if (activeCall != null && activeCall.can(Connection.CAPABILITY_HOLD)) {
5428d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                mCallsManager.holdCall(activeCall);
54368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                return true;
54468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
54568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        } else if (chld == CHLD_TYPE_ADDHELDTOCONF) {
54668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            if (activeCall != null) {
54707bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad                if (activeCall.can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
54888a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    activeCall.mergeConference();
54968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                    return true;
55088a4a60284de8e1222488667b810b098c16d22acSantos Cordon                } else {
55188a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    List<Call> conferenceable = activeCall.getConferenceableCalls();
55288a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    if (!conferenceable.isEmpty()) {
5538d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad                        mCallsManager.conference(activeCall, conferenceable.get(0));
55488a4a60284de8e1222488667b810b098c16d22acSantos Cordon                        return true;
5555385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                    }
55668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                }
55768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
55868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
55968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        return false;
56068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
56168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
56268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private void enforceModifyPermission() {
56378a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        mContext.enforceCallingOrSelfPermission(
56478a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad                android.Manifest.permission.MODIFY_PHONE_STATE, null);
56568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
56668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
56788a4a60284de8e1222488667b810b098c16d22acSantos Cordon    private void sendListOfCalls(boolean shouldLog) {
56878a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        Collection<Call> mCalls = mCallsManager.getCalls();
56933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        for (Call call : mCalls) {
57033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            // We don't send the parent conference call to the bluetooth device.
5719365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            // We do, however want to send conferences that have no children to the bluetooth
5729365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            // device (e.g. IMS Conference).
5739365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            if (!call.isConference() ||
5749365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn                    (call.isConference() && call
5759365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn                            .can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN))) {
57688a4a60284de8e1222488667b810b098c16d22acSantos Cordon                sendClccForCall(call, shouldLog);
57733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            }
57833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        }
57933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        sendClccEndMarker();
58033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    }
58133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
58233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    /**
58333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon     * Sends a single clcc (C* List Current Calls) event for the specified call.
58433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon     */
58588a4a60284de8e1222488667b810b098c16d22acSantos Cordon    private void sendClccForCall(Call call, boolean shouldLog) {
58678a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        boolean isForeground = mCallsManager.getForegroundCall() == call;
58733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        int state = convertCallState(call.getState(), isForeground);
58888a4a60284de8e1222488667b810b098c16d22acSantos Cordon        boolean isPartOfConference = false;
5899365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn        boolean isConferenceWithNoChildren = call.isConference() && call
5909365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn                .can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
59105a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen
59205a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen        if (state == CALL_STATE_IDLE) {
59305a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen            return;
59405a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen        }
59505a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen
59688a4a60284de8e1222488667b810b098c16d22acSantos Cordon        Call conferenceCall = call.getParentCall();
59788a4a60284de8e1222488667b810b098c16d22acSantos Cordon        if (conferenceCall != null) {
59888a4a60284de8e1222488667b810b098c16d22acSantos Cordon            isPartOfConference = true;
59988a4a60284de8e1222488667b810b098c16d22acSantos Cordon
60088a4a60284de8e1222488667b810b098c16d22acSantos Cordon            // Run some alternative states for Conference-level merge/swap support.
60188a4a60284de8e1222488667b810b098c16d22acSantos Cordon            // Basically, if call supports swapping or merging at the conference-level, then we need
60207bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            // to expose the calls as having distinct states (ACTIVE vs CAPABILITY_HOLD) or the
60307bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            // functionality won't show up on the bluetooth device.
60488a4a60284de8e1222488667b810b098c16d22acSantos Cordon
60588a4a60284de8e1222488667b810b098c16d22acSantos Cordon            // Before doing any special logic, ensure that we are dealing with an ACTIVE call and
60688a4a60284de8e1222488667b810b098c16d22acSantos Cordon            // that the conference itself has a notion of the current "active" child call.
60788a4a60284de8e1222488667b810b098c16d22acSantos Cordon            Call activeChild = conferenceCall.getConferenceLevelActiveCall();
60888a4a60284de8e1222488667b810b098c16d22acSantos Cordon            if (state == CALL_STATE_ACTIVE && activeChild != null) {
60988a4a60284de8e1222488667b810b098c16d22acSantos Cordon                // Reevaluate state if we can MERGE or if we can SWAP without previously having
61088a4a60284de8e1222488667b810b098c16d22acSantos Cordon                // MERGED.
61188a4a60284de8e1222488667b810b098c16d22acSantos Cordon                boolean shouldReevaluateState =
61207bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad                        conferenceCall.can(Connection.CAPABILITY_MERGE_CONFERENCE) ||
61307bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad                        (conferenceCall.can(Connection.CAPABILITY_SWAP_CONFERENCE) &&
6145385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                        !conferenceCall.wasConferencePreviouslyMerged());
61588a4a60284de8e1222488667b810b098c16d22acSantos Cordon
61688a4a60284de8e1222488667b810b098c16d22acSantos Cordon                if (shouldReevaluateState) {
61788a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    isPartOfConference = false;
61888a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    if (call == activeChild) {
61988a4a60284de8e1222488667b810b098c16d22acSantos Cordon                        state = CALL_STATE_ACTIVE;
62088a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    } else {
62188a4a60284de8e1222488667b810b098c16d22acSantos Cordon                        // At this point we know there is an "active" child and we know that it is
62288a4a60284de8e1222488667b810b098c16d22acSantos Cordon                        // not this call, so set it to HELD instead.
62388a4a60284de8e1222488667b810b098c16d22acSantos Cordon                        state = CALL_STATE_HELD;
62488a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    }
62588a4a60284de8e1222488667b810b098c16d22acSantos Cordon                }
62688a4a60284de8e1222488667b810b098c16d22acSantos Cordon            }
6276fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu            if (conferenceCall.getState() == CallState.ON_HOLD &&
6286fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu                    conferenceCall.can(Connection.CAPABILITY_MANAGE_CONFERENCE)) {
6296fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu                // If the parent IMS CEP conference call is on hold, we should mark this call as
6306fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu                // being on hold regardless of what the other children are doing.
6316fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu                state = CALL_STATE_HELD;
6326fccadb9ac133412c216ba5628ebcc5852eeb328Hall Liu            }
6339365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn        } else if (isConferenceWithNoChildren) {
6349365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            // Handle the special case of an IMS conference call without conference event package
6359365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            // support.  The call will be marked as a conference, but the conference will not have
6369365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            // child calls where conference event packages are not used by the carrier.
6379365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn            isPartOfConference = true;
63888a4a60284de8e1222488667b810b098c16d22acSantos Cordon        }
63988a4a60284de8e1222488667b810b098c16d22acSantos Cordon
64005a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen        int index = getIndexForCall(call);
64105a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen        int direction = call.isIncoming() ? 1 : 0;
642fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee        final Uri addressUri;
643fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee        if (call.getGatewayInfo() != null) {
644fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee            addressUri = call.getGatewayInfo().getOriginalAddress();
645fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee        } else {
646fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee            addressUri = call.getHandle();
647fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee        }
648f4bd7c2179028999fa3964bf0d45a593171b5480Satish Kodishala
64933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        String address = addressUri == null ? null : addressUri.getSchemeSpecificPart();
650f4bd7c2179028999fa3964bf0d45a593171b5480Satish Kodishala        if (address != null) {
651f4bd7c2179028999fa3964bf0d45a593171b5480Satish Kodishala            address = PhoneNumberUtils.stripSeparators(address);
652f4bd7c2179028999fa3964bf0d45a593171b5480Satish Kodishala        }
653f4bd7c2179028999fa3964bf0d45a593171b5480Satish Kodishala
65433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address);
65533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
65688a4a60284de8e1222488667b810b098c16d22acSantos Cordon        if (shouldLog) {
65788a4a60284de8e1222488667b810b098c16d22acSantos Cordon            Log.i(this, "sending clcc for call %d, %d, %d, %b, %s, %d",
65888a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    index, direction, state, isPartOfConference, Log.piiHandle(address),
65988a4a60284de8e1222488667b810b098c16d22acSantos Cordon                    addressType);
66088a4a60284de8e1222488667b810b098c16d22acSantos Cordon        }
661e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee
662e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee        if (mBluetoothHeadset != null) {
663e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee            mBluetoothHeadset.clccResponse(
664e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee                    index, direction, state, 0, isPartOfConference, address, addressType);
665e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee        }
66633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    }
66733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
66833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    private void sendClccEndMarker() {
66933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        // End marker is recognized with an index value of 0. All other parameters are ignored.
670e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee        if (mBluetoothHeadset != null) {
671e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee            mBluetoothHeadset.clccResponse(0 /* index */, 0, 0, 0, false, null, 0);
672e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee        }
67333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    }
67433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
67533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    /**
67633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon     * Returns the caches index for the specified call.  If no such index exists, then an index is
67733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon     * given (smallest number starting from 1 that isn't already taken).
67833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon     */
67933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    private int getIndexForCall(Call call) {
68033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        if (mClccIndexMap.containsKey(call)) {
68133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            return mClccIndexMap.get(call);
68233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        }
68333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
68433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        int i = 1;  // Indexes for bluetooth clcc are 1-based.
68533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        while (mClccIndexMap.containsValue(i)) {
68633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            i++;
68733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        }
68833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
68933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        // NOTE: Indexes are removed in {@link #onCallRemoved}.
69033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        mClccIndexMap.put(call, i);
69133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        return i;
69233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    }
69333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
694cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn    /**
695cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     * Sends an update of the current call state to the current Headset.
696cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     *
697cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     * @param force {@code true} if the headset state should be sent regardless if no changes to the
698cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     *      state have occurred, {@code false} if the state should only be sent if the state has
699cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     *      changed.
700cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn     */
701cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn    private void updateHeadsetWithCallState(boolean force) {
7028d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call activeCall = mCallsManager.getActiveCall();
7038d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call ringingCall = mCallsManager.getRingingCall();
7048d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call heldCall = mCallsManager.getHeldCall();
70568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
70668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        int bluetoothCallState = getBluetoothCallStateForUpdate();
70768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
70868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        String ringingAddress = null;
70968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        int ringingAddressType = 128;
710ecaaeac225ada350b9b3acfb485583cc388050deSantos Cordon        if (ringingCall != null && ringingCall.getHandle() != null) {
71168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            ringingAddress = ringingCall.getHandle().getSchemeSpecificPart();
71268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            if (ringingAddress != null) {
71368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon                ringingAddressType = PhoneNumberUtils.toaFromString(ringingAddress);
71468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            }
71568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
71668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (ringingAddress == null) {
71768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            ringingAddress = "";
71868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
71968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
720a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon        int numActiveCalls = activeCall == null ? 0 : 1;
7218d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        int numHeldCalls = mCallsManager.getNumHeldCalls();
7226a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu        int numChildrenOfActiveCall = activeCall == null ? 0 : activeCall.getChildCalls().size();
7236a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu
7247d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius        // Intermediate state for GSM calls which are in the process of being swapped.
7257d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius        // TODO: Should we be hardcoding this value to 2 or should we check if all top level calls
7267d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius        //       are held?
7277d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius        boolean callsPendingSwitch = (numHeldCalls == 2);
728a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon
72988a4a60284de8e1222488667b810b098c16d22acSantos Cordon        // For conference calls which support swapping the active call within the conference
73088a4a60284de8e1222488667b810b098c16d22acSantos Cordon        // (namely CDMA calls) we need to expose that as a held call in order for the BT device
73188a4a60284de8e1222488667b810b098c16d22acSantos Cordon        // to show "swap" and "merge" functionality.
732720bcbe344a3e907393026f7019d590306c92194Yorke Lee        boolean ignoreHeldCallChange = false;
7339365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn        if (activeCall != null && activeCall.isConference() &&
7349365c274f5f3c0b1c289f54e855792bfb24096d6Tyler Gunn                !activeCall.can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
73507bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            if (activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
73688a4a60284de8e1222488667b810b098c16d22acSantos Cordon                // Indicate that BT device should show SWAP command by indicating that there is a
73788a4a60284de8e1222488667b810b098c16d22acSantos Cordon                // call on hold, but only if the conference wasn't previously merged.
73888a4a60284de8e1222488667b810b098c16d22acSantos Cordon                numHeldCalls = activeCall.wasConferencePreviouslyMerged() ? 0 : 1;
73907bc5ee853bc9a0b4cd46e0c702888b2c7989392Ihab Awad            } else if (activeCall.can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
74088a4a60284de8e1222488667b810b098c16d22acSantos Cordon                numHeldCalls = 1;  // Merge is available, so expose via numHeldCalls.
74188a4a60284de8e1222488667b810b098c16d22acSantos Cordon            }
742720bcbe344a3e907393026f7019d590306c92194Yorke Lee
743720bcbe344a3e907393026f7019d590306c92194Yorke Lee            for (Call childCall : activeCall.getChildCalls()) {
744720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // Held call has changed due to it being combined into a CDMA conference. Keep
745720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // track of this and ignore any future update since it doesn't really count as
746720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // a call change.
747720bcbe344a3e907393026f7019d590306c92194Yorke Lee                if (mOldHeldCall == childCall) {
748720bcbe344a3e907393026f7019d590306c92194Yorke Lee                    ignoreHeldCallChange = true;
749720bcbe344a3e907393026f7019d590306c92194Yorke Lee                    break;
750720bcbe344a3e907393026f7019d590306c92194Yorke Lee                }
751720bcbe344a3e907393026f7019d590306c92194Yorke Lee            }
75288a4a60284de8e1222488667b810b098c16d22acSantos Cordon        }
75388a4a60284de8e1222488667b810b098c16d22acSantos Cordon
754a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon        if (mBluetoothHeadset != null &&
7557d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius                (force ||
7567d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius                        (!callsPendingSwitch &&
7577d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius                                (numActiveCalls != mNumActiveCalls ||
7586a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu                                        numChildrenOfActiveCall != mNumChildrenOfActiveCall ||
7596a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu                                        numHeldCalls != mNumHeldCalls ||
7606a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu                                        bluetoothCallState != mBluetoothCallState ||
7616a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu                                        !TextUtils.equals(ringingAddress, mRingingAddress) ||
7626a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu                                        ringingAddressType != mRingingAddressType ||
7635385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                                (heldCall != mOldHeldCall && !ignoreHeldCallChange))))) {
764a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon
765a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            // If the call is transitioning into the alerting state, send DIALING first.
766a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            // Some devices expect to see a DIALING state prior to seeing an ALERTING state
767a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            // so we need to send it first.
768a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            boolean sendDialingFirst = mBluetoothCallState != bluetoothCallState &&
769a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    bluetoothCallState == CALL_STATE_ALERTING;
770a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon
771c0ca76ee6dc2d21cf1e9f310f2d16662c8ceb25eSantos Cordon            mOldHeldCall = heldCall;
772a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            mNumActiveCalls = numActiveCalls;
7736a89ba2edab624de0dfa9af1d504f683d0130817Hall Liu            mNumChildrenOfActiveCall = numChildrenOfActiveCall;
774a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            mNumHeldCalls = numHeldCalls;
775a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            mBluetoothCallState = bluetoothCallState;
776a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            mRingingAddress = ringingAddress;
777a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            mRingingAddressType = ringingAddressType;
778a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon
779a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            if (sendDialingFirst) {
780720bcbe344a3e907393026f7019d590306c92194Yorke Lee                // Log in full to make logs easier to debug.
781720bcbe344a3e907393026f7019d590306c92194Yorke Lee                Log.i(TAG, "updateHeadsetWithCallState " +
782720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        "numActive %s, " +
783720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        "numHeld %s, " +
784720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        "callState %s, " +
785720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        "ringing number %s, " +
786720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        "ringing type %s",
787720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        mNumActiveCalls,
788720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        mNumHeldCalls,
789720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        CALL_STATE_DIALING,
790720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        Log.pii(mRingingAddress),
791720bcbe344a3e907393026f7019d590306c92194Yorke Lee                        mRingingAddressType);
792a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                mBluetoothHeadset.phoneStateChanged(
793a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                        mNumActiveCalls,
794a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                        mNumHeldCalls,
795a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                        CALL_STATE_DIALING,
796a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                        mRingingAddress,
797a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                        mRingingAddressType);
798a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            }
79968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
800a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon            Log.i(TAG, "updateHeadsetWithCallState " +
801a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    "numActive %s, " +
802a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    "numHeld %s, " +
803a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    "callState %s, " +
804a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    "ringing number %s, " +
805a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    "ringing type %s",
806a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mNumActiveCalls,
807a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mNumHeldCalls,
808a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mBluetoothCallState,
809a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    Log.pii(mRingingAddress),
810a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mRingingAddressType);
81168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
81268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            mBluetoothHeadset.phoneStateChanged(
813a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mNumActiveCalls,
814a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mNumHeldCalls,
815a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mBluetoothCallState,
816a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mRingingAddress,
817a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon                    mRingingAddressType);
81888a4a60284de8e1222488667b810b098c16d22acSantos Cordon
81988a4a60284de8e1222488667b810b098c16d22acSantos Cordon            mHeadsetUpdatedRecently = true;
82068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
82168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
82268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
82368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private int getBluetoothCallStateForUpdate() {
82478a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        CallsManager callsManager = mCallsManager;
8258d5d9ddc66b55b6906364ab3c0e244dab4d58f13Ihab Awad        Call ringingCall = mCallsManager.getRingingCall();
8267d7cf27dd519c8910d98e942adc5a95675eba0c8Roshan Pius        Call dialingCall = mCallsManager.getOutgoingCall();
827b3ccbb31fc30056ba45559659391313c27605cabHonggang        boolean hasOnlyDisconnectedCalls = mCallsManager.hasOnlyDisconnectedCalls();
82868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
82968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        //
83068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // !! WARNING !!
83168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // You will note that CALL_STATE_WAITING, CALL_STATE_HELD, and CALL_STATE_ACTIVE are not
83268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // used in this version of the call state mappings.  This is on purpose.
83368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // phone_state_change() in btif_hf.c is not written to handle these states. Only with the
83468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // listCalls*() method are WAITING and ACTIVE used.
83568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // Using the unsupported states here caused problems with inconsistent state in some
83668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        // bluetooth devices (like not getting out of ringing state after answering a call).
83768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        //
83868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        int bluetoothCallState = CALL_STATE_IDLE;
83968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (ringingCall != null) {
84068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            bluetoothCallState = CALL_STATE_INCOMING;
84105a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen        } else if (dialingCall != null) {
84268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            bluetoothCallState = CALL_STATE_ALERTING;
843b3ccbb31fc30056ba45559659391313c27605cabHonggang        } else if (hasOnlyDisconnectedCalls || mIsDisconnectedTonePlaying) {
844b3ccbb31fc30056ba45559659391313c27605cabHonggang            // Keep the DISCONNECTED state until the disconnect tone's playback is done
845b3ccbb31fc30056ba45559659391313c27605cabHonggang            bluetoothCallState = CALL_STATE_DISCONNECTED;
84668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
84768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        return bluetoothCallState;
84868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
84968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
85033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    private int convertCallState(int callState, boolean isForegroundCall) {
85133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        switch (callState) {
85233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.NEW:
85333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.ABORTED:
85433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.DISCONNECTED:
85533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                return CALL_STATE_IDLE;
85633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
85733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.ACTIVE:
85833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                return CALL_STATE_ACTIVE;
85933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
860d9f9006eafb1751f1b4ae1aa0954d445aa03fd3cSantos Cordon            case CallState.CONNECTING:
861d9f9006eafb1751f1b4ae1aa0954d445aa03fd3cSantos Cordon            case CallState.SELECT_PHONE_ACCOUNT:
86233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.DIALING:
8631e37be5dd86a51b90e461f09dc8a89effe4aee21Tyler Gunn            case CallState.PULLING:
86433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // Yes, this is correctly returning ALERTING.
86533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // "Dialing" for BT means that we have sent information to the service provider
86633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // to place the call but there is no confirmation that the call is going through.
86733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // When there finally is confirmation, the ringback is played which is referred to
86833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // as an "alert" tone, thus, ALERTING.
86933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // TODO: We should consider using the ALERTING terms in Telecom because that
87033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                // seems to be more industry-standard.
87133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                return CALL_STATE_ALERTING;
87233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
87333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.ON_HOLD:
87433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                return CALL_STATE_HELD;
87533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
87633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon            case CallState.RINGING:
87733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                if (isForegroundCall) {
87833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                    return CALL_STATE_INCOMING;
87933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                } else {
88033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                    return CALL_STATE_WAITING;
88133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon                }
88233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        }
88333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon        return CALL_STATE_IDLE;
88433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon    }
88533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon
88668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    /**
88768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * Returns the best phone account to use for the given state of all calls.
88868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * First, tries to return the phone account for the foreground call, second the default
88968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     * phone account for PhoneAccount.SCHEME_TEL.
89068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon     */
89168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    private PhoneAccount getBestPhoneAccount() {
89278a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        if (mPhoneAccountRegistrar == null) {
8930b5cb4d0036a45725d4a3250fe8475599a31a202Santos Cordon            return null;
8940b5cb4d0036a45725d4a3250fe8475599a31a202Santos Cordon        }
8950b5cb4d0036a45725d4a3250fe8475599a31a202Santos Cordon
89678a5e6b9c1595c81f72d7a822617cb78db224e48Ihab Awad        Call call = mCallsManager.getForegroundCall();
89768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
89868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        PhoneAccount account = null;
89968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (call != null) {
90068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            // First try to get the network name of the foreground call.
901240656f19c078b4f703d0502ce29114de0d45a50Tony Mak            account = mPhoneAccountRegistrar.getPhoneAccountOfCurrentUser(
9026a2126477ce3f527ecaec807fe4f40cd13ff02b0Santos Cordon                    call.getTargetPhoneAccount());
90368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
90468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon
90568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        if (account == null) {
90668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon            // Second, Try to get the label for the default Phone Account.
907240656f19c078b4f703d0502ce29114de0d45a50Tony Mak            account = mPhoneAccountRegistrar.getPhoneAccountUnchecked(
908240656f19c078b4f703d0502ce29114de0d45a50Tony Mak                    mPhoneAccountRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(
9095385513ae43b4d5896245bf076a83b27dbf32a25Brad Ebinger                            PhoneAccount.SCHEME_TEL));
91068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        }
91168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon        return account;
91268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon    }
91368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon}
914