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

Commit 67268ff1 authored by Ashit Sood's avatar Ashit Sood Committed by Bruno Martins
Browse files

IMS: RTT feature changes

Implement RTT feature changes

IMS: Allow sending RTT message in Upon Request mode
Scenario -
-Device is in Upon Request mode
-Device receives RTT call and call is now active
-User tries to send RTT message
-Allow sending the message in this mode
-Remove the full mode check

IMS: Add null check for RttTextStream

RttTextStream can be null if RTT operations are not
performed from UI. So add a null check to prevent
NPE when the operations are performed through adb
commands.

IMS: Answer the call as RTT only if call is offered as RTT

Waiting call is answered as RTT call, even if the call is offered
like a regular waiting call if RTT UI option is on.
To fix this, check if the call profile is having RTT mode before
answering it as RTT call.

IMS: Handle RTT Downgrade request and response

Handle RTT Downgrade request and response.

Change-Id: Ied8086f04ec76ad2cd3712ff902a64d747deae1f
CRs-Fixed: 2178403
parent a304dcdf
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    android.hardware.radio-V1.2-java \
    android.hardware.radio.config-V1.0-java \
    android.hardware.radio.deprecated-V1.0-java \
    android.hidl.base-V1.0-java
    android.hidl.base-V1.0-java \
    ims-ext-common

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := telephony-common
+207 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
@@ -70,8 +71,10 @@ import android.telephony.ims.ImsCallForwardInfo;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsSsInfo;
import android.telephony.ims.ImsStreamMediaProfile;
import android.text.TextUtils;

import com.android.ims.ImsCall;
import com.android.ims.ImsEcbm;
import com.android.ims.ImsEcbmStateListener;
import com.android.ims.ImsException;
@@ -98,6 +101,9 @@ import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.util.NotificationChannelController;

import org.codeaurora.ims.QtiCallConstants;
import org.codeaurora.ims.utils.QtiImsExtUtils;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -282,6 +288,14 @@ public class ImsPhone extends ImsPhoneBase {
        mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
        // Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED.
        // Settings provider or CarrierConfig may not be loaded now.

        // Register receiver for sending RTT text message and
        // for receving RTT Operation
        // .i.e.Upgrade Initiate, Upgrade accept, Upgrade reject
        IntentFilter filter = new IntentFilter();
        filter.addAction(QtiCallConstants.ACTION_SEND_RTT_TEXT);
        filter.addAction(QtiCallConstants.ACTION_RTT_OPERATION);
        mDefaultPhone.getContext().registerReceiver(mRttReceiver, filter);
    }

    //todo: get rid of this function. It is not needed since parentPhone obj never changes
@@ -301,6 +315,7 @@ public class ImsPhone extends ImsPhoneBase {
            mDefaultPhone.getServiceStateTracker().
                    unregisterForDataRegStateOrRatChanged(this);
            mDefaultPhone.unregisterForServiceStateChanged(this);
            mDefaultPhone.getContext().unregisterReceiver(mRttReceiver);
        }
    }

@@ -1829,6 +1844,198 @@ public class ImsPhone extends ImsPhoneBase {
        return tm.isNetworkRoaming();
    }

    private BroadcastReceiver mRttReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (QtiCallConstants.ACTION_SEND_RTT_TEXT.equals(intent.getAction())) {
                Rlog.d(LOG_TAG, "RTT: Received ACTION_SEND_RTT_TEXT");
                String data = intent.getStringExtra(QtiCallConstants.RTT_TEXT_VALUE);
                sendRttMessage(data);
            } else if (QtiCallConstants.ACTION_RTT_OPERATION.equals(intent.getAction())) {
                Rlog.d(LOG_TAG, "RTT: Received ACTION_RTT_OPERATION");
                int data = intent.getIntExtra(QtiCallConstants.RTT_OPERATION_TYPE, 0);
                checkIfModifyRequestOrResponse(data);
            } else {
                Rlog.d(LOG_TAG, "RTT: unknown intent");
            }
        }
    };

    /**
     * Sends Rtt message
     * Rtt Message can be sent only when -
     * operating mode is RTT_FULL and for non-VT calls only based on config
     *
     * @param data The Rtt text to be sent
     */
    public void sendRttMessage(String data) {
        if (!canProcessRttRequest() || !isFgCallActive()) {
            return;
        }

        // Check for empty message
        if (TextUtils.isEmpty(data)) {
            Rlog.d(LOG_TAG, "RTT: Text null");
            return;
        }

        ImsCall imsCall = getForegroundCall().getImsCall();
        if (imsCall == null) {
            Rlog.d(LOG_TAG, "RTT: imsCall null");
            return;
        }

        if (!isRttVtCallAllowed(imsCall)) {
            Rlog.d(LOG_TAG, "RTT: InCorrect mode");
            return;
        }

        Rlog.d(LOG_TAG, "RTT: sendRttMessage");
        imsCall.sendRttMessage(data);
    }

    /**
     * Sends RTT Upgrade request
     *
     * @param to: expected profile
     */
    public void sendRttModifyRequest(ImsCallProfile to) {
        Rlog.d(LOG_TAG, "RTT: sendRttModifyRequest");
        ImsCall imsCall = getForegroundCall().getImsCall();
        if (imsCall == null) {
            Rlog.d(LOG_TAG, "RTT: imsCall null");
            return;
        }

        imsCall.sendRttModifyRequest();
    }

    /**
     * Sends RTT Upgrade response
     *
     * @param data : response for upgrade
     */
    public void sendRttModifyResponse(int response) {
        ImsCall imsCall = getForegroundCall().getImsCall();
        if (imsCall == null) {
            Rlog.d(LOG_TAG, "RTT: imsCall null");
            return;
        }

        if (!isRttVtCallAllowed(imsCall)) {
            Rlog.d(LOG_TAG, "RTT: Not allowed for VT");
            return;
        }

        Rlog.d(LOG_TAG, "RTT: sendRttModifyResponse");
        imsCall.sendRttModifyResponse(mapRequestToResponse(response));
    }

    // Utility to check if the value coming in intent is for upgrade initiate or upgrade response
    private void checkIfModifyRequestOrResponse(int data) {
        if (!canProcessRttRequest() || !isFgCallActive()) {
            return;
        }

        Rlog.d(LOG_TAG, "RTT: checkIfModifyRequestOrResponse data =  " + data);
        switch (data) {
            case QtiCallConstants.RTT_UPGRADE_INITIATE:
                // Rtt Upgrade means enable Rtt
                packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_FULL);
                break;
            case QtiCallConstants.RTT_DOWNGRADE_INITIATE:
                // Rtt downrade means disable Rtt
                packRttModifyRequestToProfile(ImsStreamMediaProfile.RTT_MODE_DISABLED);
                break;
            case QtiCallConstants.RTT_UPGRADE_CONFIRM:
            case QtiCallConstants.RTT_UPGRADE_REJECT:
                sendRttModifyResponse(data);
                break;
        }
    }

    private void packRttModifyRequestToProfile(int data) {
        if (!canSendRttModifyRequest()) {
            Rlog.d(LOG_TAG, "RTT: cannot send rtt modify request");
            return;
        }

        ImsCallProfile fromProfile = getForegroundCall().getImsCall().getCallProfile();
        ImsCallProfile toProfile = fromProfile;
        toProfile.mMediaProfile = new ImsStreamMediaProfile(data);

        Rlog.d(LOG_TAG, "RTT: packRttModifyRequestToProfile");
        sendRttModifyRequest(toProfile);
    }

    private boolean canSendRttModifyRequest() {
        ImsCall imsCall = getForegroundCall().getImsCall();
        if (imsCall == null) {
            Rlog.d(LOG_TAG, "RTT: imsCall null");
            return false;
        }

        return true;
    }

    private boolean mapRequestToResponse(int response) {
        switch (response) {
            case QtiCallConstants.RTT_UPGRADE_CONFIRM:
                return true;
            case QtiCallConstants.RTT_UPGRADE_REJECT:
                return false;
            default:
                return false;
        }
    }

    /*
     * Returns true if Mode is RTT_FULL, false otherwise
     */
    private boolean isInFullRttMode() {
        int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
        Rlog.d(LOG_TAG, "RTT: isInFullRttMode mode = " + mode);
        return (mode == QtiCallConstants.RTT_MODE_FULL);
    }

    /*
     * Rtt for VT calls is not supported for certain operators
     * Check the config and process the request
     */
    public boolean isRttVtCallAllowed(ImsCall call) {
        int mode = QtiImsExtUtils.getRttOperatingMode(mContext);
        Rlog.d(LOG_TAG, "RTT: isRttVtCallAllowed mode = " + mode);

        if (call.getCallProfile().isVideoCall() &&
                !QtiImsExtUtils.isRttSupportedOnVtCalls(mPhoneId, mContext)) {
            return false;
        }
        return true;
    }

    public boolean canProcessRttRequest() {
        // Process only if Carrier supports RTT and RTT is on
        if (!(QtiImsExtUtils.isRttSupported(mPhoneId, mContext) &&
                    QtiImsExtUtils.isRttOn(mContext))) {
            Rlog.d(LOG_TAG, "RTT: canProcessRttRequest RTT is not supported/off");
            return false;
        }
        Rlog.d(LOG_TAG, "RTT: canProcessRttRequest rtt supported = " +
                QtiImsExtUtils.isRttSupported(mPhoneId, mContext) + ", is Rtt on = " +
                QtiImsExtUtils.isRttOn(mContext) + ", Rtt mode = " +
                QtiImsExtUtils.getRttOperatingMode(mContext));
        return true;
    }

    public boolean isFgCallActive() {
        // process the request only if foreground is active
        if (ImsPhoneCall.State.ACTIVE != getForegroundCall().getState()) {
            Rlog.d(LOG_TAG, "RTT: isFgCallActive fg call not active");
            return false;
        }
        return true;
    }

    @Override
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        pw.println("ImsPhone extends:");
+54 −3
Original line number Diff line number Diff line
@@ -101,6 +101,9 @@ import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
import com.android.server.net.NetworkStatsService;

import org.codeaurora.ims.QtiCallConstants;
import org.codeaurora.ims.utils.QtiImsExtUtils;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -1213,6 +1216,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                // being sent to the lower layers/to the network.
            }

            profile = setRttModeBasedOnOperator(profile);
            ImsCall imsCall = mImsManager.makeCall(profile, callees, mImsCallListener);
            conn.setImsCall(imsCall);

@@ -1245,6 +1249,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            throw new CallStateException("cannot accept call");
        }

        ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
        if ((mRingingCall.getState() == ImsPhoneCall.State.WAITING)
                && mForegroundCall.getState().isAlive()) {
            setMute(false);
@@ -1264,7 +1269,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                // We need to disconnect the foreground call before answering the background call.
                mForegroundCall.hangup();
                try {
                    ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
                    mediaProfile = addRttAttributeIfRequired(ringingCall, mediaProfile);
                    ringingCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
                            mediaProfile);
                } catch (ImsException e) {
                    throw new CallStateException("cannot accept call");
                }
@@ -1278,7 +1285,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
            try {
                ImsCall imsCall = mRingingCall.getImsCall();
                if (imsCall != null) {
                    imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState));
                    mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);
                    imsCall.accept(ImsCallProfile.getCallTypeFromVideoState(videoState),
                            mediaProfile);
                    mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
                            ImsCommand.IMS_CMD_ACCEPT);
                } else {
@@ -1746,8 +1755,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
                //accept waiting call after holding background call
                ImsCall imsCall = mRingingCall.getImsCall();
                if (imsCall != null) {
                    ImsStreamMediaProfile mediaProfile = new ImsStreamMediaProfile();
                    mediaProfile = addRttAttributeIfRequired(imsCall, mediaProfile);

                    imsCall.accept(
                        ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState));
                            ImsCallProfile.getCallTypeFromVideoState(mPendingCallVideoState),
                            mediaProfile);
                    mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
                            ImsCommand.IMS_CMD_ACCEPT);
                }
@@ -3930,4 +3943,42 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
    public void setAlwaysPlayRemoteHoldTone(boolean shouldPlayRemoteHoldTone) {
        mAlwaysPlayRemoteHoldTone = shouldPlayRemoteHoldTone;
    }

    // Update the Rtt attribute
    private ImsCallProfile setRttModeBasedOnOperator(ImsCallProfile profile) {
        if (!mPhone.canProcessRttRequest()) {
            return profile;
        }

        int mode = QtiImsExtUtils.getRttOperatingMode(mPhone.getContext());

        if (DBG) log("RTT: setRttModeBasedOnOperator mode = " + mode);

        if (!QtiImsExtUtils.isRttSupportedOnVtCalls(mPhone.getPhoneId(), mPhone.getContext()) &&
                profile.isVideoCall()) {
            return profile;
        }

        profile.mMediaProfile.setRttMode(mode);
        return profile;
    }

    // Accept the call as RTT if incoming call as RTT attribute set
    private ImsStreamMediaProfile addRttAttributeIfRequired(ImsCall call,
            ImsStreamMediaProfile mediaProfile) {

        if (!mPhone.canProcessRttRequest()) {
            return mediaProfile;
        }

        ImsCallProfile profile = call.getCallProfile();
        if (profile.mMediaProfile != null && profile.mMediaProfile.isRttCall() &&
                (mPhone.isRttVtCallAllowed(call))) {
            if (DBG) log("RTT: addRttAttributeIfRequired = " + profile.mMediaProfile.isRttCall());
            // If RTT UI option is on, then incoming RTT call should always be accepted
            // as RTT, irrespective of Modes
            mediaProfile.setRttMode(ImsStreamMediaProfile.RTT_MODE_FULL);
        }
        return mediaProfile;
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -124,11 +124,19 @@ public class ImsRttTextHandler extends Handler {
                    return;
                }
                mRttTextStream = (Connection.RttTextStream) msg.obj;
                if (mRttTextStream == null) {
                    Rlog.e(LOG_TAG, "RTT text stream is null");
                    return;
                }
                mReaderThread = new InCallReaderThread(mRttTextStream);
                mReaderThread.start();
                break;
            case SEND_TO_INCALL:
                String messageToIncall = (String) msg.obj;
                if (mRttTextStream == null) {
                    Rlog.e(LOG_TAG, "RTT text stream is null");
                    return;
                }
                try {
                    mRttTextStream.write(messageToIncall);
                } catch (IOException e) {