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

Commit 3808616e authored by James.cf Lin's avatar James.cf Lin
Browse files

Fix the PIDF parser may fail when the pidf xml contains the newline characters.

Bug: 186075898
Test: atest PidfParserTest; atest ImsServiceTest
Change-Id: Ie54f0d37a0118fa2ed96717942d0cae60254d3ff
parent ec617e6c
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -58,6 +60,8 @@ public class PidfParser {

    private static final String LOG_TAG = UceUtils.getLogPrefix() + "PidfParser";

    private static final Pattern PIDF_PATTERN = Pattern.compile("\t|\r|\n");

    /**
     * Convert the RcsContactUceCapability to the string of pidf.
     */
@@ -98,6 +102,15 @@ public class PidfParser {
     */
    public static @Nullable RcsContactUceCapability getRcsContactUceCapability(String pidf) {
        if (TextUtils.isEmpty(pidf)) {
            Log.w(LOG_TAG, "getRcsContactUceCapability: The given pidf is empty");
            return null;
        }

        // Filter the newline characters
        Matcher matcher = PIDF_PATTERN.matcher(pidf);
        String formattedPidf = matcher.replaceAll("");
        if (TextUtils.isEmpty(formattedPidf)) {
            Log.w(LOG_TAG, "getRcsContactUceCapability: The formatted pidf is empty");
            return null;
        }

@@ -106,7 +119,7 @@ public class PidfParser {
            // Init the instance of the parser
            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
            reader = new StringReader(pidf);
            reader = new StringReader(formattedPidf);
            parser.setInput(reader);

            // Start parsing
+144 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.net.Uri;
import android.telephony.ims.RcsContactPresenceTuple;
@@ -34,6 +35,7 @@ import androidx.test.filters.SmallTest;
import com.android.ims.ImsTestBase;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

import org.junit.After;
@@ -107,6 +109,93 @@ public class PidfParserTest extends ImsTestBase {
        assertFalse(presenceTuple1.getServiceCapabilities().isVideoCapable());
    }

    @Test
    @SmallTest
    public void testConvertFromNewlineIncludedPidfToRcsContactUceCapability() throws Exception {
        final String contact = "tel:+11234567890";

        final RcsContactPresenceTuple.Builder tuple1Builder = new RcsContactPresenceTuple.Builder(
                "open",
                "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp",
                "1.0");
        tuple1Builder.setServiceDescription("DiscoveryPresence")
                .setContactUri(Uri.parse(contact));

        final RcsContactPresenceTuple.Builder tuple2Builder = new RcsContactPresenceTuple.Builder(
                "open",
                "org.openmobilealliance:StandaloneMsg",
                "2.0");
        tuple2Builder.setServiceDescription("StandaloneMsg")
                .setContactUri(Uri.parse(contact));

        final RcsContactPresenceTuple.Builder tuple3Builder = new RcsContactPresenceTuple.Builder(
                "open",
                "org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel",
                "1.0");
        tuple3Builder.setServiceDescription("VoLTE service");
        ServiceCapabilities.Builder capBuilder = new ServiceCapabilities.Builder(true, true);
        tuple3Builder.setServiceCapabilities(capBuilder.build())
                .setContactUri(Uri.parse(contact));

        final List<RcsContactPresenceTuple> expectedTupleList = new ArrayList<>(3);
        expectedTupleList.add(tuple1Builder.build());
        expectedTupleList.add(tuple2Builder.build());
        expectedTupleList.add(tuple3Builder.build());

        // Create the newline included PIDF data
        String pidfData = getPidfDataWithNewlineCharacters(contact);

        // Convert to the class RcsContactUceCapability
        RcsContactUceCapability capabilities = PidfParser.getRcsContactUceCapability(pidfData);

        assertNotNull(capabilities);
        assertEquals(Uri.parse(contact), capabilities.getContactUri());
        assertEquals(RcsContactUceCapability.SOURCE_TYPE_NETWORK, capabilities.getSourceType());
        assertEquals(RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE,
                capabilities.getCapabilityMechanism());

        List<RcsContactPresenceTuple> presenceTupleList = capabilities.getCapabilityTuples();
        assertNotNull(presenceTupleList);
        assertEquals(expectedTupleList.size(), presenceTupleList.size());

        for(RcsContactPresenceTuple tuple : presenceTupleList) {
            String serviceId = tuple.getServiceId();
            RcsContactPresenceTuple expectedTuple = findTuple(serviceId, expectedTupleList);
            if (expectedTuple == null) {
                fail("The service ID is invalid");
            }

            assertEquals(expectedTuple.getStatus(), tuple.getStatus());
            assertEquals(expectedTuple.getServiceVersion(), tuple.getServiceVersion());
            assertEquals(expectedTuple.getServiceDescription(), tuple.getServiceDescription());
            assertEquals(expectedTuple.getTime(), tuple.getTime());
            assertEquals(expectedTuple.getContactUri(), tuple.getContactUri());

            ServiceCapabilities expectedCap = expectedTuple.getServiceCapabilities();
            ServiceCapabilities resultCap = tuple.getServiceCapabilities();
            if (expectedCap != null) {
                assertNotNull(resultCap);
                assertEquals(expectedCap.isAudioCapable(), resultCap.isAudioCapable());
                assertEquals(expectedCap.isVideoCapable(), resultCap.isVideoCapable());
            } else {
                assertNull(resultCap);
            }
        }
    }

    private RcsContactPresenceTuple findTuple(String serviceId,
            List<RcsContactPresenceTuple> expectedTupleList) {
        if (serviceId == null) {
            return null;
        }
        for (RcsContactPresenceTuple tuple : expectedTupleList) {
            if (serviceId.equalsIgnoreCase(tuple.getServiceId())) {
                return tuple;
            }
        }
        return null;
    }

    @Test
    @SmallTest
    public void testConvertToRcsContactUceCapabilityForMultipleTuples() throws Exception {
@@ -241,6 +330,61 @@ public class PidfParserTest extends ImsTestBase {
        return pidfBuilder.toString();
    }

    private String getPidfDataWithNewlineCharacters(String contact) {
        String pidf = "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" "
                + "xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\" "
                + "xmlns:b=\"urn:ietf:params:xml:ns:pidf:caps\" "
                + "entity=\"" + contact + "\">\n"
                // The first tuple
                + "<tuple id=\"DiscoveryPres\">\n"
                + "<status>\n"
                + "<basic>open</basic>\n"
                + "</status>\n"
                + "<op:service-description>\n"
                + "<op:service-id>"
                        + "org.3gpp.urn:urn-7:3gpp-application.ims.iari.rcse.dp</op:service-id>\n"
                + "<op:version>1.0</op:version>\n"
                + "<op:description>DiscoveryPresence</op:description>\n"
                + "</op:service-description>\n"
                + "<contact>tel:+11234567890</contact>\n"
                + "</tuple>\n"
                // The second tuple
                + "<tuple id=\"VoLTE\">\n"
                + "<status>\n"
                + "<basic>open</basic>\n"
                + "</status>\n"
                + "<b:servcaps>\n"
                + "<b:audio>true</b:audio>\n"
                + "<b:video>true</b:video>\n"
                + "<b:duplex>\n"
                + "<b:supported>\n"
                + "<b:full/>\n"
                + "</b:supported>\n"
                + "</b:duplex>\n"
                + "</b:servcaps>\n"
                + "<op:service-description>\n"
                + "<op:service-id>org.3gpp.urn:urn-7:3gpp-service.ims.icsi.mmtel</op:service-id>\n"
                + "<op:version>1.0</op:version>\n"
                + "<op:description>VoLTE service</op:description>\n"
                + "</op:service-description>\n"
                + "<contact>tel:+11234567890</contact>\n"
                + "</tuple>\n"
                // The third tuple
                + "<tuple id=\"StandaloneMsg\">\n"
                + "<status>\n"
                + "<basic>open</basic>\n"
                + "</status>\n"
                + "<op:service-description>\n"
                + "<op:service-id>org.openmobilealliance:StandaloneMsg</op:service-id>\n"
                + "<op:version>2.0</op:version>\n"
                + "<op:description>StandaloneMsg</op:description>\n"
                + "</op:service-description>\n"
                + "<contact>tel:+11234567890</contact>\n"
                + "</tuple>\n"
                + "</presence>";
        return pidf;
    }

    private String getPidfDataWithMultiTuples(String contact, String serviceId1,
            String serviceDescription1, String serviceId2, String serviceDescription2,
            boolean audioSupported, boolean videoSupported) {