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