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.app.Service; 2068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothAdapter; 2168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothHeadset; 2268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.BluetoothProfile; 2368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.bluetooth.IBluetoothHeadsetPhone; 2468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.BroadcastReceiver; 2568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.Context; 2668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.Intent; 2768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.content.IntentFilter; 2868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.net.Uri; 2968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.Handler; 3068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.IBinder; 3168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.Message; 3268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.os.RemoteException; 3333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordonimport android.telecom.CallState; 3468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telecom.PhoneAccount; 3588a4a60284de8e1222488667b810b098c16d22acSantos Cordonimport android.telecom.PhoneCapabilities; 3668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telephony.PhoneNumberUtils; 3768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.telephony.TelephonyManager; 3868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonimport android.text.TextUtils; 3968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 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 */ 5168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordonpublic final class BluetoothPhoneService extends Service { 5268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 5368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Request object for performing synchronous requests to the main thread. 5468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 5568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static class MainThreadRequest { 5668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Object result; 5768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon int param; 5868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 5968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon MainThreadRequest(int param) { 6068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon this.param = param; 6168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 6268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 6368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon void setResult(Object value) { 6468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon result = value; 6568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon synchronized (this) { 6668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon notifyAll(); 6768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 6868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 6968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 7068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 7168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final String TAG = "BluetoothPhoneService"; 7268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 7368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_ANSWER_CALL = 1; 7468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_HANGUP_CALL = 2; 7568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_SEND_DTMF = 3; 7668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_PROCESS_CHLD = 4; 7768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_GET_NETWORK_OPERATOR = 5; 7868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_LIST_CURRENT_CALLS = 6; 7968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_QUERY_PHONE_STATE = 7; 8068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int MSG_GET_SUBSCRIBER_NUMBER = 8; 8168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 8268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // match up with bthf_call_state_t of bt_hf.h 8368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_ACTIVE = 0; 8468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_HELD = 1; 8568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_DIALING = 2; 8668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_ALERTING = 3; 8768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_INCOMING = 4; 8868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_WAITING = 5; 8968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CALL_STATE_IDLE = 6; 9068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 9168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // match up with bthf_call_state_t of bt_hf.h 9268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Terminate all held or set UDUB("busy") to a waiting call 9368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CHLD_TYPE_RELEASEHELD = 0; 9468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Terminate all active calls and accepts a waiting/held call 9568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1; 9668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Hold all active calls and accepts a waiting/held call 9768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2; 9868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Add all held calls to a conference 9968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private static final int CHLD_TYPE_ADDHELDTOCONF = 3; 10068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 101a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon private int mNumActiveCalls = 0; 102a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon private int mNumHeldCalls = 0; 103a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon private int mBluetoothCallState = CALL_STATE_IDLE; 104a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon private String mRingingAddress = null; 105a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon private int mRingingAddressType = 0; 106dfe06f1dbb7c13497f5033a3fa215b8a1a0cd517Santos Cordon private Call mOldHeldCall = null; 107a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon 10868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 10968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Binder implementation of IBluetoothHeadsetPhone. Implements the command interface that the 11068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * bluetooth headset code uses to control call. 11168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 11268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private final IBluetoothHeadsetPhone.Stub mBinder = new IBluetoothHeadsetPhone.Stub() { 11368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 11468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean answerCall() throws RemoteException { 11568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 11668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "BT - answering call"); 11768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_ANSWER_CALL); 11868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 11968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 12068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 12168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean hangupCall() throws RemoteException { 12268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 12368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "BT - hanging up call"); 12468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_HANGUP_CALL); 12568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 12668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 12768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 12868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean sendDtmf(int dtmf) throws RemoteException { 12968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 13068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "BT - sendDtmf %c", Log.DEBUG ? dtmf : '.'); 13168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_SEND_DTMF, dtmf); 13268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 13368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 13468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 13568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public String getNetworkOperator() throws RemoteException { 13668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "getNetworkOperator"); 13768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 13868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_GET_NETWORK_OPERATOR); 13968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 14068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 14168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 14268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public String getSubscriberNumber() throws RemoteException { 14368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "getSubscriberNumber"); 14468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 14568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_GET_SUBSCRIBER_NUMBER); 14668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 14768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 14868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 14968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean listCurrentCalls() throws RemoteException { 15088a4a60284de8e1222488667b810b098c16d22acSantos Cordon // only log if it is after we recently updated the headset state or else it can clog 15188a4a60284de8e1222488667b810b098c16d22acSantos Cordon // the android log since this can be queried every second. 15288a4a60284de8e1222488667b810b098c16d22acSantos Cordon boolean logQuery = mHeadsetUpdatedRecently; 15388a4a60284de8e1222488667b810b098c16d22acSantos Cordon mHeadsetUpdatedRecently = false; 15488a4a60284de8e1222488667b810b098c16d22acSantos Cordon 15588a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (logQuery) { 15688a4a60284de8e1222488667b810b098c16d22acSantos Cordon Log.i(TAG, "listcurrentCalls"); 15788a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 15868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 15988a4a60284de8e1222488667b810b098c16d22acSantos Cordon return sendSynchronousRequest(MSG_LIST_CURRENT_CALLS, logQuery ? 1 : 0); 16068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 16168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 16268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 16368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean queryPhoneState() throws RemoteException { 16468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "queryPhoneState"); 16568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 16668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_QUERY_PHONE_STATE); 16768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 16868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 16968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 17068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public boolean processChld(int chld) throws RemoteException { 17168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.i(TAG, "processChld %d", chld); 17268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceModifyPermission(); 17368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(MSG_PROCESS_CHLD, chld); 17468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 17568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 17668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 17768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void updateBtHandsfreeAfterRadioTechnologyChange() throws RemoteException { 17868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "RAT change"); 17968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // deprecated 18068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 18168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 18268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 18368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void cdmaSetSecondCallState(boolean state) throws RemoteException { 18468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "cdma 1"); 18568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // deprecated 18668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 18768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 18868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 18968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void cdmaSwapSecondCallState() throws RemoteException { 19068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "cdma 2"); 19168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // deprecated 19268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 19368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon }; 19468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 19568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 19668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Main-thread handler for BT commands. Since telecom logic runs on a single thread, commands 19768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * that are sent to it from the headset need to be moved over to the main thread before 19868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * executing. This handler exists for that reason. 19968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 20068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private final Handler mHandler = new Handler() { 20168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 20268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void handleMessage(Message msg) { 20368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon MainThreadRequest request = msg.obj instanceof MainThreadRequest ? 20468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon (MainThreadRequest) msg.obj : null; 20568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager callsManager = getCallsManager(); 20668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call call = null; 20768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 20868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "handleMessage(%d) w/ param %s", 20968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon msg.what, request == null ? null : request.param); 21068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 21168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon switch (msg.what) { 21268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_ANSWER_CALL: 21368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 21468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon call = callsManager.getRingingCall(); 21568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (call != null) { 21668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon getCallsManager().answerCall(call, 0); 21768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 21868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 21968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(call != null); 22068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 22168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 22268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 22368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_HANGUP_CALL: 22468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 22568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon call = callsManager.getForegroundCall(); 22668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (call != null) { 22768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.disconnectCall(call); 22868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 22968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 23068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(call != null); 23168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 23268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 23368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 23468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_SEND_DTMF: 23568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 23668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon call = callsManager.getForegroundCall(); 23768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (call != null) { 23868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // TODO: Consider making this a queue instead of starting/stopping 23968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // in quick succession. 24068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.playDtmfTone(call, (char) request.param); 24168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.stopDtmfTone(call); 24268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 24368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 24468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(call != null); 24568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 24668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 24768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 24868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_PROCESS_CHLD: 24968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Boolean result = false; 25068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 25168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon result = processChld(request.param); 25268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 25368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(result); 25468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 25568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 25668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 25768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_GET_SUBSCRIBER_NUMBER: 25868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon String address = null; 25968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 26068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon PhoneAccount account = getBestPhoneAccount(); 26168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (account != null) { 26268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Uri addressUri = account.getAddress(); 26368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (addressUri != null) { 26468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon address = addressUri.getSchemeSpecificPart(); 26568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 26668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 26768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 26868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (TextUtils.isEmpty(address)) { 26968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon address = TelephonyManager.from(BluetoothPhoneService.this) 27068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon .getLine1Number(); 27168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 27268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 27368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(address); 27468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 27568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 27668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 27768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_GET_NETWORK_OPERATOR: 27868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon String label = null; 27968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 28068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon PhoneAccount account = getBestPhoneAccount(); 28168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (account != null) { 28268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon label = account.getLabel().toString(); 28368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else { 28468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Finally, just get the network name from telephony. 28568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon label = TelephonyManager.from(BluetoothPhoneService.this) 28668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon .getNetworkOperatorName(); 28768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 28868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 28968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(label); 29068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 29168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 29268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 29368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_LIST_CURRENT_CALLS: 29433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon try { 29588a4a60284de8e1222488667b810b098c16d22acSantos Cordon sendListOfCalls(request.param == 1); 29633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } finally { 29733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon request.setResult(true); 29833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 29968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 30068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 30168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon case MSG_QUERY_PHONE_STATE: 30268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 303cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(true /* force */); 30468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } finally { 30568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (request != null) { 30668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.setResult(true); 30768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 30868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 30968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon break; 31068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 31168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 31268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon }; 31368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 31468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 31568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Listens to call changes from the CallsManager and calls into methods to update the bluetooth 31668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * headset with the new states. 31768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 31868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private CallsManagerListener mCallsManagerListener = new CallsManagerListenerBase() { 31968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 32068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onCallAdded(Call call) { 321cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(false /* force */); 32268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 32368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 32468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 32568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onCallRemoved(Call call) { 32633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon mClccIndexMap.remove(call); 327cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(false /* force */); 32868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 32968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 33068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 33168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onCallStateChanged(Call call, int oldState, int newState) { 332df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // If a call is being put on hold because of a new connecting call, ignore the 333df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // CONNECTING since the BT state update needs to send out the numHeld = 1 + dialing 334df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // state atomically. 335df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // When the call later transitions to DIALING/DISCONNECTED we will then send out the 336df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // aggregated update. 337df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (oldState == CallState.ACTIVE && newState == CallState.ON_HOLD) { 338df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee for (Call otherCall : CallsManager.getInstance().getCalls()) { 339df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (otherCall.getState() == CallState.CONNECTING) { 340df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee return; 341df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 342df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 343df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 344df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee 345df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // To have an active call and another dialing at the same time is an invalid BT 346df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // state. We can assume that the active call will be automatically held which will 347df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // send another update at which point we will be in the right state. 348df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (CallsManager.getInstance().getActiveCall() != null 349df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee && oldState == CallState.CONNECTING && newState == CallState.DIALING) { 350df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee return; 351df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 352cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(false /* force */); 35368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 35468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 35568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 35668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onForegroundCallChanged(Call oldForegroundCall, Call newForegroundCall) { 357df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // The BluetoothPhoneService does not need to respond to changes in foreground calls, 358df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // which are always accompanied by call state changes anyway. 35968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 36068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 36168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 36268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onIsConferencedChanged(Call call) { 363df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee /* 364df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * Filter certain onIsConferencedChanged callbacks. Unfortunately this needs to be done 365df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * because conference change events are not atomic and multiple callbacks get fired 366df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * when two calls are conferenced together. This confuses updateHeadsetWithCallState 367df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * if it runs in the middle of two calls being conferenced and can cause spurious and 368df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * incorrect headset state updates. One of the scenarios is described below for CDMA 369df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * conference calls. 370df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * 371df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * 1) Call 1 and Call 2 are being merged into conference Call 3. 372df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * 2) Call 1 has its parent set to Call 3, but Call 2 does not have a parent yet. 373df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * 3) updateHeadsetWithCallState now thinks that there are two active calls (Call 2 and 374df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee * Call 3) when there is actually only one active call (Call 3). 375df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee */ 376df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (call.getParentCall() != null) { 377df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // If this call is newly conferenced, ignore the callback. We only care about the 378df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // one sent for the parent conference call. 379df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee Log.d(this, "Ignoring onIsConferenceChanged from child call with new parent"); 380df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee return; 381df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 382df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (call.getChildCalls().size() == 1) { 383df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // If this is a parent call with only one child, ignore the callback as well since 384df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // the minimum number of child calls to start a conference call is 2. We expect 385df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // this to be called again when the parent call has another child call added. 386df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee Log.d(this, "Ignoring onIsConferenceChanged from parent with only one child call"); 387df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee return; 388df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 389cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(false /* force */); 39068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 39168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon }; 39268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 39368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 39468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Listens to connections and disconnections of bluetooth headsets. We need to save the current 39568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * bluetooth headset so that we know where to send call updates. 39668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 39768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private BluetoothProfile.ServiceListener mProfileListener = 39868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon new BluetoothProfile.ServiceListener() { 39968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 40068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onServiceConnected(int profile, BluetoothProfile proxy) { 40168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mBluetoothHeadset = (BluetoothHeadset) proxy; 40268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 40368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 40468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 40568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onServiceDisconnected(int profile) { 40668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mBluetoothHeadset = null; 40768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 40868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon }; 40968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 41068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 41168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Receives events for global state changes of the bluetooth adapter. 41268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 41368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private final BroadcastReceiver mBluetoothAdapterReceiver = new BroadcastReceiver() { 41468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 41568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onReceive(Context context, Intent intent) { 41668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 41768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "Bluetooth Adapter state: %d", state); 41868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (state == BluetoothAdapter.STATE_ON) { 41968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mHandler.sendEmptyMessage(MSG_QUERY_PHONE_STATE); 42068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 42168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 42268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon }; 42368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 42468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private BluetoothAdapter mBluetoothAdapter; 42568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private BluetoothHeadset mBluetoothHeadset; 42668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 42733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls). 42833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon private Map<Call, Integer> mClccIndexMap = new HashMap<>(); 42933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 43088a4a60284de8e1222488667b810b098c16d22acSantos Cordon private boolean mHeadsetUpdatedRecently = false; 43188a4a60284de8e1222488667b810b098c16d22acSantos Cordon 43268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public BluetoothPhoneService() { 43368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.v(TAG, "Constructor"); 43468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 43568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 43668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public static final void start(Context context) { 43768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (BluetoothAdapter.getDefaultAdapter() != null) { 43868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon context.startService(new Intent(context, BluetoothPhoneService.class)); 43968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 44068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 44168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 44268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 44368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public IBinder onBind(Intent intent) { 44468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "Binding service"); 44568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return mBinder; 44668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 44768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 44868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 44968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onCreate() { 45068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "onCreate"); 45168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 45268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 45368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (mBluetoothAdapter == null) { 45468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "BluetoothPhoneService shutting down, no BT Adapter found."); 45568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return; 45668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 45768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mBluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET); 45868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 45968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 46068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon registerReceiver(mBluetoothAdapterReceiver, intentFilter); 46168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 46268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager.getInstance().addListener(mCallsManagerListener); 463cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn updateHeadsetWithCallState(false /* force */); 46468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 46568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 46668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @Override 46768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon public void onDestroy() { 46868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Log.d(TAG, "onDestroy"); 46968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager.getInstance().removeListener(mCallsManagerListener); 47068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon super.onDestroy(); 47168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 47268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 47368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private boolean processChld(int chld) { 47468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager callsManager = CallsManager.getInstance(); 47568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call activeCall = callsManager.getActiveCall(); 47668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call ringingCall = callsManager.getRingingCall(); 47768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call heldCall = callsManager.getHeldCall(); 47868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 47966fe882a6437de1010af0dc8cd7350f81f2e028aSantos Cordon // TODO: Keeping as Log.i for now. Move to Log.d after L release if BT proves stable. 48066fe882a6437de1010af0dc8cd7350f81f2e028aSantos Cordon Log.i(TAG, "Active: %s\nRinging: %s\nHeld: %s", activeCall, ringingCall, heldCall); 48188a4a60284de8e1222488667b810b098c16d22acSantos Cordon 48268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (chld == CHLD_TYPE_RELEASEHELD) { 48368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingCall != null) { 48468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.rejectCall(ringingCall, false, null); 48568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 48668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (heldCall != null) { 48768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.disconnectCall(heldCall); 48868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 48968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 49068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) { 49168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (activeCall != null) { 49268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.disconnectCall(activeCall); 49368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingCall != null) { 49468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.answerCall(ringingCall, 0); 49568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (heldCall != null) { 49668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.unholdCall(heldCall); 49768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 49868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 49968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 50068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) { 50188a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (activeCall != null && activeCall.can(PhoneCapabilities.SWAP_CONFERENCE)) { 50288a4a60284de8e1222488667b810b098c16d22acSantos Cordon activeCall.swapConference(); 50388a4a60284de8e1222488667b810b098c16d22acSantos Cordon return true; 50488a4a60284de8e1222488667b810b098c16d22acSantos Cordon } else if (ringingCall != null) { 50568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.answerCall(ringingCall, 0); 50668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 50768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (heldCall != null) { 50868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // CallsManager will hold any active calls when unhold() is called on a 50968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // currently-held call. 51068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.unholdCall(heldCall); 51168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 51288a4a60284de8e1222488667b810b098c16d22acSantos Cordon } else if (activeCall != null && activeCall.can(PhoneCapabilities.HOLD)) { 51368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon callsManager.holdCall(activeCall); 51468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 51568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 51668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } else if (chld == CHLD_TYPE_ADDHELDTOCONF) { 51768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (activeCall != null) { 51866fe882a6437de1010af0dc8cd7350f81f2e028aSantos Cordon if (activeCall.can(PhoneCapabilities.MERGE_CONFERENCE)) { 51988a4a60284de8e1222488667b810b098c16d22acSantos Cordon activeCall.mergeConference(); 52068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return true; 52188a4a60284de8e1222488667b810b098c16d22acSantos Cordon } else { 52288a4a60284de8e1222488667b810b098c16d22acSantos Cordon List<Call> conferenceable = activeCall.getConferenceableCalls(); 52388a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (!conferenceable.isEmpty()) { 52488a4a60284de8e1222488667b810b098c16d22acSantos Cordon callsManager.conference(activeCall, conferenceable.get(0)); 52588a4a60284de8e1222488667b810b098c16d22acSantos Cordon return true; 52688a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 52768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 52868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 52968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 53068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return false; 53168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 53268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 53368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private void enforceModifyPermission() { 53468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null); 53568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 53668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 53768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private <T> T sendSynchronousRequest(int message) { 53868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return sendSynchronousRequest(message, 0); 53968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 54068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 54168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private <T> T sendSynchronousRequest(int message, int param) { 54268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon MainThreadRequest request = new MainThreadRequest(param); 54368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mHandler.obtainMessage(message, request).sendToTarget(); 54468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon synchronized (request) { 54568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon while (request.result == null) { 54668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon try { 54768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon request.wait(); 54868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } catch (InterruptedException e) { 54968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Do nothing, go back and wait until the request is complete. 55068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 55168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 55268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 55368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (request.result != null) { 55468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon @SuppressWarnings("unchecked") 55568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon T retval = (T) request.result; 55668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return retval; 55768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 55868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return null; 55968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 56068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 56188a4a60284de8e1222488667b810b098c16d22acSantos Cordon private void sendListOfCalls(boolean shouldLog) { 56233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon Collection<Call> mCalls = getCallsManager().getCalls(); 56333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon for (Call call : mCalls) { 56433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // We don't send the parent conference call to the bluetooth device. 56533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon if (!call.isConference()) { 56688a4a60284de8e1222488667b810b098c16d22acSantos Cordon sendClccForCall(call, shouldLog); 56733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 56833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 56933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon sendClccEndMarker(); 57033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 57133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 57233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon /** 57333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon * Sends a single clcc (C* List Current Calls) event for the specified call. 57433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon */ 57588a4a60284de8e1222488667b810b098c16d22acSantos Cordon private void sendClccForCall(Call call, boolean shouldLog) { 57633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon boolean isForeground = getCallsManager().getForegroundCall() == call; 57733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon int state = convertCallState(call.getState(), isForeground); 57888a4a60284de8e1222488667b810b098c16d22acSantos Cordon boolean isPartOfConference = false; 57905a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen 58005a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen if (state == CALL_STATE_IDLE) { 58105a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen return; 58205a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen } 58305a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen 58488a4a60284de8e1222488667b810b098c16d22acSantos Cordon Call conferenceCall = call.getParentCall(); 58588a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (conferenceCall != null) { 58688a4a60284de8e1222488667b810b098c16d22acSantos Cordon isPartOfConference = true; 58788a4a60284de8e1222488667b810b098c16d22acSantos Cordon 58888a4a60284de8e1222488667b810b098c16d22acSantos Cordon // Run some alternative states for Conference-level merge/swap support. 58988a4a60284de8e1222488667b810b098c16d22acSantos Cordon // Basically, if call supports swapping or merging at the conference-level, then we need 59088a4a60284de8e1222488667b810b098c16d22acSantos Cordon // to expose the calls as having distinct states (ACTIVE vs HOLD) or the functionality 59188a4a60284de8e1222488667b810b098c16d22acSantos Cordon // won't show up on the bluetooth device. 59288a4a60284de8e1222488667b810b098c16d22acSantos Cordon 59388a4a60284de8e1222488667b810b098c16d22acSantos Cordon // Before doing any special logic, ensure that we are dealing with an ACTIVE call and 59488a4a60284de8e1222488667b810b098c16d22acSantos Cordon // that the conference itself has a notion of the current "active" child call. 59588a4a60284de8e1222488667b810b098c16d22acSantos Cordon Call activeChild = conferenceCall.getConferenceLevelActiveCall(); 59688a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (state == CALL_STATE_ACTIVE && activeChild != null) { 59788a4a60284de8e1222488667b810b098c16d22acSantos Cordon // Reevaluate state if we can MERGE or if we can SWAP without previously having 59888a4a60284de8e1222488667b810b098c16d22acSantos Cordon // MERGED. 59988a4a60284de8e1222488667b810b098c16d22acSantos Cordon boolean shouldReevaluateState = 60088a4a60284de8e1222488667b810b098c16d22acSantos Cordon conferenceCall.can(PhoneCapabilities.MERGE_CONFERENCE) || 60188a4a60284de8e1222488667b810b098c16d22acSantos Cordon (conferenceCall.can(PhoneCapabilities.SWAP_CONFERENCE) && 60288a4a60284de8e1222488667b810b098c16d22acSantos Cordon !conferenceCall.wasConferencePreviouslyMerged()); 60388a4a60284de8e1222488667b810b098c16d22acSantos Cordon 60488a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (shouldReevaluateState) { 60588a4a60284de8e1222488667b810b098c16d22acSantos Cordon isPartOfConference = false; 60688a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (call == activeChild) { 60788a4a60284de8e1222488667b810b098c16d22acSantos Cordon state = CALL_STATE_ACTIVE; 60888a4a60284de8e1222488667b810b098c16d22acSantos Cordon } else { 60988a4a60284de8e1222488667b810b098c16d22acSantos Cordon // At this point we know there is an "active" child and we know that it is 61088a4a60284de8e1222488667b810b098c16d22acSantos Cordon // not this call, so set it to HELD instead. 61188a4a60284de8e1222488667b810b098c16d22acSantos Cordon state = CALL_STATE_HELD; 61288a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 61388a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 61488a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 61588a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 61688a4a60284de8e1222488667b810b098c16d22acSantos Cordon 61705a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen int index = getIndexForCall(call); 61805a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen int direction = call.isIncoming() ? 1 : 0; 619fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee final Uri addressUri; 620fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee if (call.getGatewayInfo() != null) { 621fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee addressUri = call.getGatewayInfo().getOriginalAddress(); 622fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee } else { 623fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee addressUri = call.getHandle(); 624fb70e1efbcf173a995e9bb9b312713f8f554e307Yorke Lee } 62533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon String address = addressUri == null ? null : addressUri.getSchemeSpecificPart(); 62633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); 62733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 62888a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (shouldLog) { 62988a4a60284de8e1222488667b810b098c16d22acSantos Cordon Log.i(this, "sending clcc for call %d, %d, %d, %b, %s, %d", 63088a4a60284de8e1222488667b810b098c16d22acSantos Cordon index, direction, state, isPartOfConference, Log.piiHandle(address), 63188a4a60284de8e1222488667b810b098c16d22acSantos Cordon addressType); 63288a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 633e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee 634e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee if (mBluetoothHeadset != null) { 635e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee mBluetoothHeadset.clccResponse( 636e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee index, direction, state, 0, isPartOfConference, address, addressType); 637e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee } 63833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 63933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 64033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon private void sendClccEndMarker() { 64133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // End marker is recognized with an index value of 0. All other parameters are ignored. 642e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee if (mBluetoothHeadset != null) { 643e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee mBluetoothHeadset.clccResponse(0 /* index */, 0, 0, 0, false, null, 0); 644e241cd6f340fedb82e1aa76d35bbcbca31fe423cYorke Lee } 64533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 64633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 64733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon /** 64833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon * Returns the caches index for the specified call. If no such index exists, then an index is 64933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon * given (smallest number starting from 1 that isn't already taken). 65033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon */ 65133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon private int getIndexForCall(Call call) { 65233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon if (mClccIndexMap.containsKey(call)) { 65333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return mClccIndexMap.get(call); 65433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 65533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 65633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon int i = 1; // Indexes for bluetooth clcc are 1-based. 65733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon while (mClccIndexMap.containsValue(i)) { 65833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon i++; 65933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 66033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 66133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // NOTE: Indexes are removed in {@link #onCallRemoved}. 66233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon mClccIndexMap.put(call, i); 66333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return i; 66433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 66533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 666cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn /** 667cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn * Sends an update of the current call state to the current Headset. 668cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn * 669cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn * @param force {@code true} if the headset state should be sent regardless if no changes to the 670cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn * state have occurred, {@code false} if the state should only be sent if the state has 671cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn * changed. 672cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn */ 673cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn private void updateHeadsetWithCallState(boolean force) { 67468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager callsManager = getCallsManager(); 67568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call activeCall = callsManager.getActiveCall(); 67668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call ringingCall = callsManager.getRingingCall(); 67768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call heldCall = callsManager.getHeldCall(); 67868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 67968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon int bluetoothCallState = getBluetoothCallStateForUpdate(); 68068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 68168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon String ringingAddress = null; 68268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon int ringingAddressType = 128; 68368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingCall != null) { 68468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon ringingAddress = ringingCall.getHandle().getSchemeSpecificPart(); 68568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingAddress != null) { 68668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon ringingAddressType = PhoneNumberUtils.toaFromString(ringingAddress); 68768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 68868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 68968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingAddress == null) { 69068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon ringingAddress = ""; 69168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 69268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 693a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon int numActiveCalls = activeCall == null ? 0 : 1; 694dfe06f1dbb7c13497f5033a3fa215b8a1a0cd517Santos Cordon int numHeldCalls = callsManager.getNumHeldCalls(); 695a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon 69688a4a60284de8e1222488667b810b098c16d22acSantos Cordon // For conference calls which support swapping the active call within the conference 69788a4a60284de8e1222488667b810b098c16d22acSantos Cordon // (namely CDMA calls) we need to expose that as a held call in order for the BT device 69888a4a60284de8e1222488667b810b098c16d22acSantos Cordon // to show "swap" and "merge" functionality. 699df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee boolean ignoreHeldCallChange = false; 70088a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (activeCall != null && activeCall.isConference()) { 70188a4a60284de8e1222488667b810b098c16d22acSantos Cordon if (activeCall.can(PhoneCapabilities.SWAP_CONFERENCE)) { 70288a4a60284de8e1222488667b810b098c16d22acSantos Cordon // Indicate that BT device should show SWAP command by indicating that there is a 70388a4a60284de8e1222488667b810b098c16d22acSantos Cordon // call on hold, but only if the conference wasn't previously merged. 70488a4a60284de8e1222488667b810b098c16d22acSantos Cordon numHeldCalls = activeCall.wasConferencePreviouslyMerged() ? 0 : 1; 70588a4a60284de8e1222488667b810b098c16d22acSantos Cordon } else if (activeCall.can(PhoneCapabilities.MERGE_CONFERENCE)) { 70688a4a60284de8e1222488667b810b098c16d22acSantos Cordon numHeldCalls = 1; // Merge is available, so expose via numHeldCalls. 70788a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 708df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee 709df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee for (Call childCall : activeCall.getChildCalls()) { 710df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // Held call has changed due to it being combined into a CDMA conference. Keep 711df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // track of this and ignore any future update since it doesn't really count as 712df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // a call change. 713df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee if (mOldHeldCall == childCall) { 714df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee ignoreHeldCallChange = true; 715df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee break; 716df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 717df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee } 71888a4a60284de8e1222488667b810b098c16d22acSantos Cordon } 71988a4a60284de8e1222488667b810b098c16d22acSantos Cordon 720a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon if (mBluetoothHeadset != null && 721a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon (numActiveCalls != mNumActiveCalls || 722a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon numHeldCalls != mNumHeldCalls || 723a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon bluetoothCallState != mBluetoothCallState || 724a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon !TextUtils.equals(ringingAddress, mRingingAddress) || 725cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn ringingAddressType != mRingingAddressType || 726df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee (heldCall != mOldHeldCall && !ignoreHeldCallChange) || 727cd685e56453b2e1feb118b560a1caa1ef40039d6Tyler Gunn force)) { 728a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon 729a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon // If the call is transitioning into the alerting state, send DIALING first. 730a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon // Some devices expect to see a DIALING state prior to seeing an ALERTING state 731a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon // so we need to send it first. 732a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon boolean sendDialingFirst = mBluetoothCallState != bluetoothCallState && 733a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon bluetoothCallState == CALL_STATE_ALERTING; 734a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon 735dfe06f1dbb7c13497f5033a3fa215b8a1a0cd517Santos Cordon mOldHeldCall = heldCall; 736a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumActiveCalls = numActiveCalls; 737a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumHeldCalls = numHeldCalls; 738a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mBluetoothCallState = bluetoothCallState; 739a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddress = ringingAddress; 740a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddressType = ringingAddressType; 741a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon 742a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon if (sendDialingFirst) { 743df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee // Log in full to make logs easier to debug. 744df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee Log.i(TAG, "updateHeadsetWithCallState " + 745df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee "numActive %s, " + 746df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee "numHeld %s, " + 747df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee "callState %s, " + 748df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee "ringing number %s, " + 749df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee "ringing type %s", 750df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee mNumActiveCalls, 751df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee mNumHeldCalls, 752df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee CALL_STATE_DIALING, 753df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee Log.pii(mRingingAddress), 754df441ed20bec7f2ebe319afc57f52df5f3996920Yorke Lee mRingingAddressType); 755a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mBluetoothHeadset.phoneStateChanged( 756a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumActiveCalls, 757a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumHeldCalls, 758a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon CALL_STATE_DIALING, 759a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddress, 760a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddressType); 761a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon } 76268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 763a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon Log.i(TAG, "updateHeadsetWithCallState " + 764a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon "numActive %s, " + 765a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon "numHeld %s, " + 766a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon "callState %s, " + 767a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon "ringing number %s, " + 768a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon "ringing type %s", 769a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumActiveCalls, 770a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumHeldCalls, 771a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mBluetoothCallState, 772a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon Log.pii(mRingingAddress), 773a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddressType); 77468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 77568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon mBluetoothHeadset.phoneStateChanged( 776a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumActiveCalls, 777a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mNumHeldCalls, 778a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mBluetoothCallState, 779a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddress, 780a0b4612909c6046315a11072d245e4ff0b9e784eSantos Cordon mRingingAddressType); 78188a4a60284de8e1222488667b810b098c16d22acSantos Cordon 78288a4a60284de8e1222488667b810b098c16d22acSantos Cordon mHeadsetUpdatedRecently = true; 78368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 78468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 78568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 78668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private int getBluetoothCallStateForUpdate() { 78768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon CallsManager callsManager = getCallsManager(); 78868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call ringingCall = callsManager.getRingingCall(); 78905a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen Call dialingCall = callsManager.getDialingCall(); 79068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 79168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // 79268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // !! WARNING !! 79368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // You will note that CALL_STATE_WAITING, CALL_STATE_HELD, and CALL_STATE_ACTIVE are not 79468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // used in this version of the call state mappings. This is on purpose. 79568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // phone_state_change() in btif_hf.c is not written to handle these states. Only with the 79668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // listCalls*() method are WAITING and ACTIVE used. 79768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Using the unsupported states here caused problems with inconsistent state in some 79868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // bluetooth devices (like not getting out of ringing state after answering a call). 79968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // 80068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon int bluetoothCallState = CALL_STATE_IDLE; 80168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (ringingCall != null) { 80268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon bluetoothCallState = CALL_STATE_INCOMING; 80305a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen } else if (dialingCall != null) { 80468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon bluetoothCallState = CALL_STATE_ALERTING; 80568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 80668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return bluetoothCallState; 80768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 80868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 80933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon private int convertCallState(int callState, boolean isForegroundCall) { 81033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon switch (callState) { 81133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.NEW: 81233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.ABORTED: 81333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.DISCONNECTED: 81405a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen case CallState.CONNECTING: 81505a9e40ba1edc7b4597163f73503e2e92b746208Nancy Chen case CallState.PRE_DIAL_WAIT: 81633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_IDLE; 81733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 81833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.ACTIVE: 81933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_ACTIVE; 82033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 82133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.DIALING: 82233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // Yes, this is correctly returning ALERTING. 82333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // "Dialing" for BT means that we have sent information to the service provider 82433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // to place the call but there is no confirmation that the call is going through. 82533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // When there finally is confirmation, the ringback is played which is referred to 82633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // as an "alert" tone, thus, ALERTING. 82733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // TODO: We should consider using the ALERTING terms in Telecom because that 82833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon // seems to be more industry-standard. 82933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_ALERTING; 83033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 83133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.ON_HOLD: 83233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_HELD; 83333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 83433fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon case CallState.RINGING: 83533fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon if (isForegroundCall) { 83633fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_INCOMING; 83733fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } else { 83833fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_WAITING; 83933fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 84033fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 84133fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon return CALL_STATE_IDLE; 84233fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon } 84333fff4905fb4e977cb982fbc89d5d0c52a92b55cSantos Cordon 84468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private CallsManager getCallsManager() { 84568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return CallsManager.getInstance(); 84668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 84768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 84868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon /** 84968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * Returns the best phone account to use for the given state of all calls. 85068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * First, tries to return the phone account for the foreground call, second the default 85168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon * phone account for PhoneAccount.SCHEME_TEL. 85268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon */ 85368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon private PhoneAccount getBestPhoneAccount() { 85468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon TelecomApp app = (TelecomApp) getApplication(); 85568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon PhoneAccountRegistrar registry = app.getPhoneAccountRegistrar(); 85668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon Call call = getCallsManager().getForegroundCall(); 85768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 85868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon PhoneAccount account = null; 85968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (call != null) { 86068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // First try to get the network name of the foreground call. 86168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon account = registry.getPhoneAccount(call.getTargetPhoneAccount()); 86268d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 86368d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon 86468d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon if (account == null) { 86568d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon // Second, Try to get the label for the default Phone Account. 86668d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon account = registry.getPhoneAccount( 86768d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon registry.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL)); 86868d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 86968d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon return account; 87068d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon } 87168d1a6b0bd8840b74c61a94928610312c09b0486Santos Cordon} 872