1fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal/* 2fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * Copyright (C) 2014 The Android Open Source Project 3fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * 4fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * Licensed under the Apache License, Version 2.0 (the "License"); 5fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * you may not use this file except in compliance with the License. 6fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * You may obtain a copy of the License at 7fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * 8fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * http://www.apache.org/licenses/LICENSE-2.0 9fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * 10fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * Unless required by applicable law or agreed to in writing, software 11fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * distributed under the License is distributed on an "AS IS" BASIS, 12fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * See the License for the specific language governing permissions and 14fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal * limitations under the License 15fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal */ 16fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 17fc22ba88566ef70e202128335231c367de6c52afSailesh Nepalpackage com.android.incallui; 18fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 190afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordonimport android.content.ActivityNotFoundException; 200afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordonimport android.content.Intent; 21fc22ba88566ef70e202128335231c367de6c52afSailesh Nepalimport android.os.Looper; 220ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordonimport android.telecom.InCallService; 236cddf46812634fadc194830774110780f14e9462Tyler Gunnimport android.telecom.PhoneAccountHandle; 24fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 25fc22ba88566ef70e202128335231c367de6c52afSailesh Nepalimport com.google.common.base.Preconditions; 26fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 27c79d745deeda2cdd2b17122602a32812132885aaSantos Cordonimport java.util.List; 28c79d745deeda2cdd2b17122602a32812132885aaSantos Cordon 290ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordonfinal class TelecomAdapter implements InCallServiceListener { 300afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon private static final String ADD_CALL_MODE_KEY = "add_call_mode"; 310afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon 326cddf46812634fadc194830774110780f14e9462Tyler Gunn private static TelecomAdapter sInstance; 330ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon private InCallService mInCallService; 34fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 356cddf46812634fadc194830774110780f14e9462Tyler Gunn static TelecomAdapter getInstance() { 36fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal Preconditions.checkState(Looper.getMainLooper().getThread() == Thread.currentThread()); 37fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal if (sInstance == null) { 386cddf46812634fadc194830774110780f14e9462Tyler Gunn sInstance = new TelecomAdapter(); 39fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 40fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal return sInstance; 41fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 42fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 436cddf46812634fadc194830774110780f14e9462Tyler Gunn private TelecomAdapter() { 44fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 45fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 46df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad @Override 470ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon public void setInCallService(InCallService inCallService) { 480ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon mInCallService = inCallService; 49df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad } 50df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad 51df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad @Override 520ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon public void clearInCallService() { 530ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon mInCallService = null; 54df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad } 55df06e232852a93d8238f3cacaab4d704de7e1216Ihab Awad 566cddf46812634fadc194830774110780f14e9462Tyler Gunn private android.telecom.Call getTelecommCallById(String callId) { 570ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Call call = CallList.getInstance().getCallById(callId); 58f3400c7cebb84af2a25137f536d17c1f3c50b556Yorke Lee return call == null ? null : call.getTelecommCall(); 59fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 60fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 619044e6296320cac2ee7c49465fdbb4a55912058aAndrew Lee void answerCall(String callId, int videoState) { 620ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 630ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 640ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.answer(videoState); 65fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 660ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error answerCall, call not in call list: " + callId); 67fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 68fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 69fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 706af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void rejectCall(String callId, boolean rejectWithMessage, String message) { 710ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 720ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 730ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.reject(rejectWithMessage, message); 74fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 750ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error rejectCall, call not in call list: " + callId); 76fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 77fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 78fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 796af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void disconnectCall(String callId) { 800ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 810ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 820ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.disconnect(); 83fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 840ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error disconnectCall, call not in call list " + callId); 85fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 86fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 87fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 886af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void holdCall(String callId) { 890ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 900ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 910ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.hold(); 92fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 930ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error holdCall, call not in call list " + callId); 94fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 95fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 96fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 976af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void unholdCall(String callId) { 980ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 990ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 1000ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.unhold(); 101fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 1020ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error unholdCall, call not in call list " + callId); 103fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 104fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 105fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 106fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal void mute(boolean shouldMute) { 1070ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (mInCallService != null) { 1080ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon mInCallService.setMuted(shouldMute); 109fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 1100ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error mute, mInCallService is null"); 111fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 112fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 113fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 114fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal void setAudioRoute(int route) { 1150ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (mInCallService != null) { 1160ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon mInCallService.setAudioRoute(route); 117fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 1180ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error setAudioRoute, mInCallService is null"); 119fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 120fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 121fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 1226af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void separateCall(String callId) { 1230ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 1240ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 1250ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.splitFromConference(); 126c9e18a969b97f6d110c1e1e84240d4828706c401Santos Cordon } else { 1270ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error separateCall, call not in call list " + callId); 128c9e18a969b97f6d110c1e1e84240d4828706c401Santos Cordon } 129fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 130fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 131c9e18a969b97f6d110c1e1e84240d4828706c401Santos Cordon void merge(String callId) { 1320ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 1330ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 1346cddf46812634fadc194830774110780f14e9462Tyler Gunn List<android.telecom.Call> conferenceable = call.getConferenceableCalls(); 135c79d745deeda2cdd2b17122602a32812132885aaSantos Cordon if (!conferenceable.isEmpty()) { 136c79d745deeda2cdd2b17122602a32812132885aaSantos Cordon call.conference(conferenceable.get(0)); 13752c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon } else { 138737f56760b617688aac7218021a5e615ed750810Ihab Awad if (call.getDetails().can( 139737f56760b617688aac7218021a5e615ed750810Ihab Awad android.telecom.Call.Details.CAPABILITY_MERGE_CONFERENCE)) { 14052c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon call.mergeConference(); 14152c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon } 142c79d745deeda2cdd2b17122602a32812132885aaSantos Cordon } 143c9e18a969b97f6d110c1e1e84240d4828706c401Santos Cordon } else { 1440ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error merge, call not in call list " + callId); 145c9e18a969b97f6d110c1e1e84240d4828706c401Santos Cordon } 146fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 147fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 1485461c6a3b5090e6fab47076c5c0aeb2d1091606dSailesh Nepal void swap(String callId) { 1490ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 1500ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 151737f56760b617688aac7218021a5e615ed750810Ihab Awad if (call.getDetails().can( 152737f56760b617688aac7218021a5e615ed750810Ihab Awad android.telecom.Call.Details.CAPABILITY_SWAP_CONFERENCE)) { 15352c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon call.swapConference(); 15452c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon } 15552c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon } else { 1560ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error swap, call not in call list " + callId); 15752c30ebe11e132c5b00a15aabdf4a411355bf0f4Santos Cordon } 158fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 159fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 160fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal void addCall() { 1610ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (mInCallService != null) { 1620afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon Intent intent = new Intent(Intent.ACTION_DIAL); 1630afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1640afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon 1650afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // when we request the dialer come up, we also want to inform 1660afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // it that we're going through the "add call" option from the 1670afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // InCallScreen / PhoneUtils. 1680afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon intent.putExtra(ADD_CALL_MODE_KEY, true); 1690afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon try { 1700afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon Log.d(this, "Sending the add Call intent"); 1710ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon mInCallService.startActivity(intent); 1720afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon } catch (ActivityNotFoundException e) { 1730afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // This is rather rare but possible. 1740afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // Note: this method is used even when the phone is encrypted. At that moment 1750afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon // the system may not find any Activity which can accept this Intent. 1760afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon Log.e(this, "Activity for adding calls isn't found.", e); 1770afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon } 1780afa8f450a86517bac3009dbae94ed4973de4dddSantos Cordon } 179fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 180fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 1816af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void playDtmfTone(String callId, char digit) { 1820ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 1830ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 1840ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.playDtmfTone(digit); 185fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 1860ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error playDtmfTone, call not in call list " + callId); 187fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 188fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 189fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 1906af0c61c32da6cfb400168ae3b0cf9f802abfed4Sailesh Nepal void stopDtmfTone(String callId) { 1910ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 1920ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 1930ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.stopDtmfTone(); 194fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } else { 1950ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error stopDtmfTone, call not in call list " + callId); 196fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 197fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 198fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 19903e06507ca4fb2463155052622880eff6286e254Evan Charlton void postDialContinue(String callId, boolean proceed) { 2000ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 2010ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 2020ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.postDialContinue(proceed); 2036e017333e59cb26bc914c6d77798a97d8c789d68Sailesh Nepal } else { 2040ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error postDialContinue, call not in call list " + callId); 2056e017333e59cb26bc914c6d77798a97d8c789d68Sailesh Nepal } 206fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal } 207fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal 20890b4ee033c8c0e9ceeaef0495ce8e1c205203aa5Nancy Chen void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, boolean setDefault) { 2090b26ad3b112ff399aa9627d7e6a252080a46f319Nancy Chen if (accountHandle == null) { 2100b26ad3b112ff399aa9627d7e6a252080a46f319Nancy Chen Log.e(this, "error phoneAccountSelected, accountHandle is null"); 2110ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon // TODO: Do we really want to send null accountHandle? 2120ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon } 2130ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon 2140ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon android.telecom.Call call = getTelecommCallById(callId); 2150ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon if (call != null) { 2160ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon call.phoneAccountSelected(accountHandle, setDefault); 2170ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon } else { 2180ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon Log.e(this, "error phoneAccountSelected, call not in call list " + callId); 2190b26ad3b112ff399aa9627d7e6a252080a46f319Nancy Chen } 2204fbdb77e2abc34e0a5e2479ab3a7e71c1da4619dNancy Chen } 221ba4e858e872fe446f3a7a17321289d025a40a847Santos Cordon 222ba4e858e872fe446f3a7a17321289d025a40a847Santos Cordon boolean canAddCall() { 223ba4e858e872fe446f3a7a17321289d025a40a847Santos Cordon // Default to true if we are not connected to telecom. 2240ea6ed91cc6956cf9497e506a9c63ef8380aaf42Santos Cordon return mInCallService == null ? true : mInCallService.canAddCall(); 225ba4e858e872fe446f3a7a17321289d025a40a847Santos Cordon } 226fc22ba88566ef70e202128335231c367de6c52afSailesh Nepal} 227