Loading src/java/com/android/internal/telephony/Connection.java +13 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,18 @@ public abstract class Connection { * For an IMS call, indicates that the peer supports video. */ public static final int SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 0x00000008; /** * Indicates that the connection is an external connection (e.g. an instance of the class * {@link com.android.internal.telephony.imsphone.ImsExternalConnection}. */ public static final int IS_EXTERNAL_CONNECTION = 0x00000010; /** * Indicates that this external connection can be pulled from the remote device to the * local device. */ public static final int IS_PULLABLE = 0x00000020; } /** Loading src/java/com/android/internal/telephony/TelephonyComponentFactory.java +5 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.uicc.IccCardProxy; Loading Loading @@ -115,6 +116,10 @@ public class TelephonyComponentFactory { return new ImsPhoneCallTracker(imsPhone); } public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) { return new ImsExternalCallTracker(imsPhone); } public CdmaSubscriptionSourceManager getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h, int what, Object obj) { Loading src/java/com/android/internal/telephony/TelephonyTester.java +60 −0 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Build; import android.telephony.Rlog; import com.android.ims.ImsCall; import com.android.ims.ImsCallProfile; import com.android.ims.ImsConferenceState; import com.android.ims.ImsExternalCallState; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.test.TestConferenceEventPackageParser; Loading @@ -32,6 +36,8 @@ import com.android.internal.telephony.test.TestConferenceEventPackageParser; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; /** * Telephony tester receives the following intents where {name} is the phone name Loading @@ -50,7 +56,22 @@ public class TelephonyTester { */ private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE = "com.android.internal.telephony.TestConferenceEventPackage"; /** * Test-only intent used to send a test dialog event package to the IMS framework. */ private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE = "com.android.internal.telephony.TestDialogEventPackage"; private static final String EXTRA_FILENAME = "filename"; private static final String EXTRA_STARTPACKAGE = "startPackage"; private static final String EXTRA_SENDPACKAGE = "sendPackage"; private static final String EXTRA_DIALOGID = "dialogId"; private static final String EXTRA_NUMBER = "number"; private static final String EXTRA_STATE = "state"; private static final String EXTRA_CANPULL = "canPull"; private static List<ImsExternalCallState> mImsExternalCallStates = null; private Phone mPhone; Loading @@ -70,6 +91,9 @@ public class TelephonyTester { } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) { log("inject simulated conference event package"); handleTestConferenceEventPackage(context, intent.getStringExtra(EXTRA_FILENAME)); } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) { log("handle test dialog event package intent"); handleTestDialogEventPackageIntent(intent); } else { if (DBG) log("onReceive: unknown action=" + action); } Loading @@ -91,6 +115,8 @@ public class TelephonyTester { if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE); filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE); filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE); mImsExternalCallStates = new ArrayList<ImsExternalCallState>(); } phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler()); Loading Loading @@ -148,4 +174,38 @@ public class TelephonyTester { imsCall.conferenceStateUpdated(imsConferenceState); } /** * Handles intents containing test dialog event package data. * * @param intent */ private void handleTestDialogEventPackageIntent(Intent intent) { ImsPhone imsPhone = (ImsPhone) mPhone; if (imsPhone == null) { return; } ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker(); if (externalCallTracker == null) { return; } if (intent.hasExtra(EXTRA_STARTPACKAGE)) { mImsExternalCallStates.clear(); } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) { externalCallTracker.refreshExternalCallState(mImsExternalCallStates); mImsExternalCallStates.clear(); } else if (intent.hasExtra(EXTRA_DIALOGID)) { ImsExternalCallState state = new ImsExternalCallState( intent.getIntExtra(EXTRA_DIALOGID, 0), Uri.parse(intent.getStringExtra(EXTRA_NUMBER)), intent.getBooleanExtra(EXTRA_CANPULL, true), intent.getIntExtra(EXTRA_STATE, ImsExternalCallState.CALL_STATE_CONFIRMED), ImsCallProfile.CALL_TYPE_VOICE, false /* isHeld */ ); mImsExternalCallStates.add(state); } } } src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.internal.telephony.imsphone; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; import java.util.List; /** * Companion class for {@link ImsExternalConnection}; represents an external call which was * received via {@link com.android.ims.ImsExternalCallState} info. */ public class ImsExternalCall extends Call { private Phone mPhone; public ImsExternalCall(Phone phone, ImsExternalConnection connection) { mPhone = phone; mConnections.add(connection); } @Override public List<Connection> getConnections() { return mConnections; } @Override public Phone getPhone() { return mPhone; } @Override public boolean isMultiparty() { return false; } @Override public void hangup() throws CallStateException { } /** * Sets the call state to active. */ public void setActive() { setState(State.ACTIVE); } /** * Sets the call state to terminated. */ public void setTerminated() { setState(State.DISCONNECTED); } } src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.internal.telephony.imsphone; import com.android.ims.ImsExternalCallState; import com.android.internal.telephony.Call; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; import android.os.Bundle; import android.telecom.PhoneAccountHandle; import android.util.ArrayMap; import android.util.Log; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Responsible for tracking external calls known to the system. */ public class ImsExternalCallTracker { public final static String TAG = "ImsExternalCallTracker"; /** * Extra key used when informing telecom of a new external call using the * {@link android.telecom.TelecomManager#addNewUnknownCall(PhoneAccountHandle, Bundle)} API. * Used to ensure that when Telecom requests the {@link android.telecom.ConnectionService} to * create the connection for the unknown call that we can determine which * {@link ImsExternalConnection} in {@link #mExternalConnections} is the one being requested. */ public final static String EXTRA_IMS_EXTERNAL_CALL_ID = "android.telephony.ImsExternalCallTracker.extra.EXTERNAL_CALL_ID"; /** * Contains a list of the external connections known by the ImsPhoneCallTracker. These are * connections which originated from a dialog event package and reside on another device. * Used in multi-endpoint (VoLTE for internet connected endpoints) scenarios. */ private Map<Integer, ImsExternalConnection> mExternalConnections = new ArrayMap<Integer, ImsExternalConnection>(); private ImsPhone mPhone; public ImsExternalCallTracker(ImsPhone phone) { mPhone = phone; } /** * Called when the IMS stack receives a new dialog event package. Triggers the creation and * update of {@link ImsExternalConnection}s to represent the dialogs in the dialog event * package data. * * @param externalCallStates the {@link ImsExternalCallState} information for the dialog event * package. */ public void refreshExternalCallState(List<ImsExternalCallState> externalCallStates) { Log.d(TAG, "refreshExternalCallState: depSize = " + externalCallStates.size()); // Check to see if any call Ids are no longer present in the external call state. If they // are, the calls are terminated and should be removed. Iterator<Map.Entry<Integer, ImsExternalConnection>> connectionIterator = mExternalConnections.entrySet().iterator(); boolean wasCallRemoved = false; while (connectionIterator.hasNext()) { Map.Entry<Integer, ImsExternalConnection> entry = connectionIterator.next(); int callId = entry.getKey().intValue(); if (!containsCallId(externalCallStates, callId)) { ImsExternalConnection externalConnection = entry.getValue(); externalConnection.setTerminated(); connectionIterator.remove(); wasCallRemoved = true; } } // If one or more calls were removed, trigger a notification that will cause the // TelephonyConnection instancse to refresh their state with Telecom. if (wasCallRemoved) { mPhone.notifyPreciseCallStateChanged(); } // Check for new calls, and updates to existing ones. for (ImsExternalCallState callState : externalCallStates) { if (!mExternalConnections.containsKey(callState.getCallId())) { Log.d(TAG, "refreshExternalCallState: got = " + callState); // If there is a new entry and it is already terminated, don't bother adding it to // telecom. if (callState.getCallState() != ImsExternalCallState.CALL_STATE_CONFIRMED) { continue; } createExternalConnection(callState); } else{ updateExistingConnection(mExternalConnections.get(callState.getCallId()), callState); } } } /** * Finds an external connection given a call Id. * * @param callId The call Id. * @return The {@link Connection}, or {@code null} if no match found. */ public Connection getConnectionById(int callId) { return mExternalConnections.get(callId); } /** * Given an {@link ImsExternalCallState} instance obtained from a dialog event package, * creates a new instance of {@link ImsExternalConnection} to represent the connection, and * initiates the addition of the new call to Telecom as an unknown call. * * @param state External call state from a dialog event package. */ private void createExternalConnection(ImsExternalCallState state) { Log.i(TAG, "createExternalConnection"); ImsExternalConnection connection = new ImsExternalConnection(mPhone, state.getCallId(), /* Dialog event package call id */ state.getAddress().getSchemeSpecificPart() /* phone number */, state.isCallPullable()); // Add to list of tracked connections. mExternalConnections.put(connection.getCallId(), connection); // Note: The notification of unknown connection is ultimately handled by // PstnIncomingCallNotifier#addNewUnknownCall. That method will ensure that an extra is set // containing the ImsExternalConnection#mCallId so that we have a means of reconciling which // unknown call was added. mPhone.notifyUnknownConnection(connection); } /** * Given an existing {@link ImsExternalConnection}, applies any changes found found in a * {@link ImsExternalCallState} instance received from a dialog event package to the connection. * * @param connection The connection to apply changes to. * @param state The new dialog state for the connection. */ private void updateExistingConnection(ImsExternalConnection connection, ImsExternalCallState state) { Call.State existingState = connection.getState(); Call.State newState = state.getCallState() == ImsExternalCallState.CALL_STATE_CONFIRMED ? Call.State.ACTIVE : Call.State.DISCONNECTED; if (existingState != newState) { if (newState == Call.State.ACTIVE) { connection.setActive(); } else { connection.setTerminated(); mExternalConnections.remove(connection); mPhone.notifyPreciseCallStateChanged(); } } connection.setIsPullable(state.isCallPullable()); } /** * Determines if a list of call states obtained from a dialog event package contacts an existing * call Id. * * @param externalCallStates The dialog event package state information. * @param callId The call Id. * @return {@code true} if the state information contains the call Id, {@code false} otherwise. */ private boolean containsCallId(List<ImsExternalCallState> externalCallStates, int callId) { for (ImsExternalCallState state : externalCallStates) { if (state.getCallId() == callId) { return true; } } return false; } } Loading
src/java/com/android/internal/telephony/Connection.java +13 −1 Original line number Diff line number Diff line Loading @@ -66,6 +66,18 @@ public abstract class Connection { * For an IMS call, indicates that the peer supports video. */ public static final int SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 0x00000008; /** * Indicates that the connection is an external connection (e.g. an instance of the class * {@link com.android.internal.telephony.imsphone.ImsExternalConnection}. */ public static final int IS_EXTERNAL_CONNECTION = 0x00000010; /** * Indicates that this external connection can be pulled from the remote device to the * local device. */ public static final int IS_PULLABLE = 0x00000020; } /** Loading
src/java/com/android/internal/telephony/TelephonyComponentFactory.java +5 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.dataconnection.DcTracker; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCallTracker; import com.android.internal.telephony.uicc.IccCardProxy; Loading Loading @@ -115,6 +116,10 @@ public class TelephonyComponentFactory { return new ImsPhoneCallTracker(imsPhone); } public ImsExternalCallTracker makeImsExternalCallTracker(ImsPhone imsPhone) { return new ImsExternalCallTracker(imsPhone); } public CdmaSubscriptionSourceManager getCdmaSubscriptionSourceManagerInstance(Context context, CommandsInterface ci, Handler h, int what, Object obj) { Loading
src/java/com/android/internal/telephony/TelephonyTester.java +60 −0 Original line number Diff line number Diff line Loading @@ -20,11 +20,15 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Build; import android.telephony.Rlog; import com.android.ims.ImsCall; import com.android.ims.ImsCallProfile; import com.android.ims.ImsConferenceState; import com.android.ims.ImsExternalCallState; import com.android.internal.telephony.imsphone.ImsExternalCallTracker; import com.android.internal.telephony.imsphone.ImsPhone; import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.test.TestConferenceEventPackageParser; Loading @@ -32,6 +36,8 @@ import com.android.internal.telephony.test.TestConferenceEventPackageParser; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.List; /** * Telephony tester receives the following intents where {name} is the phone name Loading @@ -50,7 +56,22 @@ public class TelephonyTester { */ private static final String ACTION_TEST_CONFERENCE_EVENT_PACKAGE = "com.android.internal.telephony.TestConferenceEventPackage"; /** * Test-only intent used to send a test dialog event package to the IMS framework. */ private static final String ACTION_TEST_DIALOG_EVENT_PACKAGE = "com.android.internal.telephony.TestDialogEventPackage"; private static final String EXTRA_FILENAME = "filename"; private static final String EXTRA_STARTPACKAGE = "startPackage"; private static final String EXTRA_SENDPACKAGE = "sendPackage"; private static final String EXTRA_DIALOGID = "dialogId"; private static final String EXTRA_NUMBER = "number"; private static final String EXTRA_STATE = "state"; private static final String EXTRA_CANPULL = "canPull"; private static List<ImsExternalCallState> mImsExternalCallStates = null; private Phone mPhone; Loading @@ -70,6 +91,9 @@ public class TelephonyTester { } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) { log("inject simulated conference event package"); handleTestConferenceEventPackage(context, intent.getStringExtra(EXTRA_FILENAME)); } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) { log("handle test dialog event package intent"); handleTestDialogEventPackageIntent(intent); } else { if (DBG) log("onReceive: unknown action=" + action); } Loading @@ -91,6 +115,8 @@ public class TelephonyTester { if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { log("register for intent action=" + ACTION_TEST_CONFERENCE_EVENT_PACKAGE); filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE); filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE); mImsExternalCallStates = new ArrayList<ImsExternalCallState>(); } phone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone.getHandler()); Loading Loading @@ -148,4 +174,38 @@ public class TelephonyTester { imsCall.conferenceStateUpdated(imsConferenceState); } /** * Handles intents containing test dialog event package data. * * @param intent */ private void handleTestDialogEventPackageIntent(Intent intent) { ImsPhone imsPhone = (ImsPhone) mPhone; if (imsPhone == null) { return; } ImsExternalCallTracker externalCallTracker = imsPhone.getExternalCallTracker(); if (externalCallTracker == null) { return; } if (intent.hasExtra(EXTRA_STARTPACKAGE)) { mImsExternalCallStates.clear(); } else if (intent.hasExtra(EXTRA_SENDPACKAGE)) { externalCallTracker.refreshExternalCallState(mImsExternalCallStates); mImsExternalCallStates.clear(); } else if (intent.hasExtra(EXTRA_DIALOGID)) { ImsExternalCallState state = new ImsExternalCallState( intent.getIntExtra(EXTRA_DIALOGID, 0), Uri.parse(intent.getStringExtra(EXTRA_NUMBER)), intent.getBooleanExtra(EXTRA_CANPULL, true), intent.getIntExtra(EXTRA_STATE, ImsExternalCallState.CALL_STATE_CONFIRMED), ImsCallProfile.CALL_TYPE_VOICE, false /* isHeld */ ); mImsExternalCallStates.add(state); } } }
src/java/com/android/internal/telephony/imsphone/ImsExternalCall.java 0 → 100644 +72 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.internal.telephony.imsphone; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; import java.util.List; /** * Companion class for {@link ImsExternalConnection}; represents an external call which was * received via {@link com.android.ims.ImsExternalCallState} info. */ public class ImsExternalCall extends Call { private Phone mPhone; public ImsExternalCall(Phone phone, ImsExternalConnection connection) { mPhone = phone; mConnections.add(connection); } @Override public List<Connection> getConnections() { return mConnections; } @Override public Phone getPhone() { return mPhone; } @Override public boolean isMultiparty() { return false; } @Override public void hangup() throws CallStateException { } /** * Sets the call state to active. */ public void setActive() { setState(State.ACTIVE); } /** * Sets the call state to terminated. */ public void setTerminated() { setState(State.DISCONNECTED); } }
src/java/com/android/internal/telephony/imsphone/ImsExternalCallTracker.java 0 → 100644 +193 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.internal.telephony.imsphone; import com.android.ims.ImsExternalCallState; import com.android.internal.telephony.Call; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; import android.os.Bundle; import android.telecom.PhoneAccountHandle; import android.util.ArrayMap; import android.util.Log; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Responsible for tracking external calls known to the system. */ public class ImsExternalCallTracker { public final static String TAG = "ImsExternalCallTracker"; /** * Extra key used when informing telecom of a new external call using the * {@link android.telecom.TelecomManager#addNewUnknownCall(PhoneAccountHandle, Bundle)} API. * Used to ensure that when Telecom requests the {@link android.telecom.ConnectionService} to * create the connection for the unknown call that we can determine which * {@link ImsExternalConnection} in {@link #mExternalConnections} is the one being requested. */ public final static String EXTRA_IMS_EXTERNAL_CALL_ID = "android.telephony.ImsExternalCallTracker.extra.EXTERNAL_CALL_ID"; /** * Contains a list of the external connections known by the ImsPhoneCallTracker. These are * connections which originated from a dialog event package and reside on another device. * Used in multi-endpoint (VoLTE for internet connected endpoints) scenarios. */ private Map<Integer, ImsExternalConnection> mExternalConnections = new ArrayMap<Integer, ImsExternalConnection>(); private ImsPhone mPhone; public ImsExternalCallTracker(ImsPhone phone) { mPhone = phone; } /** * Called when the IMS stack receives a new dialog event package. Triggers the creation and * update of {@link ImsExternalConnection}s to represent the dialogs in the dialog event * package data. * * @param externalCallStates the {@link ImsExternalCallState} information for the dialog event * package. */ public void refreshExternalCallState(List<ImsExternalCallState> externalCallStates) { Log.d(TAG, "refreshExternalCallState: depSize = " + externalCallStates.size()); // Check to see if any call Ids are no longer present in the external call state. If they // are, the calls are terminated and should be removed. Iterator<Map.Entry<Integer, ImsExternalConnection>> connectionIterator = mExternalConnections.entrySet().iterator(); boolean wasCallRemoved = false; while (connectionIterator.hasNext()) { Map.Entry<Integer, ImsExternalConnection> entry = connectionIterator.next(); int callId = entry.getKey().intValue(); if (!containsCallId(externalCallStates, callId)) { ImsExternalConnection externalConnection = entry.getValue(); externalConnection.setTerminated(); connectionIterator.remove(); wasCallRemoved = true; } } // If one or more calls were removed, trigger a notification that will cause the // TelephonyConnection instancse to refresh their state with Telecom. if (wasCallRemoved) { mPhone.notifyPreciseCallStateChanged(); } // Check for new calls, and updates to existing ones. for (ImsExternalCallState callState : externalCallStates) { if (!mExternalConnections.containsKey(callState.getCallId())) { Log.d(TAG, "refreshExternalCallState: got = " + callState); // If there is a new entry and it is already terminated, don't bother adding it to // telecom. if (callState.getCallState() != ImsExternalCallState.CALL_STATE_CONFIRMED) { continue; } createExternalConnection(callState); } else{ updateExistingConnection(mExternalConnections.get(callState.getCallId()), callState); } } } /** * Finds an external connection given a call Id. * * @param callId The call Id. * @return The {@link Connection}, or {@code null} if no match found. */ public Connection getConnectionById(int callId) { return mExternalConnections.get(callId); } /** * Given an {@link ImsExternalCallState} instance obtained from a dialog event package, * creates a new instance of {@link ImsExternalConnection} to represent the connection, and * initiates the addition of the new call to Telecom as an unknown call. * * @param state External call state from a dialog event package. */ private void createExternalConnection(ImsExternalCallState state) { Log.i(TAG, "createExternalConnection"); ImsExternalConnection connection = new ImsExternalConnection(mPhone, state.getCallId(), /* Dialog event package call id */ state.getAddress().getSchemeSpecificPart() /* phone number */, state.isCallPullable()); // Add to list of tracked connections. mExternalConnections.put(connection.getCallId(), connection); // Note: The notification of unknown connection is ultimately handled by // PstnIncomingCallNotifier#addNewUnknownCall. That method will ensure that an extra is set // containing the ImsExternalConnection#mCallId so that we have a means of reconciling which // unknown call was added. mPhone.notifyUnknownConnection(connection); } /** * Given an existing {@link ImsExternalConnection}, applies any changes found found in a * {@link ImsExternalCallState} instance received from a dialog event package to the connection. * * @param connection The connection to apply changes to. * @param state The new dialog state for the connection. */ private void updateExistingConnection(ImsExternalConnection connection, ImsExternalCallState state) { Call.State existingState = connection.getState(); Call.State newState = state.getCallState() == ImsExternalCallState.CALL_STATE_CONFIRMED ? Call.State.ACTIVE : Call.State.DISCONNECTED; if (existingState != newState) { if (newState == Call.State.ACTIVE) { connection.setActive(); } else { connection.setTerminated(); mExternalConnections.remove(connection); mPhone.notifyPreciseCallStateChanged(); } } connection.setIsPullable(state.isCallPullable()); } /** * Determines if a list of call states obtained from a dialog event package contacts an existing * call Id. * * @param externalCallStates The dialog event package state information. * @param callId The call Id. * @return {@code true} if the state information contains the call Id, {@code false} otherwise. */ private boolean containsCallId(List<ImsExternalCallState> externalCallStates, int callId) { for (ImsExternalCallState state : externalCallStates) { if (state.getCallId() == callId) { return true; } } return false; } }