13d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer/* 23d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Copyright (C) 2015 The Android Open Source Project 33d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 43d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Licensed under the Apache License, Version 2.0 (the "License"); 53d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * you may not use this file except in compliance with the License. 63d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * You may obtain a copy of the License at 73d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 83d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * http://www.apache.org/licenses/LICENSE-2.0 93d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * 103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Unless required by applicable law or agreed to in writing, software 113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * distributed under the License is distributed on an "AS IS" BASIS, 123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * See the License for the specific language governing permissions and 143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * limitations under the License. 153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerpackage com.android.car.dialer.telecom; 173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 18684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.bluetooth.BluetoothAdapter; 19684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.bluetooth.BluetoothDevice; 20684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.bluetooth.BluetoothHeadsetClient; 21684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.bluetooth.BluetoothHeadsetClientCall; 22684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.bluetooth.BluetoothProfile; 236ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.content.ComponentName; 243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.content.Context; 256ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.content.Intent; 266ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.content.ServiceConnection; 273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.database.Cursor; 286ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.net.Uri; 296ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.os.IBinder; 303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.provider.CallLog; 313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.telecom.Call; 326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.telecom.CallAudioState; 33684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.telecom.CallAudioState.CallAudioRoute; 346ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.telecom.DisconnectCause; 356ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.telecom.GatewayInfo; 366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.telecom.InCallService; 37684d175b191db416438ba00355f20d16eb79cef3Yuzhouimport android.telecom.PhoneAccountHandle; 386ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport android.telecom.TelecomManager; 393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.telephony.TelephonyManager; 403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.text.TextUtils; 413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport android.util.Log; 42a16cb24e5b5690af55597ad5c8540a7c90ae146aSrinivas Visvanathan 43bb51ff67f2973488079684ca58924a1c4b712dabJohnny Zhouimport com.android.car.dialer.CallListener; 443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport com.android.car.dialer.R; 453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport java.lang.ref.WeakReference; 473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.ArrayList; 483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.Calendar; 493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.Collections; 503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.Comparator; 516ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport java.util.HashMap; 523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyerimport java.util.List; 536ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport java.util.Map; 546ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanimport java.util.concurrent.CopyOnWriteArrayList; 553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer/** 573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * The entry point for all interactions between UI and telecom. 583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 596ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathanpublic class UiCallManager { 603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static String TAG = "Em.TelecomMgr"; 613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 62684d175b191db416438ba00355f20d16eb79cef3Yuzhou private static final String HFP_CLIENT_CONNECTION_SERVICE_CLASS_NAME 63684d175b191db416438ba00355f20d16eb79cef3Yuzhou = "com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService"; 643d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // Rate limit how often you can place outgoing calls. 653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static final long MIN_TIME_BETWEEN_CALLS_MS = 3000; 663d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static final List<Integer> sCallStateRank = new ArrayList<>(); 670ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou private static UiCallManager sUiCallManager; 683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 696ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // Used to assign id's to UiCall objects as they're created. 706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private static int nextCarPhoneCallId = 0; 713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer static { 733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // States should be added from lowest rank to highest 743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_DISCONNECTED); 753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_DISCONNECTING); 763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_NEW); 773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_CONNECTING); 783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_SELECT_PHONE_ACCOUNT); 793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_HOLDING); 803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_ACTIVE); 813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_DIALING); 823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer sCallStateRank.add(Call.STATE_RINGING); 833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 856ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private Context mContext; 866ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private TelephonyManager mTelephonyManager; 876ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private long mLastPlacedCallTimeMs; 883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 896ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private TelecomManager mTelecomManager; 906ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private InCallServiceImpl mInCallService; 91684d175b191db416438ba00355f20d16eb79cef3Yuzhou private BluetoothHeadsetClient mBluetoothHeadsetClient; 926ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private final Map<UiCall, Call> mCallMapping = new HashMap<>(); 936ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private final List<CallListener> mCallListeners = new CopyOnWriteArrayList<>(); 943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 950ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou /** 960ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * Initialized a globally accessible {@link UiCallManager} which can be retrieved by 970ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * {@link #get}. If this function is called a second time before calling {@link #tearDown()}, 980ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * an exception will be thrown. 990ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * 1000ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * @param applicationContext Application context. 1010ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou */ 1020ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou public static UiCallManager init(Context applicationContext) { 1030ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou if (sUiCallManager == null) { 1040ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou sUiCallManager = new UiCallManager(applicationContext); 1050ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou } else { 1060ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou throw new IllegalStateException("UiCallManager has been initialized."); 1070ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou } 1080ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou return sUiCallManager; 1090ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou } 1100ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou 1110ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou /** 1120ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * Gets the global {@link UiCallManager} instance. Make sure 1130ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * {@link #init(Context)} is called before calling this method. 1140ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou */ 1150ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou public static UiCallManager get() { 1160ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou if (sUiCallManager == null) { 1170ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou throw new IllegalStateException( 1180ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou "Call UiCallManager.init(Context) before calling this function"); 1190ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou } 1200ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou return sUiCallManager; 1210ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou } 1220ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou 1230ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou private UiCallManager(Context context) { 1243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 1253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "SetUp"); 1263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mContext = context; 1293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 1306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 1316ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mTelecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); 1326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Intent intent = new Intent(context, InCallServiceImpl.class); 1336ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan intent.setAction(InCallServiceImpl.ACTION_LOCAL_BIND); 1346ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan context.bindService(intent, mInCallServiceConnection, Context.BIND_AUTO_CREATE); 135684d175b191db416438ba00355f20d16eb79cef3Yuzhou 136684d175b191db416438ba00355f20d16eb79cef3Yuzhou BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 137684d175b191db416438ba00355f20d16eb79cef3Yuzhou adapter.getProfileProxy(mContext, new BluetoothProfile.ServiceListener() { 138684d175b191db416438ba00355f20d16eb79cef3Yuzhou @Override 139684d175b191db416438ba00355f20d16eb79cef3Yuzhou public void onServiceConnected(int profile, BluetoothProfile proxy) { 140684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (profile == BluetoothProfile.HEADSET_CLIENT) { 141684d175b191db416438ba00355f20d16eb79cef3Yuzhou mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy; 142684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 143684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 144684d175b191db416438ba00355f20d16eb79cef3Yuzhou 145684d175b191db416438ba00355f20d16eb79cef3Yuzhou @Override 146684d175b191db416438ba00355f20d16eb79cef3Yuzhou public void onServiceDisconnected(int profile) { 147684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 148684d175b191db416438ba00355f20d16eb79cef3Yuzhou }, BluetoothProfile.HEADSET_CLIENT); 1493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 1503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1516ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private final ServiceConnection mInCallServiceConnection = new ServiceConnection() { 1523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1536ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 1546ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onServiceConnected(ComponentName name, IBinder binder) { 1556ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 1566ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "onServiceConnected: " + name + ", service: " + binder); 1576ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1586ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mInCallService = ((InCallServiceImpl.LocalBinder) binder).getService(); 1596ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mInCallService.registerCallback(mInCallServiceCallback); 1606ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 1616ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // The InCallServiceImpl could be bound when we already have some active calls, let's 1626ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // notify UI about these calls. 1636ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (Call telecomCall : mInCallService.getCalls()) { 1646ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall uiCall = doTelecomCallAdded(telecomCall); 1656ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan onStateChanged(uiCall, uiCall.getState()); 1666ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1676ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1696ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 1706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onServiceDisconnected(ComponentName name) { 1716ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 1726ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "onServiceDisconnected: " + name); 1736ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1746ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mInCallService.unregisterCallback(mInCallServiceCallback); 1756ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 1776ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private InCallServiceImpl.Callback mInCallServiceCallback = 1786ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan new InCallServiceImpl.Callback() { 1796ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 1806ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onTelecomCallAdded(Call telecomCall) { 1816ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doTelecomCallAdded(telecomCall); 1826ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1836ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 1846ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 1856ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onTelecomCallRemoved(Call telecomCall) { 1866ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doTelecomCallRemoved(telecomCall); 1876ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1886ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 1896ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 1906ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onCallAudioStateChanged(CallAudioState audioState) { 1916ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallAudioStateChanged(audioState); 1926ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 1936ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan }; 1946ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan }; 1956ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 1960ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou /** 1970ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * Tears down the {@link UiCallManager}. Calling this function will null out the global 1980ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * accessible {@link UiCallManager} instance. Remember to re-initialize the 1990ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou * {@link UiCallManager}. 2000ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou */ 2016ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void tearDown() { 2026ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (mInCallService != null) { 2036ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mContext.unbindService(mInCallServiceConnection); 2046ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mInCallService = null; 2056ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2066ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallMapping.clear(); 2070ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou // Clear out the mContext reference to avoid memory leak. 2080ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou mContext = null; 2090ee4ae4c98ab4a94e1217399d4a71f6f6db87e99Yuzhou sUiCallManager = null; 2106ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2126ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void addListener(CallListener listener) { 2136ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2146ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "addListener: " + listener); 2156ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2166ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallListeners.add(listener); 2176ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2196ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void removeListener(CallListener listener) { 2206ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2216ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "removeListener: " + listener); 2226ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2236ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallListeners.remove(listener); 2246ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2266ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan protected void placeCall(String number) { 2276ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2286ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "placeCall: " + number); 2296ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Uri uri = Uri.fromParts("tel", number, null); 2316ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "android.telecom.TelecomManager#placeCall: " + uri); 2326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mTelecomManager.placeCall(uri, null); 2336ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2356ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void answerCall(UiCall uiCall) { 2366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2376ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "answerCall: " + uiCall); 2386ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2406ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 2416ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 2426ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.answer(0); 2436ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2446ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void rejectCall(UiCall uiCall, boolean rejectWithMessage, String textMessage) { 2476ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2486ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "rejectCall: " + uiCall + ", rejectWithMessage: " + rejectWithMessage 2496ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan + "textMessage: " + textMessage); 2506ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2526ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 2536ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 2546ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.reject(rejectWithMessage, textMessage); 2556ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2566ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2586ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void disconnectCall(UiCall uiCall) { 2596ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2606ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "disconnectCall: " + uiCall); 2616ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2636ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 2646ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 2656ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.disconnect(); 2666ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2676ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2696ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public List<UiCall> getCalls() { 2706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return new ArrayList<>(mCallMapping.keySet()); 2716ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2736ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public boolean getMuted() { 2746ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2756ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "getMuted"); 2766ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2776ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (mInCallService == null) { 2786ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return false; 2796ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2806ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan CallAudioState audioState = mInCallService.getCallAudioState(); 2816ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return audioState != null && audioState.isMuted(); 2826ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2846ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void setMuted(boolean muted) { 2856ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2866ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "setMuted: " + muted); 2876ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2886ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (mInCallService == null) { 2896ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return; 2906ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2916ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mInCallService.setMuted(muted); 2926ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2946ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public int getSupportedAudioRouteMask() { 2956ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 2966ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "getSupportedAudioRouteMask"); 2976ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 2983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 2996ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan CallAudioState audioState = getCallAudioStateOrNull(); 3006ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return audioState != null ? audioState.getSupportedRouteMask() : 0; 3016ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 303684d175b191db416438ba00355f20d16eb79cef3Yuzhou public List<Integer> getSupportedAudioRoute() { 304684d175b191db416438ba00355f20d16eb79cef3Yuzhou List<Integer> audioRouteList = new ArrayList<>(); 305684d175b191db416438ba00355f20d16eb79cef3Yuzhou 306684d175b191db416438ba00355f20d16eb79cef3Yuzhou boolean isBluetoothPhoneCall = isBluetoothCall(); 307684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (isBluetoothPhoneCall) { 308684d175b191db416438ba00355f20d16eb79cef3Yuzhou // if this is bluetooth phone call, we can only select audio route between vehicle 309684d175b191db416438ba00355f20d16eb79cef3Yuzhou // and phone. 310684d175b191db416438ba00355f20d16eb79cef3Yuzhou // Vehicle speaker route. 311684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_BLUETOOTH); 312684d175b191db416438ba00355f20d16eb79cef3Yuzhou // Headset route. 313684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_EARPIECE); 314684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else { 315684d175b191db416438ba00355f20d16eb79cef3Yuzhou // Most likely we are making phone call with on board SIM card. 316684d175b191db416438ba00355f20d16eb79cef3Yuzhou int supportedAudioRouteMask = getSupportedAudioRouteMask(); 317684d175b191db416438ba00355f20d16eb79cef3Yuzhou 318684d175b191db416438ba00355f20d16eb79cef3Yuzhou if ((supportedAudioRouteMask & CallAudioState.ROUTE_EARPIECE) != 0) { 319684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_EARPIECE); 320684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_BLUETOOTH) != 0) { 321684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_BLUETOOTH); 322684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_WIRED_HEADSET) != 0) { 323684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_WIRED_HEADSET); 324684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else if ((supportedAudioRouteMask & CallAudioState.ROUTE_SPEAKER) != 0) { 325684d175b191db416438ba00355f20d16eb79cef3Yuzhou audioRouteList.add(CallAudioState.ROUTE_SPEAKER); 326684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 327684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 328684d175b191db416438ba00355f20d16eb79cef3Yuzhou 329684d175b191db416438ba00355f20d16eb79cef3Yuzhou return audioRouteList; 330684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 331684d175b191db416438ba00355f20d16eb79cef3Yuzhou 332684d175b191db416438ba00355f20d16eb79cef3Yuzhou public boolean isBluetoothCall() { 333684d175b191db416438ba00355f20d16eb79cef3Yuzhou PhoneAccountHandle phoneAccountHandle = 334684d175b191db416438ba00355f20d16eb79cef3Yuzhou mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 335684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) { 336684d175b191db416438ba00355f20d16eb79cef3Yuzhou return HFP_CLIENT_CONNECTION_SERVICE_CLASS_NAME.equals( 337684d175b191db416438ba00355f20d16eb79cef3Yuzhou phoneAccountHandle.getComponentName().getClassName()); 338684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else { 339684d175b191db416438ba00355f20d16eb79cef3Yuzhou return false; 340684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 341684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 342684d175b191db416438ba00355f20d16eb79cef3Yuzhou 3436ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public int getAudioRoute() { 3446ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan CallAudioState audioState = getCallAudioStateOrNull(); 3456ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan int audioRoute = audioState != null ? audioState.getRoute() : 0; 3466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 3476ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "getAudioRoute " + audioRoute); 3486ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3496ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return audioRoute; 3506ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3516ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 352684d175b191db416438ba00355f20d16eb79cef3Yuzhou /** 353684d175b191db416438ba00355f20d16eb79cef3Yuzhou * Re-route the audio out phone of the ongoing phone call. 354684d175b191db416438ba00355f20d16eb79cef3Yuzhou */ 355684d175b191db416438ba00355f20d16eb79cef3Yuzhou public void setAudioRoute(@CallAudioRoute int audioRoute) { 356684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (mBluetoothHeadsetClient != null && isBluetoothCall()) { 357684d175b191db416438ba00355f20d16eb79cef3Yuzhou for (BluetoothDevice device : mBluetoothHeadsetClient.getConnectedDevices()) { 358684d175b191db416438ba00355f20d16eb79cef3Yuzhou List<BluetoothHeadsetClientCall> currentCalls = 359684d175b191db416438ba00355f20d16eb79cef3Yuzhou mBluetoothHeadsetClient.getCurrentCalls(device); 360684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (currentCalls != null && !currentCalls.isEmpty()) { 361684d175b191db416438ba00355f20d16eb79cef3Yuzhou if (audioRoute == CallAudioState.ROUTE_BLUETOOTH) { 362684d175b191db416438ba00355f20d16eb79cef3Yuzhou mBluetoothHeadsetClient.connectAudio(device); 363684d175b191db416438ba00355f20d16eb79cef3Yuzhou } else if ((audioRoute & CallAudioState.ROUTE_WIRED_OR_EARPIECE) != 0) { 364684d175b191db416438ba00355f20d16eb79cef3Yuzhou mBluetoothHeadsetClient.disconnectAudio(device); 365684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 366684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 367684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 368684d175b191db416438ba00355f20d16eb79cef3Yuzhou } 369684d175b191db416438ba00355f20d16eb79cef3Yuzhou // TODO: Implement routing audio if current call is not a bluetooth call. 3706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3716ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 3726ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void holdCall(UiCall uiCall) { 3736ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 3746ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "holdCall: " + uiCall); 3756ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3766ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 3776ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 3786ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 3796ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.hold(); 3806ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3816ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 3836ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void unholdCall(UiCall uiCall) { 3846ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 3856ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "unholdCall: " + uiCall); 3866ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3876ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 3886ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 3896ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 3906ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.unhold(); 3916ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3926ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3936ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 3946ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void playDtmfTone(UiCall uiCall, char digit) { 3956ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 3966ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "playDtmfTone: call: " + uiCall + ", digit: " + digit); 3976ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 3986ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 3996ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 4006ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 4016ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.playDtmfTone(digit); 4026ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4036ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4046ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4056ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void stopDtmfTone(UiCall uiCall) { 4066ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 4076ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "stopDtmfTone: call: " + uiCall); 4086ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4096ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4106ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 4116ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 4126ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.stopDtmfTone(); 4136ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4146ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4156ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4166ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void postDialContinue(UiCall uiCall, boolean proceed) { 4176ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 4186ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "postDialContinue: call: " + uiCall + ", proceed: " + proceed); 4196ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4206ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4216ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 4226ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 4236ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.postDialContinue(proceed); 4246ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4256ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4266ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4276ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void conference(UiCall uiCall, UiCall otherUiCall) { 4286ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 4296ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "conference: call: " + uiCall + ", otherCall: " + otherUiCall); 4306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4316ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 4336ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call otherTelecomCall = mCallMapping.get(otherUiCall); 4346ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 4356ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.conference(otherTelecomCall); 4366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4376ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4386ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4396ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void splitFromConference(UiCall uiCall) { 4406ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 4416ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "splitFromConference: call: " + uiCall); 4426ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4436ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4446ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call telecomCall = mCallMapping.get(uiCall); 4456ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall != null) { 4466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.splitFromConference(); 4476ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4486ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4496ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4506ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private UiCall doTelecomCallAdded(final Call telecomCall) { 4516ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "doTelecomCallAdded: " + telecomCall); 4526ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4536ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall uiCall = getOrCreateCallContainer(telecomCall); 4546ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.registerCallback(new TelecomCallListener(this, uiCall)); 4556ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (CallListener listener : mCallListeners) { 4566ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan listener.onCallAdded(uiCall); 4576ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4586ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "Call backs registered"); 4596ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4606ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (telecomCall.getState() == Call.STATE_SELECT_PHONE_ACCOUNT) { 4616ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // TODO(b/26189994): need to show Phone Account picker to let user choose a phone 4626ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // account. It should be an account from TelecomManager#getCallCapablePhoneAccounts 4636ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan // list. 4646ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.w(TAG, "Need to select phone account for the given call: " + telecomCall + ", " 4656ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan + "but this feature is not implemented yet."); 4666ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan telecomCall.disconnect(); 4676ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4686ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return uiCall; 4696ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4716ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private void doTelecomCallRemoved(Call telecomCall) { 4726ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall uiCall = getOrCreateCallContainer(telecomCall); 4736ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4746ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallMapping.remove(uiCall); 4756ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4766ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (CallListener listener : mCallListeners) { 4776ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan listener.onCallRemoved(uiCall); 4786ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4796ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4806ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4816ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private void doCallAudioStateChanged(CallAudioState audioState) { 4826ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (CallListener listener : mCallListeners) { 4836ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan listener.onAudioStateChanged(audioState.isMuted(), audioState.getRoute(), 4846ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan audioState.getSupportedRouteMask()); 4856ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4866ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4876ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4886ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private void onStateChanged(UiCall uiCall, int state) { 4896ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (CallListener listener : mCallListeners) { 490bb51ff67f2973488079684ca58924a1c4b712dabJohnny Zhou listener.onCallStateChanged(uiCall, state); 4916ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4926ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4936ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 4946ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private void onCallUpdated(UiCall uiCall) { 4956ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (CallListener listener : mCallListeners) { 4966ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan listener.onCallUpdated(uiCall); 4976ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4986ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 4996ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5006ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private UiCall getOrCreateCallContainer(Call telecomCall) { 5016ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan for (Map.Entry<UiCall, Call> entry : mCallMapping.entrySet()) { 5026ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (entry.getValue() == telecomCall) { 5036ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return entry.getKey(); 5046ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5056ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5066ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5076ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall uiCall = new UiCall(nextCarPhoneCallId++); 5086ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan updateCallContainerFromTelecom(uiCall, telecomCall); 5096ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallMapping.put(uiCall, telecomCall); 5106ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return uiCall; 5116ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5126ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5136ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private static void updateCallContainerFromTelecom(UiCall uiCall, Call telecomCall) { 5146ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 5156ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "updateCallContainerFromTelecom: call: " + uiCall + ", telecomCall: " 5166ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan + telecomCall); 5176ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5186ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5196ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setState(telecomCall.getState()); 5206ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setHasChildren(!telecomCall.getChildren().isEmpty()); 5216ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setHasParent(telecomCall.getParent() != null); 5226ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5236ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Call.Details details = telecomCall.getDetails(); 5246ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (details == null) { 5256ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return; 5266ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5276ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5286ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setConnectTimeMillis(details.getConnectTimeMillis()); 5296ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan DisconnectCause cause = details.getDisconnectCause(); 5316ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setDisconnectCause(cause == null ? null : cause.getLabel()); 5326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5336ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan GatewayInfo gatewayInfo = details.getGatewayInfo(); 5346ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setGatewayInfoOriginalAddress( 5356ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan gatewayInfo == null ? null : gatewayInfo.getOriginalAddress()); 5366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5376ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan String number = ""; 5386ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (gatewayInfo != null) { 5396ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan number = gatewayInfo.getOriginalAddress().getSchemeSpecificPart(); 5406ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } else if (details.getHandle() != null) { 5416ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan number = details.getHandle().getSchemeSpecificPart(); 5426ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5436ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan uiCall.setNumber(number); 5446ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5456ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 5466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private CallAudioState getCallAudioStateOrNull() { 5476ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan return mInCallService != null ? mInCallService.getCallAudioState() : null; 5486ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 5493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer /** Returns a first call that matches at least one provided call state */ 5513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public UiCall getCallWithState(int... callStates) { 5523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 5533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "getCallWithState: " + callStates); 5543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer for (UiCall call : getCalls()) { 5563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer for (int callState : callStates) { 5573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (call.getState() == callState) { 5583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return call; 5593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 5633d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5643d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public UiCall getPrimaryCall() { 5663d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 5673d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "getPrimaryCall"); 5683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5693d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer List<UiCall> calls = getCalls(); 5703d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (calls.isEmpty()) { 5713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 5723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Collections.sort(calls, getCallComparator()); 5753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer UiCall uiCall = calls.get(0); 5763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (uiCall.hasParent()) { 5773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 5783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return uiCall; 5803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public UiCall getSecondaryCall() { 5833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 5843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "getSecondaryCall"); 5853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer List<UiCall> calls = getCalls(); 5873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (calls.size() < 2) { 5883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 5893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Collections.sort(calls, getCallComparator()); 5923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer UiCall uiCall = calls.get(1); 5933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (uiCall.hasParent()) { 5943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return null; 5953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return uiCall; 5973d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 5983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 5993d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public static final int CAN_PLACE_CALL_RESULT_OK = 0; 6003d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public static final int CAN_PLACE_CALL_RESULT_NETWORK_UNAVAILABLE = 1; 6013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public static final int CAN_PLACE_CALL_RESULT_HFP_UNAVAILABLE = 2; 6023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public static final int CAN_PLACE_CALL_RESULT_AIRPLANE_MODE = 3; 6033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public int getCanPlaceCallStatus(String number, boolean bluetoothRequired) { 6053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer // TODO(b/26191392): figure out the logic for projected and embedded modes 6063d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return CAN_PLACE_CALL_RESULT_OK; 6073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public String getFailToPlaceCallMessage(int canPlaceCallResult) { 6103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer switch (canPlaceCallResult) { 6113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer case CAN_PLACE_CALL_RESULT_OK: 6123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return ""; 6133d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer case CAN_PLACE_CALL_RESULT_HFP_UNAVAILABLE: 6143d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return mContext.getString(R.string.error_no_hfp); 6153d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer case CAN_PLACE_CALL_RESULT_AIRPLANE_MODE: 6163d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return mContext.getString(R.string.error_airplane_mode); 6173d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer case CAN_PLACE_CALL_RESULT_NETWORK_UNAVAILABLE: 6183d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer default: 6193d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return mContext.getString(R.string.error_network_not_available); 6203d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6213d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6223d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6233d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer /** Places call only if there's no outgoing call right now */ 6243d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public void safePlaceCall(String number, boolean bluetoothRequired) { 6253d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 6263d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "safePlaceCall: " + number); 6273d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6283d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6293d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int placeCallStatus = getCanPlaceCallStatus(number, bluetoothRequired); 6303d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (placeCallStatus != CAN_PLACE_CALL_RESULT_OK) { 6313d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 6323d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "Unable to place a call: " + placeCallStatus); 6333d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6343d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return; 6353d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6363d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6373d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer UiCall outgoingCall = getCallWithState( 6383d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Call.STATE_CONNECTING, Call.STATE_NEW, Call.STATE_DIALING); 6393d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (outgoingCall == null) { 6403d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer long now = Calendar.getInstance().getTimeInMillis(); 6413d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (now - mLastPlacedCallTimeMs > MIN_TIME_BETWEEN_CALLS_MS) { 6423d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer placeCall(number); 6433d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer mLastPlacedCallTimeMs = now; 6443d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 6453d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.INFO)) { 6463d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.i(TAG, "You have to wait " + MIN_TIME_BETWEEN_CALLS_MS 6473d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer + "ms between making calls"); 6483d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6493d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6503d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6513d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6523d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6533d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public void callVoicemail() { 6543d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 6553d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "callVoicemail"); 6563d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6573d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6583d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String voicemailNumber = TelecomUtils.getVoicemailNumber(mContext); 6593d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (TextUtils.isEmpty(voicemailNumber)) { 6603d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.w(TAG, "Unable to get voicemail number."); 6613d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return; 6623d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6633d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer safePlaceCall(voicemailNumber, false); 6643d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6653d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6663d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer /** 6673d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Returns the call types for the given number of items in the cursor. 6683d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * <p/> 6693d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * It uses the next {@code count} rows in the cursor to extract the types. 6703d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * <p/> 6713d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer * Its position in the cursor is unchanged by this function. 6723d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer */ 6733d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public int[] getCallTypes(Cursor cursor, int count) { 6743d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (Log.isLoggable(TAG, Log.DEBUG)) { 6753d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer Log.d(TAG, "getCallTypes: cursor: " + cursor + ", count: " + count); 6763d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6773d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int position = cursor.getPosition(); 6793d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int[] callTypes = new int[count]; 6803d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String voicemailNumber = mTelephonyManager.getVoiceMailNumber(); 6813d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int column; 6823d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer for (int index = 0; index < count; ++index) { 6833d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer column = cursor.getColumnIndex(CallLog.Calls.NUMBER); 6843d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer String phoneNumber = cursor.getString(column); 6853d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (phoneNumber != null && phoneNumber.equals(voicemailNumber)) { 6863d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer callTypes[index] = PhoneLoader.VOICEMAIL_TYPE; 6873d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else { 6883d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer column = cursor.getColumnIndex(CallLog.Calls.TYPE); 6893d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer callTypes[index] = cursor.getInt(column); 6903d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6913d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer cursor.moveToNext(); 6923d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6933d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer cursor.moveToPosition(position); 6943d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return callTypes; 6953d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 6963d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 6973d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer private static Comparator<UiCall> getCallComparator() { 6983d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return new Comparator<UiCall>() { 6993d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer @Override 7003d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer public int compare(UiCall call, UiCall otherCall) { 7013d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer if (call.hasParent() && !otherCall.hasParent()) { 7023d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return 1; 7033d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } else if (!call.hasParent() && otherCall.hasParent()) { 7043d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return -1; 7053d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 7063d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int carCallRank = sCallStateRank.indexOf(call.getState()); 7073d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer int otherCarCallRank = sCallStateRank.indexOf(otherCall.getState()); 7083d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer 7093d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer return otherCarCallRank - carCallRank; 7103d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 7113d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer }; 7123d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer } 7136ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7146ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private static class TelecomCallListener extends Call.Callback { 7156ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private final WeakReference<UiCallManager> mCarTelecomMangerRef; 7166ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private final WeakReference<UiCall> mCallContainerRef; 7176ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7186ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan TelecomCallListener(UiCallManager carTelecomManager, UiCall uiCall) { 7196ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCarTelecomMangerRef = new WeakReference<>(carTelecomManager); 7206ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan mCallContainerRef = new WeakReference<>(uiCall); 7216ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7226ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7236ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7246ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onStateChanged(Call telecomCall, int state) { 7256ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 7266ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "onStateChanged: " + state); 7276ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7286ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCallManager manager = mCarTelecomMangerRef.get(); 7296ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall call = mCallContainerRef.get(); 7306ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (manager != null && call != null) { 7316ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan call.setState(state); 7326ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan manager.onStateChanged(call, state); 7336ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7346ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7356ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7366ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7376ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onParentChanged(Call telecomCall, Call parent) { 7386ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallUpdated(telecomCall); 7396ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7406ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7416ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7426ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onCallDestroyed(Call telecomCall) { 7436ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (Log.isLoggable(TAG, Log.DEBUG)) { 7446ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan Log.d(TAG, "onCallDestroyed"); 7456ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7466ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7476ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7486ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7496ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onDetailsChanged(Call telecomCall, Call.Details details) { 7506ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallUpdated(telecomCall); 7516ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7526ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7536ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7546ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onVideoCallChanged(Call telecomCall, InCallService.VideoCall videoCall) { 7556ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallUpdated(telecomCall); 7566ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7576ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7586ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7596ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onCannedTextResponsesLoaded(Call telecomCall, 7606ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan List<String> cannedTextResponses) { 7616ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallUpdated(telecomCall); 7626ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7636ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7646ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan @Override 7656ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan public void onChildrenChanged(Call telecomCall, List<Call> children) { 7666ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan doCallUpdated(telecomCall); 7676ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7686ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan 7696ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan private void doCallUpdated(Call telecomCall) { 7706ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCallManager manager = mCarTelecomMangerRef.get(); 7716ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan UiCall uiCall = mCallContainerRef.get(); 7726ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan if (manager != null && uiCall != null) { 7736ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan updateCallContainerFromTelecom(uiCall, telecomCall); 7746ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan manager.onCallUpdated(uiCall); 7756ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7766ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7776ed89513a64aeaadc55268607e556c8299d4d6b4Srinivas Visvanathan } 7783d724a4b70dd9a08d9adddc3b403edfd572bcaa6Rakesh Iyer} 779