12afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon/* 22afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * Copyright (C) 2014 The Android Open Source Project 32afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * 42afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * Licensed under the Apache License, Version 2.0 (the "License"); 52afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * you may not use this file except in compliance with the License. 62afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * You may obtain a copy of the License at 72afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * 82afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * http://www.apache.org/licenses/LICENSE-2.0 92afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * 102afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * Unless required by applicable law or agreed to in writing, software 112afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * distributed under the License is distributed on an "AS IS" BASIS, 122afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * See the License for the specific language governing permissions and 142afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * limitations under the License. 152afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 162afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 172afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonpackage com.android.services.telephony; 182afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 194ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepalimport android.net.Uri; 202afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport android.os.AsyncResult; 214ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepalimport android.os.Bundle; 222afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport android.os.Handler; 232afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport android.os.Message; 24a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepalimport android.os.SystemClock; 254d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.PhoneAccount; 26d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebingerimport android.telecom.PhoneAccountHandle; 274d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunnimport android.telecom.TelecomManager; 284ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepalimport android.text.TextUtils; 295ad698f06592baf77a439007e0f084df85916a54Santos Cordon 302afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport com.android.internal.telephony.Call; 31d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebingerimport com.android.internal.telephony.CallStateException; 322afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport com.android.internal.telephony.Connection; 336ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunnimport com.android.internal.telephony.GsmCdmaPhone; 342afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordonimport com.android.internal.telephony.Phone; 356ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunnimport com.android.internal.telephony.PhoneConstants; 36a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordonimport com.android.internal.telephony.cdma.CdmaCallWaitingNotification; 375046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunnimport com.android.internal.telephony.imsphone.ImsExternalCallTracker; 385046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunnimport com.android.internal.telephony.imsphone.ImsExternalConnection; 39d5165b05c851ecd47d330b600ed2768e0db8b9d1Andrew Leeimport com.android.phone.PhoneUtils; 403f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee 41aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordonimport com.google.common.base.Preconditions; 422afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 43a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordonimport java.util.Objects; 44a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon 452afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon/** 464d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunn * Listens to incoming-call events from the associated phone object and notifies Telecom upon each 472afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * occurence. One instance of these exists for each of the telephony-based call services. 482afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 49aa7340388473c1676495a60e30dc6a48d318a489Ihab Awadfinal class PstnIncomingCallNotifier { 502afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon /** New ringing connection event code. */ 512afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon private static final int EVENT_NEW_RINGING_CONNECTION = 100; 52a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon private static final int EVENT_CDMA_CALL_WAITING = 101; 533f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee private static final int EVENT_UNKNOWN_CONNECTION = 102; 542afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 559cf11515781910c7fda66a8a27a0fa14ab1ed2afAmit Mahajan /** The phone object to listen to. */ 56c5201f417b58f95c5f1b54de1c101b3a35ad544fAmit Mahajan private final Phone mPhone; 57aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon 58aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon /** 596d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan * Used to listen to events from {@link #mPhone}. 602afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 612afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon private final Handler mHandler = new Handler() { 622afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon @Override 632afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon public void handleMessage(Message msg) { 642afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon switch(msg.what) { 652afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon case EVENT_NEW_RINGING_CONNECTION: 662afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon handleNewRingingConnection((AsyncResult) msg.obj); 672afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon break; 68a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon case EVENT_CDMA_CALL_WAITING: 69a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon handleCdmaCallWaiting((AsyncResult) msg.obj); 70a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon break; 713f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee case EVENT_UNKNOWN_CONNECTION: 723f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee handleNewUnknownConnection((AsyncResult) msg.obj); 733f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee break; 742afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon default: 752afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon break; 762afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 772afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 782afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon }; 792afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 802afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon /** 812afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * Persists the specified parameters and starts listening to phone events. 822afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * 839cf11515781910c7fda66a8a27a0fa14ab1ed2afAmit Mahajan * @param phone The phone object for listening to incoming calls. 842afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 85c5201f417b58f95c5f1b54de1c101b3a35ad544fAmit Mahajan PstnIncomingCallNotifier(Phone phone) { 869cf11515781910c7fda66a8a27a0fa14ab1ed2afAmit Mahajan Preconditions.checkNotNull(phone); 872afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 889cf11515781910c7fda66a8a27a0fa14ab1ed2afAmit Mahajan mPhone = phone; 89aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon 90aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon registerForNotifications(); 91aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon } 922afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 93e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon void teardown() { 94e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon unregisterForNotifications(); 95e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon } 96e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon 97aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon /** 98aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon * Register for notifications from the base phone. 99aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon */ 100aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon private void registerForNotifications() { 1016d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan if (mPhone != null) { 1026d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan Log.i(this, "Registering: %s", mPhone); 1036d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null); 1046d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.registerForCallWaiting(mHandler, EVENT_CDMA_CALL_WAITING, null); 1056d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null); 106aac7719aa36cbef5b52ec45aef75005084d60c4aSantos Cordon } 1072afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 1082afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 109e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon private void unregisterForNotifications() { 1106d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan if (mPhone != null) { 1116d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan Log.i(this, "Unregistering: %s", mPhone); 1126d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.unregisterForNewRingingConnection(mHandler); 1136d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.unregisterForCallWaiting(mHandler); 1146d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan mPhone.unregisterForUnknownConnection(mHandler); 115e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon } 116e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon } 117e3b3e4df2ca751ff55a34aa95c2722dca1a91924Santos Cordon 1182afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon /** 1194d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunn * Verifies the incoming call and triggers sending the incoming-call intent to Telecom. 1202afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * 1212afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon * @param asyncResult The result object from the new ringing event. 1222afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 1232afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon private void handleNewRingingConnection(AsyncResult asyncResult) { 1244822ee866dd3fc138f566afb2da810b491b68a6eSailesh Nepal Log.d(this, "handleNewRingingConnection"); 1252afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon Connection connection = (Connection) asyncResult.result; 1262afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon if (connection != null) { 1272afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon Call call = connection.getCall(); 1282afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 1294d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunn // Final verification of the ringing state before sending the intent to Telecom. 1302afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon if (call != null && call.getState().isRinging()) { 1313199aa7f8bcb48569eb8289abc055ba0f8496ba8Sailesh Nepal sendIncomingCallIntent(connection); 1322afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 1332afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 1342afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 1352afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon 136a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon private void handleCdmaCallWaiting(AsyncResult asyncResult) { 137a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon Log.d(this, "handleCdmaCallWaiting"); 138a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon CdmaCallWaitingNotification ccwi = (CdmaCallWaitingNotification) asyncResult.result; 1396d83e5eb90ee8b4551d61c4789bb8f124c4c12d2Amit Mahajan Call call = mPhone.getRingingCall(); 140a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon if (call.getState() == Call.State.WAITING) { 141a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon Connection connection = call.getLatestConnection(); 142a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon if (connection != null) { 143a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon String number = connection.getAddress(); 144e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn int presentation = connection.getNumberPresentation(); 145e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn 146e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn if (presentation != PhoneConstants.PRESENTATION_ALLOWED 147e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn && presentation == ccwi.numberPresentation) { 148e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn // Presentation of number not allowed, but the presentation of the Connection 149e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn // and the call waiting presentation match. 150e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn Log.i(this, "handleCdmaCallWaiting: inform telecom of waiting call; " 151e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn + "presentation = %d", presentation); 152a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon sendIncomingCallIntent(connection); 153e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn } else if (!TextUtils.isEmpty(number) && Objects.equals(number, ccwi.number)) { 154e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn // Presentation of the number is allowed, so we ensure the number matches the 155e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn // one in the call waiting information. 156e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn Log.i(this, "handleCdmaCallWaiting: inform telecom of waiting call; " 157e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn + "number = %s", Log.pii(number)); 158e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn sendIncomingCallIntent(connection); 159e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn } else { 160e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn Log.w(this, "handleCdmaCallWaiting: presentation or number do not match, not" 161e83529f2f30e8d5f762bd2b01a3e1f70bb91c39dTyler Gunn + " informing telecom of call: %s", ccwi); 162a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon } 163a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon } 164a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon } 165a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon } 166a956f73382c3aa2619c73b880a11ee1899c2fe18Santos Cordon 1673f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee private void handleNewUnknownConnection(AsyncResult asyncResult) { 1683f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee Log.i(this, "handleNewUnknownConnection"); 169fac053aeb7e30a964d683812b4f2bc6c37e1a038Yorke Lee if (!(asyncResult.result instanceof Connection)) { 170fac053aeb7e30a964d683812b4f2bc6c37e1a038Yorke Lee Log.w(this, "handleNewUnknownConnection called with non-Connection object"); 171fac053aeb7e30a964d683812b4f2bc6c37e1a038Yorke Lee return; 172fac053aeb7e30a964d683812b4f2bc6c37e1a038Yorke Lee } 1733f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee Connection connection = (Connection) asyncResult.result; 1743f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee if (connection != null) { 175fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon // Because there is a handler between telephony and here, it causes this action to be 176fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon // asynchronous which means that the call can switch to DISCONNECTED by the time it gets 177fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon // to this code. Check here to ensure we are not adding a disconnected or IDLE call. 178fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon Call.State state = connection.getState(); 179fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon if (state == Call.State.DISCONNECTED || state == Call.State.IDLE) { 180fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon Log.i(this, "Skipping new unknown connection because it is idle. " + connection); 181fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon return; 182fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon } 183fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon 1843f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee Call call = connection.getCall(); 1853f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee if (call != null && call.getState().isAlive()) { 1863f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee addNewUnknownCall(connection); 1873f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee } 1883f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee } 1893f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee } 1903f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee 1913f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee private void addNewUnknownCall(Connection connection) { 1920918d946e9711796acd766bac053b6dedf21f079Ihab Awad Log.i(this, "addNewUnknownCall, connection is: %s", connection); 193fff1c1dc2ffc2372b02b5bb78a8dfd0a16659ea8Santos Cordon 1940918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (!maybeSwapAnyWithUnknownConnection(connection)) { 1950918d946e9711796acd766bac053b6dedf21f079Ihab Awad Log.i(this, "determined new connection is: %s", connection); 196a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal Bundle extras = new Bundle(); 1970918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED && 1980918d946e9711796acd766bac053b6dedf21f079Ihab Awad !TextUtils.isEmpty(connection.getAddress())) { 1990918d946e9711796acd766bac053b6dedf21f079Ihab Awad Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null); 2000918d946e9711796acd766bac053b6dedf21f079Ihab Awad extras.putParcelable(TelecomManager.EXTRA_UNKNOWN_CALL_HANDLE, uri); 2010918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 2025046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn // ImsExternalConnections are keyed by a unique mCallId; include this as an extra on 2035046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn // the call to addNewUknownCall in Telecom. This way when the request comes back to the 2045046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn // TelephonyConnectionService, we will be able to determine which unknown connection is 2055046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn // being added. 2065046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn if (connection instanceof ImsExternalConnection) { 2075046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn ImsExternalConnection externalConnection = (ImsExternalConnection) connection; 2085046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn extras.putInt(ImsExternalCallTracker.EXTRA_IMS_EXTERNAL_CALL_ID, 2095046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn externalConnection.getCallId()); 2105046bc73a9bb72c6f6f9f913def0c71d551da62dTyler Gunn } 211a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal 212a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal // Specifies the time the call was added. This is used by the dialer for analytics. 213a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal extras.putLong(TelecomManager.EXTRA_CALL_CREATED_TIME_MILLIS, 214a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal SystemClock.elapsedRealtime()); 215a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal 216d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger PhoneAccountHandle handle = findCorrectPhoneAccountHandle(); 217d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger if (handle == null) { 218d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger try { 219d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger connection.hangup(); 220d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } catch (CallStateException e) { 221d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // connection already disconnected. Do nothing 222d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 223d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } else { 224d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger TelecomManager.from(mPhone.getContext()).addNewUnknownCall(handle, extras); 225d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 2260918d946e9711796acd766bac053b6dedf21f079Ihab Awad } else { 2270918d946e9711796acd766bac053b6dedf21f079Ihab Awad Log.i(this, "swapped an old connection, new one is: %s", connection); 2283f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee } 2293f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee } 2303f7f717a2295f9ae5cc6a34ed404ec22e94012daYorke Lee 2312afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon /** 2324d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunn * Sends the incoming call intent to telecom. 2332afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon */ 2343199aa7f8bcb48569eb8289abc055ba0f8496ba8Sailesh Nepal private void sendIncomingCallIntent(Connection connection) { 235a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal Bundle extras = new Bundle(); 2364d45d1cf58a2003378fd35912d6d73a00001bf06Tyler Gunn if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED && 2374ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepal !TextUtils.isEmpty(connection.getAddress())) { 2384ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepal Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null); 2395204cd32dc744cb3450401a19029fe95d665a13bYorke Lee extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri); 2404ddf9f9db56f7174c4cb20f7e9888a36b07e4d81Sailesh Nepal } 241a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal 242a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal // Specifies the time the call was added. This is used by the dialer for analytics. 243a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal extras.putLong(TelecomManager.EXTRA_CALL_CREATED_TIME_MILLIS, 244a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal SystemClock.elapsedRealtime()); 245a35276c6b0c79c2dc509faa251a2bfefe79f27efSailesh Nepal 246d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger PhoneAccountHandle handle = findCorrectPhoneAccountHandle(); 247d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger if (handle == null) { 248d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger try { 249d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger connection.hangup(); 250d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } catch (CallStateException e) { 251d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // connection already disconnected. Do nothing 252d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 253d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } else { 254d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras); 255d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 256d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 257d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger 258d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger /** 259d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger * Returns the PhoneAccount associated with this {@code PstnIncomingCallNotifier}'s phone. On a 260d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger * device with No SIM or in airplane mode, it can return an Emergency-only PhoneAccount. If no 261d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger * PhoneAccount is registered with telecom, return null. 262d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger * @return A valid PhoneAccountHandle that is registered to Telecom or null if there is none 263d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger * registered. 264d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger */ 265d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger private PhoneAccountHandle findCorrectPhoneAccountHandle() { 266d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger TelecomAccountRegistry telecomAccountRegistry = TelecomAccountRegistry.getInstance(null); 267d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // Check to see if a the SIM PhoneAccountHandle Exists for the Call. 268d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger PhoneAccountHandle handle = PhoneUtils.makePstnPhoneAccountHandle(mPhone); 269d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger if (telecomAccountRegistry.hasAccountEntryForPhoneAccount(handle)) { 270d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger return handle; 271d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 272d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // The PhoneAccountHandle does not match any PhoneAccount registered in Telecom. 273d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // This is only known to happen if there is no SIM card in the device and the device 274d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // receives an MT call while in ECM. Use the Emergency PhoneAccount to receive the account 275d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger // if it exists. 276d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger PhoneAccountHandle emergencyHandle = 277d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger PhoneUtils.makePstnPhoneAccountHandleWithPrefix(mPhone, "", true); 278d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger if(telecomAccountRegistry.hasAccountEntryForPhoneAccount(emergencyHandle)) { 279d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger Log.i(this, "Receiving MT call in ECM. Using Emergency PhoneAccount Instead."); 280d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger return emergencyHandle; 281d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger } 282d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger Log.w(this, "PhoneAccount not found."); 283d3edc2292d969ecf8df96281c50e1a8f7a3fc777Brad Ebinger return null; 2842afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon } 2850918d946e9711796acd766bac053b6dedf21f079Ihab Awad 2860918d946e9711796acd766bac053b6dedf21f079Ihab Awad /** 2870918d946e9711796acd766bac053b6dedf21f079Ihab Awad * Define cait.Connection := com.android.internal.telephony.Connection 2880918d946e9711796acd766bac053b6dedf21f079Ihab Awad * 2890918d946e9711796acd766bac053b6dedf21f079Ihab Awad * Given a previously unknown cait.Connection, check to see if it's likely a replacement for 2900918d946e9711796acd766bac053b6dedf21f079Ihab Awad * another cait.Connnection we already know about. If it is, then we silently swap it out 2910918d946e9711796acd766bac053b6dedf21f079Ihab Awad * underneath within the relevant {@link TelephonyConnection}, using 2920918d946e9711796acd766bac053b6dedf21f079Ihab Awad * {@link TelephonyConnection#setOriginalConnection(Connection)}, and return {@code true}. 2930918d946e9711796acd766bac053b6dedf21f079Ihab Awad * Otherwise, we return {@code false}. 2940918d946e9711796acd766bac053b6dedf21f079Ihab Awad */ 2950918d946e9711796acd766bac053b6dedf21f079Ihab Awad private boolean maybeSwapAnyWithUnknownConnection(Connection unknown) { 2960918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (!unknown.isIncoming()) { 2970918d946e9711796acd766bac053b6dedf21f079Ihab Awad TelecomAccountRegistry registry = TelecomAccountRegistry.getInstance(null); 2980918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (registry != null) { 2990918d946e9711796acd766bac053b6dedf21f079Ihab Awad TelephonyConnectionService service = registry.getTelephonyConnectionService(); 3000918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (service != null) { 3010918d946e9711796acd766bac053b6dedf21f079Ihab Awad for (android.telecom.Connection telephonyConnection : service 3020918d946e9711796acd766bac053b6dedf21f079Ihab Awad .getAllConnections()) { 303d0a745cc30614b02b88923964725937f789b6acbTyler Gunn if (telephonyConnection instanceof TelephonyConnection) { 304d0a745cc30614b02b88923964725937f789b6acbTyler Gunn if (maybeSwapWithUnknownConnection( 305d0a745cc30614b02b88923964725937f789b6acbTyler Gunn (TelephonyConnection) telephonyConnection, 306d0a745cc30614b02b88923964725937f789b6acbTyler Gunn unknown)) { 307d0a745cc30614b02b88923964725937f789b6acbTyler Gunn return true; 308d0a745cc30614b02b88923964725937f789b6acbTyler Gunn } 3090918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3100918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3110918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3120918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3130918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3140918d946e9711796acd766bac053b6dedf21f079Ihab Awad return false; 3150918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3160918d946e9711796acd766bac053b6dedf21f079Ihab Awad 3170918d946e9711796acd766bac053b6dedf21f079Ihab Awad private boolean maybeSwapWithUnknownConnection( 3180918d946e9711796acd766bac053b6dedf21f079Ihab Awad TelephonyConnection telephonyConnection, 3190918d946e9711796acd766bac053b6dedf21f079Ihab Awad Connection unknown) { 3200918d946e9711796acd766bac053b6dedf21f079Ihab Awad Connection original = telephonyConnection.getOriginalConnection(); 3210918d946e9711796acd766bac053b6dedf21f079Ihab Awad if (original != null && !original.isIncoming() 3220918d946e9711796acd766bac053b6dedf21f079Ihab Awad && Objects.equals(original.getAddress(), unknown.getAddress())) { 3235e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn // If the new unknown connection is an external connection, don't swap one with an 3245e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn // actual connection. This means a call got pulled away. We want the actual connection 3255e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn // to disconnect. 3265e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn if (unknown instanceof ImsExternalConnection && 3275e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn !(telephonyConnection 3285e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn .getOriginalConnection() instanceof ImsExternalConnection)) { 3295e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn Log.v(this, "maybeSwapWithUnknownConnection - not swapping regular connection " + 3305e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn "with external connection."); 3315e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn return false; 3325e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn } 3335e32cc7fbcd6e62684c72e5d50ec7795ab6bb23bTyler Gunn 3340918d946e9711796acd766bac053b6dedf21f079Ihab Awad telephonyConnection.setOriginalConnection(unknown); 335aee68204870f51e30808411e5de774111f8e9039Brad Ebinger 336aee68204870f51e30808411e5de774111f8e9039Brad Ebinger // Do not call hang up if the original connection is an ImsExternalConnection, it is 337aee68204870f51e30808411e5de774111f8e9039Brad Ebinger // not supported. 338aee68204870f51e30808411e5de774111f8e9039Brad Ebinger if (original instanceof ImsExternalConnection) { 339aee68204870f51e30808411e5de774111f8e9039Brad Ebinger return true; 340aee68204870f51e30808411e5de774111f8e9039Brad Ebinger } 3416ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn // If the connection we're replacing was a GSM or CDMA connection, call upon the call 3426ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn // tracker to perform cleanup of calls. This ensures that we don't end up with a 3436ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn // call stuck in the call tracker preventing other calls from being placed. 3446ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn if (original.getCall() != null && original.getCall().getPhone() != null && 3456ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn original.getCall().getPhone() instanceof GsmCdmaPhone) { 3466ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn 3476ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn GsmCdmaPhone phone = (GsmCdmaPhone) original.getCall().getPhone(); 3486ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn phone.getCallTracker().cleanupCalls(); 3496ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn Log.i(this, "maybeSwapWithUnknownConnection - Invoking call tracker cleanup " 3506ae83e2c15b08a04d92c083bb3d2c9aa39c0b085Tyler Gunn + "for connection: " + original); 351aee68204870f51e30808411e5de774111f8e9039Brad Ebinger } 3520918d946e9711796acd766bac053b6dedf21f079Ihab Awad return true; 3530918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3540918d946e9711796acd766bac053b6dedf21f079Ihab Awad return false; 3550918d946e9711796acd766bac053b6dedf21f079Ihab Awad } 3562afb2bebbb9c88f5ab8752f602a9148e14d14009Santos Cordon} 357