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

Commit dd68bc36 authored by Hall Liu's avatar Hall Liu
Browse files

Add support for RTT calls (part 1)

Adds logic for handling RTT call initiation and communication with the
InCallService and the ConnectionService and includes changes to the
testapps that exercise this functionality. This change handles RTT
initiation from the beginning of a call.

Change-Id: I3d713b662a100b2e0ad817b92005f044bcc60c62
Test: manual, through testapps
parent b2d91514
Loading
Loading
Loading
Loading
+83 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.Trace;
import android.provider.ContactsContract.Contacts;
@@ -34,6 +35,7 @@ import android.telecom.GatewayInfo;
import android.telecom.Log;
import android.telecom.Logging.EventManager;
import android.telecom.ParcelableConnection;
import android.telecom.ParcelableRttCall;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.Response;
@@ -50,6 +52,7 @@ import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.Preconditions;

import java.io.IOException;
import java.lang.String;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -82,6 +85,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
    /** Identifies extras changes which originated from an incall service. */
    public static final int SOURCE_INCALL_SERVICE = 2;

    private static final int RTT_PIPE_READ_SIDE_INDEX = 0;
    private static final int RTT_PIPE_WRITE_SIDE_INDEX = 1;
    /**
     * Listener for events on the call.
     */
@@ -97,7 +102,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
        void onPostDialWait(Call call, String remaining);
        void onPostDialChar(Call call, char nextChar);
        void onConnectionCapabilitiesChanged(Call call);
        void onConnectionPropertiesChanged(Call call);
        void onConnectionPropertiesChanged(Call call, boolean didRttChange);
        void onParentChanged(Call call);
        void onChildrenChanged(Call call);
        void onCannedSmsResponsesLoaded(Call call);
@@ -142,7 +147,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
        @Override
        public void onConnectionCapabilitiesChanged(Call call) {}
        @Override
        public void onConnectionPropertiesChanged(Call call) {}
        public void onConnectionPropertiesChanged(Call call, boolean didRttChange) {}
        @Override
        public void onParentChanged(Call call) {}
        @Override
@@ -406,6 +411,20 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
     */
    private String mOriginalConnectionId;

    /**
     * Two pairs of {@link android.os.ParcelFileDescriptor}s that handle RTT text communication
     * between the in-call app and the connection service. If both non-null, this call should be
     * treated as an RTT call.
     * Each array should be of size 2. First one is the read side and the second one is the write
     * side.
     */
    private ParcelFileDescriptor[] mInCallToConnectionServiceStreams;
    private ParcelFileDescriptor[] mConnectionServiceToInCallStreams;
    /**
     * Integer constant from {@link android.telecom.Call.RttCall}. Describes the current RTT mode.
     */
    private int mRttMode;

    /**
     * Persists the specified parameters and initializes the new instance.
     *
@@ -1087,11 +1106,17 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
            connectionProperties &= ~Connection.PROPERTY_SELF_MANAGED;
        }

        if (mConnectionProperties != connectionProperties) {
        int changedProperties = mConnectionProperties ^ connectionProperties;

        if (changedProperties != 0) {
            int previousProperties = mConnectionProperties;
            mConnectionProperties = connectionProperties;
            setIsRttCall((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
                    Connection.PROPERTY_IS_RTT);
            boolean didRttChange =
                    (changedProperties & Connection.PROPERTY_IS_RTT) == Connection.PROPERTY_IS_RTT;
            for (Listener l : mListeners) {
                l.onConnectionPropertiesChanged(this);
                l.onConnectionPropertiesChanged(this, didRttChange);
            }

            boolean wasExternal = (previousProperties & Connection.PROPERTY_IS_EXTERNAL_CALL)
@@ -1105,7 +1130,6 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
                for (Listener l : mListeners) {
                    l.onExternalCallChanged(this, isExternal);
                }

            }

            mAnalytics.addCallProperties(mConnectionProperties);
@@ -2003,6 +2027,55 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
        return mSpeakerphoneOn;
    }

    public void setIsRttCall(boolean shouldBeRtt) {
        boolean areStreamsInitialized = mInCallToConnectionServiceStreams != null
                && mConnectionServiceToInCallStreams != null;
        if (shouldBeRtt && !areStreamsInitialized) {
            try {
                mInCallToConnectionServiceStreams = ParcelFileDescriptor.createReliablePipe();
                mConnectionServiceToInCallStreams = ParcelFileDescriptor.createReliablePipe();
            } catch (IOException e) {
                Log.e(this, e, "Failed to create pipes for RTT call.");
            }
        } else if (!shouldBeRtt && areStreamsInitialized) {
            closeRttPipes();
            mInCallToConnectionServiceStreams = null;
            mConnectionServiceToInCallStreams = null;
        }
    }

    public void closeRttPipes() {
        // TODO: may defer this until call is removed?
    }

    public boolean isRttCall() {
        return (mConnectionProperties & Connection.PROPERTY_IS_RTT) == Connection.PROPERTY_IS_RTT;
    }

    public ParcelFileDescriptor getCsToInCallRttPipeForCs() {
        return mConnectionServiceToInCallStreams == null ? null
                : mConnectionServiceToInCallStreams[RTT_PIPE_WRITE_SIDE_INDEX];
    }

    public ParcelFileDescriptor getInCallToCsRttPipeForCs() {
        return mInCallToConnectionServiceStreams == null ? null
                : mInCallToConnectionServiceStreams[RTT_PIPE_READ_SIDE_INDEX];
    }

    public ParcelFileDescriptor getCsToInCallRttPipeForInCall() {
        return mConnectionServiceToInCallStreams == null ? null
                : mConnectionServiceToInCallStreams[RTT_PIPE_READ_SIDE_INDEX];
    }

    public ParcelFileDescriptor getInCallToCsRttPipeForInCall() {
        return mInCallToConnectionServiceStreams == null ? null
                : mInCallToConnectionServiceStreams[RTT_PIPE_WRITE_SIDE_INDEX];
    }

    public int getRttMode() {
        return mRttMode;
    }

    /**
     * Sets a video call provider for the call.
     */
@@ -2221,6 +2294,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable {
        return mCallDataUsage;
    }

    public void setRttMode(int mode) {
        mRttMode = mode;
        // TODO: hook this up to CallAudioManager
    }

    /**
     * Returns true if the call is outgoing and the NEW_OUTGOING_CALL ordered broadcast intent
     * has come back to telecom and was processed.
+28 −3
Original line number Diff line number Diff line
@@ -720,6 +720,12 @@ public class CallsManager extends Call.ListenerBase
        if (phoneAccount != null) {
            call.setIsSelfManaged(phoneAccount.isSelfManaged());
        }
        if (extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
            if (phoneAccount != null &&
                    phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
                call.setIsRttCall(true);
            }
        }

        call.initAnalytics();
        if (getForegroundCall() != null) {
@@ -854,9 +860,9 @@ public class CallsManager extends Call.ListenerBase
            isReusedCall = false;
        }

        // Set the video state on the call early so that when it is added to the InCall UI the UI
        // knows to configure itself as a video call immediately.
        if (extras != null) {
            // Set the video state on the call early so that when it is added to the InCall UI the
            // UI knows to configure itself as a video call immediately.
            int videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
                    VideoProfile.STATE_AUDIO_ONLY);

@@ -956,8 +962,16 @@ public class CallsManager extends Call.ListenerBase
            call.setState(
                    CallState.CONNECTING,
                    phoneAccountHandle == null ? "no-handle" : phoneAccountHandle.toString());
            PhoneAccount accountToUse =
                    mPhoneAccountRegistrar.getPhoneAccount(phoneAccountHandle, initiatingUser);
            if (extras != null
                    && extras.getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
                if (accountToUse != null
                        && accountToUse.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
                    call.setIsRttCall(true);
                }
            }
        }

        setIntentExtrasAndStartTime(call, extras);

        // Do not add the call if it is a potential MMI code.
@@ -1401,6 +1415,16 @@ public class CallsManager extends Call.ListenerBase
        } else {
            call.setTargetPhoneAccount(account);

            if (call.getIntentExtras()
                    .getBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, false)) {
                PhoneAccount realPhoneAccount =
                        mPhoneAccountRegistrar.getPhoneAccountUnchecked(account);
                if (realPhoneAccount != null
                        && realPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_RTT)) {
                    call.setIsRttCall(true);
                }
            }

            if (!call.isNewOutgoingCallIntentBroadcastDone()) {
                return;
            }
@@ -1829,6 +1853,7 @@ public class CallsManager extends Call.ListenerBase
        call.setParentCall(null);  // need to clean up parent relationship before destroying.
        call.removeListener(this);
        call.clearConnectionService();
        // TODO: clean up RTT pipes

        boolean shouldNotify = false;
        if (mCalls.contains(call)) {
+20 −14
Original line number Diff line number Diff line
@@ -861,7 +861,7 @@ public class ConnectionServiceWrapper extends ServiceBinder {
                }

                Log.addEvent(call, LogUtils.Events.START_CONNECTION, Log.piiHandle(call.getHandle()));
                try {

                // For self-managed incoming calls, if there is another ongoing call Telecom is
                // responsible for showing a UI to ask the user if they'd like to answer this
                // new incoming call.
@@ -869,16 +869,22 @@ public class ConnectionServiceWrapper extends ServiceBinder {
                        !mCallsManager.hasCallsForOtherPhoneAccount(
                                call.getTargetPhoneAccount());

                ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
                        .setAccountHandle(call.getTargetPhoneAccount())
                        .setAddress(call.getHandle())
                        .setExtras(call.getIntentExtras())
                        .setVideoState(call.getVideoState())
                        .setTelecomCallId(callId)
                        .setShouldShowIncomingCallUi(shouldShowIncomingCallUI)
                        .setRttPipeFromInCall(call.getInCallToCsRttPipeForCs())
                        .setRttPipeToInCall(call.getCsToInCallRttPipeForCs())
                        .build();

                try {
                    mServiceInterface.createConnection(
                            call.getConnectionManagerPhoneAccount(),
                            callId,
                            new ConnectionRequest(
                                    call.getTargetPhoneAccount(),
                                    call.getHandle(),
                                    extras,
                                    call.getVideoState(),
                                    callId,
                                    shouldShowIncomingCallUI),
                            connectionRequest,
                            call.shouldAttachToExistingConnection(),
                            call.isUnknown(),
                            Log.getExternalSession());
+68 −0
Original line number Diff line number Diff line
@@ -494,4 +494,72 @@ class InCallAdapter extends IInCallAdapter.Stub {
             Log.endSession();
        }
    }

    @Override
    public void sendRttRequest() {
        try {
            Log.startSession("ICA.sRR");
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    // TODO
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void respondToRttRequest(int id, boolean accept) {
        try {
            Log.startSession("ICA.rTRR");
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    // TODO
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void stopRtt() {
        try {
            Log.startSession("ICA.sRTT");
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    // TODO
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }

    @Override
    public void setRttMode(int mode) {
        try {
            Log.startSession("ICA.sRM");
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    // TODO
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        } finally {
            Log.endSession();
        }
    }
}
+44 −10
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
@@ -76,6 +77,7 @@ public final class InCallController extends CallsManagerListenerBase {
        public void setListener(Listener l) {
            mListener = l;
        }
        public InCallServiceInfo getInfo() { return null; }
        public void dump(IndentingPrintWriter pw) {}
    }

@@ -210,6 +212,11 @@ public final class InCallController extends CallsManagerListenerBase {
            return mIsConnected;
        }

        @Override
        public InCallServiceInfo getInfo() {
            return mInCallServiceInfo;
        }

        @Override
        public void disconnect() {
            if (mIsConnected) {
@@ -318,6 +325,14 @@ public final class InCallController extends CallsManagerListenerBase {
            }
        }

        @Override
        public InCallServiceInfo getInfo() {
            if (mIsProxying) {
                return mSubConnection.getInfo();
            } else {
                return super.getInfo();
            }
        }
        @Override
        protected void onDisconnected() {
            // Save this here because super.onDisconnected() could force us to explicitly
@@ -426,6 +441,11 @@ public final class InCallController extends CallsManagerListenerBase {
            }
        }

        @Override
        public InCallServiceInfo getInfo() {
            return mCurrentConnection.getInfo();
        }

        @Override
        public void dump(IndentingPrintWriter pw) {
            pw.println("Car Swapping ICS");
@@ -490,8 +510,8 @@ public final class InCallController extends CallsManagerListenerBase {
        }

        @Override
        public void onConnectionPropertiesChanged(Call call) {
            updateCall(call);
        public void onConnectionPropertiesChanged(Call call, boolean didRttChange) {
            updateCall(call, false /* includeVideoProvider */, didRttChange);
        }

        @Override
@@ -501,7 +521,7 @@ public final class InCallController extends CallsManagerListenerBase {

        @Override
        public void onVideoCallProviderChanged(Call call) {
            updateCall(call, true /* videoProviderChanged */);
            updateCall(call, true /* videoProviderChanged */, false);
        }

        @Override
@@ -660,12 +680,15 @@ public final class InCallController extends CallsManagerListenerBase {
                    continue;
                }

                // Only send the RTT call if it's a UI in-call service
                boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());

                componentsUpdated.add(info.getComponentName());
                IInCallService inCallService = entry.getValue();

                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported());
                        info.isExternalCallsSupported(), includeRttCall);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
@@ -728,9 +751,12 @@ public final class InCallController extends CallsManagerListenerBase {
                componentsUpdated.add(info.getComponentName());
                IInCallService inCallService = entry.getValue();

                // Only send the RTT call if it's a UI in-call service
                boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());

                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported());
                        info.isExternalCallsSupported(), includeRttCall);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
@@ -746,7 +772,8 @@ public final class InCallController extends CallsManagerListenerBase {
                    false /* includeVideoProvider */,
                    mCallsManager.getPhoneAccountRegistrar(),
                    false /* supportsExternalCalls */,
                    android.telecom.Call.STATE_DISCONNECTED /* overrideState */);
                    android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
                    false /* includeRttCall */);

            Log.i(this, "Removing external call %s ==> %s", call, parcelableCall);
            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
@@ -1138,6 +1165,9 @@ public final class InCallController extends CallsManagerListenerBase {
                    continue;
                }

                // Only send the RTT call if it's a UI in-call service
                boolean includeRttCall = info.equals(mInCallServiceConnection.getInfo());

                // Track the call if we don't already know about it.
                addCall(call);
                numCallsSent += 1;
@@ -1145,7 +1175,8 @@ public final class InCallController extends CallsManagerListenerBase {
                        call,
                        true /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported()));
                        info.isExternalCallsSupported(),
                        includeRttCall));
            } catch (RemoteException ignored) {
            }
        }
@@ -1176,7 +1207,7 @@ public final class InCallController extends CallsManagerListenerBase {
     * @param call The {@link Call}.
     */
    private void updateCall(Call call) {
        updateCall(call, false /* videoProviderChanged */);
        updateCall(call, false /* videoProviderChanged */, false);
    }

    /**
@@ -1185,8 +1216,10 @@ public final class InCallController extends CallsManagerListenerBase {
     * @param call The {@link Call}.
     * @param videoProviderChanged {@code true} if the video provider changed, {@code false}
     *      otherwise.
     * @param rttInfoChanged {@code true} if any information about the RTT session changed,
     * {@code false} otherwise.
     */
    private void updateCall(Call call, boolean videoProviderChanged) {
    private void updateCall(Call call, boolean videoProviderChanged, boolean rttInfoChanged) {
        if (!mInCallServices.isEmpty()) {
            Log.i(this, "Sending updateCall %s", call);
            List<ComponentName> componentsUpdated = new ArrayList<>();
@@ -1200,7 +1233,8 @@ public final class InCallController extends CallsManagerListenerBase {
                        call,
                        videoProviderChanged /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported());
                        info.isExternalCallsSupported(),
                        rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()));
                ComponentName componentName = info.getComponentName();
                IInCallService inCallService = entry.getValue();
                componentsUpdated.add(componentName);
Loading