Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92ac5c2d authored by Tyler Gunn's avatar Tyler Gunn Committed by Hariprasad Jayakumar
Browse files

Creating connections for conference event package participants.

- Add "addExistingCall" method to Connection service wrapper to handle
the creation of new calls for connections which already exist in telephony.
- Fixed but in setIsConference message where an isValidCallId check made
outside of the handler would result in a newly added call NOT being
marked as conferenced due to a race condition.  The MSG_SET_IS_CONFERENCED
handler already checks if the call exists before performing its operation.

Bug: 18057361
Change-Id: I2348c8e6985cd831f2cae56b37dfcb33bae014a8

Make add-call a global property of telecom. (2/4)

ADD_CALL didn't make sense as a property of Connection or Call.
This changes it to be a global property instead.

Bug: 18285352
Change-Id: I5189e114e74dba2d81d74c6d24cf5b17f1e0922a

Set appropriate capabilities to TestConference

This allows the "Manage conference" screen to show up correctly
for test conference calls

Bug: 18269622
Change-Id: I8467654a8158c5da8c354057f613f122b22a0ed3

Create IMSConference to represent IMS conference calls.

- Removing check in ConnectionServiceWrapper which would prevent adding
a new confernece with no calls in it; an IMS conference by default will
have no calls.

Bug: 18200934
Change-Id: I2e70b9350e779310e8c4ee8e91bc8020b126bcfa

Change-Id: I2e70b9350e779310e8c4ee8e91bc8020b126bcfa
parent 3aab3351
Loading
Loading
Loading
Loading
+94 −46
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.telecom.CallState;
import android.telecom.DisconnectCause;
import android.telecom.GatewayInfo;
import android.telecom.ParcelableConference;
import android.telecom.ParcelableConnection;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.PhoneCapabilities;
@@ -80,6 +81,7 @@ public final class CallsManager extends Call.ListenerBase {
        void onIsVoipAudioModeChanged(Call call);
        void onVideoStateChanged(Call call);
        void onCallSubstateChanged(Call call);
        void onCanAddCallChanged(boolean canAddCall);
    }

    /**
@@ -95,13 +97,14 @@ public final class CallsManager extends Call.ListenerBase {
    private static final int MAXIMUM_OUTGOING_CALLS = 1;
    private static final int MAXIMUM_DSDA_LIVE_CALLS = 2;
    private static final int MAXIMUM_DSDA_HOLD_CALLS = 2;

    private static final int[] LIVE_CALL_STATES =
            {CallState.CONNECTING, CallState.DIALING, CallState.ACTIVE};
    private static final int MAXIMUM_TOP_LEVEL_CALLS = 2;

    private static final int[] OUTGOING_CALL_STATES =
            {CallState.CONNECTING, CallState.DIALING};

    private static final int[] LIVE_CALL_STATES =
            {CallState.CONNECTING, CallState.DIALING, CallState.ACTIVE};

    /**
     * The main call repository. Keeps an instance of all live calls. New incoming and outgoing
     * calls are added to the map and removed when the calls move to the disconnected state.
@@ -133,6 +136,8 @@ public final class CallsManager extends Call.ListenerBase {
    private final MissedCallNotifier mMissedCallNotifier;
    private final Set<Call> mLocallyDisconnectingCalls = new HashSet<>();

    private boolean mCanAddCall = true;

    /**
     * The call the user is currently interacting with. This is the call that should have audio
     * focus and be visible in the in-call UI.
@@ -286,7 +291,7 @@ public final class CallsManager extends Call.ListenerBase {
    @Override
    public void onParentChanged(Call call) {
        // parent-child relationship affects which call should be foreground, so do an update.
        updateForegroundCall();
        updateCallsManagerState();
        for (CallsManagerListener listener : mListeners) {
            listener.onIsConferencedChanged(call);
        }
@@ -295,7 +300,7 @@ public final class CallsManager extends Call.ListenerBase {
    @Override
    public void onChildrenChanged(Call call) {
        // parent-child relationship affects which call should be foreground, so do an update.
        updateForegroundCall();
        updateCallsManagerState();
        for (CallsManagerListener listener : mListeners) {
            listener.onIsConferencedChanged(call);
        }
@@ -1015,26 +1020,31 @@ public final class CallsManager extends Call.ListenerBase {
    }

    /**
     * Checks to see if the specified call is the only high-level call and if so, enable the
     * "Add-call" button. We allow you to add a second call but not a third or beyond.
     *
     * @param call The call to test for add-call.
     * @return Whether the add-call feature should be enabled for the call.
     * Returns true if telecom supports adding another top-level call.
     */
    protected boolean isAddCallCapable(Call call) {
        if (call.getParentCall() != null) {
            // Never true for child calls.
    boolean canAddCall() {
        int count = 0;
        for (Call call : mCalls) {
            if (call.isEmergencyCall()) {
                // We never support add call if one of the calls is an emergency call.
                return false;
            } else if (call.getParentCall() == null) {
                count++;
            }

        // Use canManageConference as a mechanism to check if the call is CDMA.
        // Disable "Add Call" for CDMA calls which are conference calls.
        boolean canManageConference = PhoneCapabilities.MANAGE_CONFERENCE
                == (call.getCallCapabilities() & PhoneCapabilities.MANAGE_CONFERENCE);
        if (call.isConference() && !canManageConference) {
            // We do not check states for canAddCall. We treat disconnected calls the same
            // and wait until they are removed instead. If we didn't count disconnected calls,
            // we could put InCallServices into a state where they are showing two calls but
            // also support add-call. Technically it's right, but overall looks better (UI-wise)
            // and acts better if we wait until the call is removed.
            if (count >= MAXIMUM_TOP_LEVEL_CALLS) {
                return false;
            }

            // Commented below block as 'Add Call' button was still missing in single
            // sim VoLTE conference cases even after increasing MAXIMUM_TOP_LEVEL_CALLS
            // TODO: Check if the below block needs changes to cover MSIM cases
            /*
            PhoneAccountHandle ph = call.getTargetPhoneAccount();
            // Loop through all the other calls and there exists a top level (has no parent) call
            // that is not the specified call, return false.
@@ -1049,6 +1059,7 @@ public final class CallsManager extends Call.ListenerBase {

            if ((call.getState() != CallState.ACTIVE) && (call.getState() != CallState.ON_HOLD)) {
                return false;
            } */
        }
        return true;
    }
@@ -1236,7 +1247,7 @@ public final class CallsManager extends Call.ListenerBase {
        for (CallsManagerListener listener : mListeners) {
            listener.onCallAdded(call);
        }
        updateForegroundCall();
        updateCallsManagerState();
    }

    private void removeCall(Call call) {
@@ -1257,15 +1268,7 @@ public final class CallsManager extends Call.ListenerBase {
            for (CallsManagerListener listener : mListeners) {
                listener.onCallRemoved(call);
            }
            updateForegroundCall();
        }

        // Now that a call has been removed, other calls may gain new call capabilities (for
        // example, if only one call is left, it is now add-call capable again). Trigger the
        // recalculation of the call's current capabilities by forcing an update. (See
        // InCallController.toParcelableCall()).
        for (Call otherCall : mCalls) {
            otherCall.setCallCapabilities(otherCall.getCallCapabilities(), true /* forceUpdate */);
            updateCallsManagerState();
        }
    }

@@ -1297,7 +1300,7 @@ public final class CallsManager extends Call.ListenerBase {
                for (CallsManagerListener listener : mListeners) {
                    listener.onCallStateChanged(call, oldState, newState);
                }
                updateForegroundCall();
                updateCallsManagerState();
            }
        }
        manageMSimInCallTones(false);
@@ -1399,6 +1402,21 @@ public final class CallsManager extends Call.ListenerBase {
        }
    }

    private void updateCanAddCall() {
        boolean newCanAddCall = canAddCall();
        if (newCanAddCall != mCanAddCall) {
            mCanAddCall = newCanAddCall;
            for (CallsManagerListener listener : mListeners) {
                listener.onCanAddCallChanged(mCanAddCall);
            }
        }
    }

    private void updateCallsManagerState() {
        updateForegroundCall();
        updateCanAddCall();
    }

    private boolean isPotentialMMICode(Uri handle) {
        return (handle != null && handle.getSchemeSpecificPart() != null
                && handle.getSchemeSpecificPart().contains("#"));
@@ -1435,7 +1453,7 @@ public final class CallsManager extends Call.ListenerBase {
        int count = 0;
        for (int state : states) {
            for (Call call : mCalls) {
                if (call.getState() == state) {
                if (call.getParentCall() == null && call.getState() == state) {
                    count++;
                }
            }
@@ -1593,6 +1611,36 @@ public final class CallsManager extends Call.ListenerBase {
        return true;
    }

    /**
     * Creates a new call for an existing connection.
     *
     * @param callId The id of the new call.
     * @param connection The connection information.
     * @return The new call.
     */
    Call createCallForExistingConnection(String callId, ParcelableConnection connection) {
        Call call = new Call(
                mContext,
                mConnectionServiceRepository,
                connection.getHandle() /* handle */,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                connection.getPhoneAccount(), /* targetPhoneAccountHandle */
                false /* isIncoming */,
                false /* isConference */);

        setCallState(call, Call.getStateFromConnectionState(connection.getState()));
        call.setConnectTimeMillis(System.currentTimeMillis());
        call.setCallCapabilities(connection.getCapabilities());
        call.setCallerDisplayName(connection.getCallerDisplayName(),
                connection.getCallerDisplayNamePresentation());

        call.addListener(this);
        addCall(call);

        return call;
    }

    /**
     * Dumps the state of the {@link CallsManager}.
     *
+4 −0
Original line number Diff line number Diff line
@@ -80,4 +80,8 @@ class CallsManagerListenerBase implements CallsManager.CallsManagerListener {
    @Override
    public void onCallSubstateChanged(Call call) {
    }

    @Override
    public void onCanAddCallChanged(boolean canAddCall) {
    }
}
+27 −20
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
    private static final int MSG_SET_DISCONNECTED_WITH_SUPP_NOTIFICATION = 22;
    private static final int MSG_SET_PHONE_ACCOUNT = 23;
    private static final int MSG_SET_CALL_SUBSTATE = 24;
    private static final int MSG_ADD_EXISTING_CONNECTION = 25;

    private final Handler mHandler = new Handler() {
        @Override
@@ -239,20 +240,6 @@ final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
                        ParcelableConference parcelableConference =
                                (ParcelableConference) args.arg2;

                        // Make sure that there's at least one valid call. For remote connections
                        // we'll get a add conference msg from both the remote connection service
                        // and from the real connection service.
                        boolean hasValidCalls = false;
                        for (String callId : parcelableConference.getConnectionIds()) {
                            if (mCallIdMapper.getCall(callId) != null) {
                                hasValidCalls = true;
                            }
                        }
                        if (!hasValidCalls) {
                            Log.d(this, "Attempting to add a conference with no valid calls");
                            break;
                        }

                        // need to create a new Call
                        Call conferenceCall = mCallsManager.createConferenceCall(
                                null, parcelableConference);
@@ -416,6 +403,19 @@ final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
                    }
                    break;
                }
                case MSG_ADD_EXISTING_CONNECTION: {
                    SomeArgs args = (SomeArgs) msg.obj;
                    try {
                        String callId = (String)args.arg1;
                        ParcelableConnection connection = (ParcelableConnection)args.arg2;
                        Call existingCall = mCallsManager.createCallForExistingConnection(callId,
                                connection);
                        mCallIdMapper.addCall(existingCall, callId);
                        existingCall.setConnectionService(ConnectionServiceWrapper.this);
                    } finally {
                        args.recycle();
                    }
                }
            }
        }
    };
@@ -549,13 +549,11 @@ final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
        @Override
        public void setIsConferenced(String callId, String conferenceCallId) {
            logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
            if (mCallIdMapper.isValidCallId(callId)) {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = callId;
            args.arg2 = conferenceCallId;
            mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
        }
        }

        @Override
        public void addConferenceCall(String callId, ParcelableConference parcelableConference) {
@@ -669,6 +667,15 @@ final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
                    MSG_SET_CALL_SUBSTATE, callSubstate, 0, callId).sendToTarget();
            }
        }

        @Override
        public void addExistingConnection(String callId, ParcelableConnection connection) {
            logIncoming("addExistingConnection  %s %s", callId, connection);
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = callId;
            args.arg2 = connection;
            mHandler.obtainMessage(MSG_ADD_EXISTING_CONNECTION, args).sendToTarget();
        }
    }

    private final Adapter mAdapter = new Adapter();
+13 −4
Original line number Diff line number Diff line
@@ -218,6 +218,19 @@ public final class InCallController extends CallsManagerListenerBase {
        }
    }

    @Override
    public void onCanAddCallChanged(boolean canAddCall) {
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "onCanAddCallChanged : %b", canAddCall);
            for (IInCallService inCallService : mInCallServices.values()) {
                try {
                    inCallService.onCanAddCallChanged(canAddCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

    void onPostDialWait(Call call, String remaining) {
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "Calling onPostDialWait, remaining = %s", remaining);
@@ -438,14 +451,10 @@ public final class InCallController extends CallsManagerListenerBase {
        String callId = mCallIdMapper.getCallId(call);

        int capabilities = call.getCallCapabilities();
        if (CallsManager.getInstance().isAddCallCapable(call)) {
            capabilities |= PhoneCapabilities.ADD_CALL;
        }

        // Disable mute and add call for emergency calls.
        if (call.isEmergencyCall()) {
            capabilities &= ~PhoneCapabilities.MUTE;
            capabilities &= ~PhoneCapabilities.ADD_CALL;
        }

        int properties = call.isConference() ? CallProperties.CONFERENCE : 0;
+5 −2
Original line number Diff line number Diff line
@@ -77,7 +77,11 @@ public class TestConnectionService extends ConnectionService {

        public TestConference(Connection a, Connection b) {
            super(null);

            setCapabilities(
                    PhoneCapabilities.SUPPORT_HOLD |
                    PhoneCapabilities.HOLD |
                    PhoneCapabilities.MUTE |
                    PhoneCapabilities.MANAGE_CONFERENCE);
            addConnection(a);
            addConnection(b);

@@ -135,7 +139,6 @@ public class TestConnectionService extends ConnectionService {
            // Assume all calls are video capable.
            int capabilities = getCallCapabilities();
            capabilities |= PhoneCapabilities.SUPPORTS_VT_LOCAL;
            capabilities |= PhoneCapabilities.ADD_CALL;
            capabilities |= PhoneCapabilities.MUTE;
            capabilities |= PhoneCapabilities.SUPPORT_HOLD;
            capabilities |= PhoneCapabilities.HOLD;