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