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

Commit 0b0a0104 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Handle Verizon iPhone WAP push for VVM" into nyc-mr1-dev

parents f5823329 9452da00
Loading
Loading
Loading
Loading
+44 −22
Original line number Diff line number Diff line
@@ -15,19 +15,18 @@
 */
package com.android.internal.telephony;

import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.provider.VoicemailContract;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.util.Log;

import android.telephony.SmsMessage;

import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;

import java.nio.charset.StandardCharsets;

public class VisualVoicemailSmsFilter {

    private static final String TAG = "VvmSmsFilter";
@@ -61,13 +60,34 @@ public class VisualVoicemailSmsFilter {
        // TODO: filter base on originating number and destination port.

        String messageBody = getFullMessage(pdus, format);

        if(messageBody == null){
            return false;
            // Verizon WAP push SMS is not recognized by android, which has a ascii PDU.
            // Attempt to parse it.
            Log.i(TAG, "Unparsable SMS received");
            String asciiMessage = parseAsciiPduMessage(pdus);
            WrappedMessageData messageData = VisualVoicemailSmsParser
                .parseAlternativeFormat(asciiMessage);
            if (messageData != null) {
                sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData);
            }
            // Confidence for what the message actually is is low. Don't remove the message and let
            // system decide. Usually because it is not parsable it will be dropped.
            return false;
        } else {
            String clientPrefix = settings.clientPrefix;

        WrappedMessageData messageData = VisualVoicemailSmsParser.parse(clientPrefix, messageBody);
            WrappedMessageData messageData = VisualVoicemailSmsParser
                .parse(clientPrefix, messageBody);
            if (messageData != null) {
                sendVvmSmsBroadcast(context, vvmClientPackage, subId, messageData);
                return true;
            }
        }
        return false;
    }

    private static void sendVvmSmsBroadcast(Context context, String vvmClientPackage, int subId,
        WrappedMessageData messageData) {
        Log.i(TAG, "VVM SMS received");
        Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_PREFIX, messageData.prefix);
@@ -75,10 +95,6 @@ public class VisualVoicemailSmsFilter {
        intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID, subId);
        intent.setPackage(vvmClientPackage);
        context.sendBroadcast(intent);
            return true;
        }

        return false;
    }

    private static String getFullMessage(byte[][] pdus, String format) {
@@ -86,10 +102,8 @@ public class VisualVoicemailSmsFilter {
        for (byte pdu[] : pdus) {
            SmsMessage message =SmsMessage.createFromPdu(pdu, format);

            if(message == null || message.mWrappedSmsMessage == null) {
                // b/29123941 Certain PDU will cause createFromPdu() to return a SmsMessage with
                // null mWrappedSmsMessage, throwing NPE on any method called. In this case, just
                // ignore the message.
            if (message == null) {
                // The PDU is not recognized by android
                return null;
            }
            String body = message.getMessageBody();
@@ -99,4 +113,12 @@ public class VisualVoicemailSmsFilter {
        }
        return builder.toString();
    }

    private static String parseAsciiPduMessage(byte[][] pdus) {
        StringBuilder builder = new StringBuilder();
        for (byte pdu[] : pdus) {
            builder.append(new String(pdu, StandardCharsets.US_ASCII));
        }
        return builder.toString();
    }
}
+43 −0
Original line number Diff line number Diff line
@@ -20,6 +20,10 @@ import android.os.Bundle;

public class VisualVoicemailSmsParser {

    private static final String[] ALLOWED_ALTERNATIVE_FORMAT_EVENT = new String[] {
            "MBOXUPDATE", "UNRECOGNIZED"
    };

    /**
     * Class wrapping the raw OMTP message data, internally represented as as map of all key-value
     * pairs found in the SMS body. <p> All the methods return null if either the field was not
@@ -80,6 +84,7 @@ public class VisualVoicemailSmsParser {
     * @param message The sms string with the prefix removed.
     * @return A WrappedMessageData object containing the map.
     */
    @Nullable
    private static Bundle parseSmsBody(String message) {
        // TODO: ensure fail if format does not match
        Bundle keyValues = new Bundle();
@@ -107,4 +112,42 @@ public class VisualVoicemailSmsParser {

        return keyValues;
    }

    /**
     * The alternative format is [Event]?([key]=[value])*, for example
     *
     * <p>"MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=foo".
     *
     * <p>This format is not protected with a client prefix and should be handled with care. For
     * safety, the event type must be one of {@link #ALLOWED_ALTERNATIVE_FORMAT_EVENT}
     */
    @Nullable
    public static WrappedMessageData parseAlternativeFormat(String smsBody) {
        try {
            int eventTypeEnd = smsBody.indexOf("?");
            if (eventTypeEnd == -1) {
                return null;
            }
            String eventType = smsBody.substring(0, eventTypeEnd);
            if (!isAllowedAlternativeFormatEvent(eventType)) {
                return null;
            }
            Bundle fields = parseSmsBody(smsBody.substring(eventTypeEnd + 1));
            if (fields == null) {
                return null;
            }
            return new WrappedMessageData(eventType, fields);
        } catch (IndexOutOfBoundsException e) {
            return null;
        }
    }

    private static boolean isAllowedAlternativeFormatEvent(String eventType) {
        for (String event : ALLOWED_ALTERNATIVE_FORMAT_EVENT) {
            if (event.equals(eventType)) {
                return true;
            }
        }
        return false;
    }
}
+38 −2
Original line number Diff line number Diff line
@@ -16,9 +16,7 @@
package com.android.internal.telephony;

import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;

import junit.framework.TestCase;

public class VisualVoicemailSmsParserTest extends TestCase {
@@ -147,4 +145,42 @@ public class VisualVoicemailSmsParserTest extends TestCase {
        assertEquals("STATUS", result.prefix);
        assertEquals("", result.fields.getString("key"));
    }

    @SmallTest
    public void testAlternativeParsing_Mboxupdate() {
        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
            "MBOXUPDATE?m=1;server=example.com;port=143;name=foo@example.com;pw=bar");

        assertEquals("MBOXUPDATE", result.prefix);
        assertEquals("1", result.fields.getString("m"));
        assertEquals("example.com", result.fields.getString("server"));
        assertEquals("143", result.fields.getString("port"));
        assertEquals("foo@example.com", result.fields.getString("name"));
        assertEquals("bar", result.fields.getString("pw"));
    }

    @SmallTest
    public void testAlternativeParsing_Unrecognized() {
        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
            "UNRECOGNIZED?cmd=STATUS");

        assertEquals("UNRECOGNIZED", result.prefix);
        assertEquals("STATUS", result.fields.getString("cmd"));
    }

    @SmallTest
    public void testAlternativeParsingFail_MissingSeparator() {
        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
            "I send SMS in weird formats");

        assertNull(result);
    }

    @SmallTest
    public void testAlternativeParsingFail_NotWhitelistedEvent() {
        WrappedMessageData result = VisualVoicemailSmsParser.parseAlternativeFormat(
            "AreYouStillThere?");

        assertNull(result);
    }
}