Search in sources :

Example 1 with TextEncodingDetails

use of com.android.internal.telephony.GsmAlphabet.TextEncodingDetails in project android_frameworks_opt_telephony by LineageOS.

the class SMSDispatcher method sendMultipartText.

/**
 * Send a multi-part text based SMS.
 *  @param destAddr the address to send the message to
 * @param scAddr is the service center address or null to use
 *   the current default SMSC
 * @param parts an <code>ArrayList</code> of strings that, in order,
 *   comprise the original message
 * @param sentIntents if not null, an <code>ArrayList</code> of
 *   <code>PendingIntent</code>s (one for each message part) that is
 *   broadcast when the corresponding message part has been sent.
 *   The result code will be <code>Activity.RESULT_OK<code> for success,
 *   or one of these errors:
 *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
 *   <code>RESULT_ERROR_RADIO_OFF</code>
 *   <code>RESULT_ERROR_NULL_PDU</code>
 *   <code>RESULT_ERROR_NO_SERVICE</code>.
 *  The per-application based SMS control checks sentIntent. If sentIntent
 *  is NULL the caller will be checked against all unknown applications,
 *  which cause smaller number of SMS to be sent in checking period.
 * @param deliveryIntents if not null, an <code>ArrayList</code> of
 *   <code>PendingIntent</code>s (one for each message part) that is
 *   broadcast when the corresponding message part has been delivered
 *   to the recipient.  The raw pdu of the status report is in the
 * @param messageUri optional URI of the message if it is already stored in the system
 * @param callingPkg the calling package name
 * @param persistMessage whether to save the sent message into SMS DB for a
 *   non-default SMS app.
 * @param priority Priority level of the message
 *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
 *  ---------------------------------
 *  PRIORITY      | Level of Priority
 *  ---------------------------------
 *      '00'      |     Normal
 *      '01'      |     Interactive
 *      '10'      |     Urgent
 *      '11'      |     Emergency
 *  ----------------------------------
 *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
 * @param expectMore is a boolean to indicate the sending messages through same link or not.
 * @param validityPeriod Validity Period of the message in mins.
 *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
 *  Validity Period(Minimum) -> 5 mins
 *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
 *  Any Other values included Negative considered as Invalid Validity Period of the message.
 */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
public void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId) {
    final String fullMessageText = getMultipartMessageText(parts);
    int refNumber = getNextConcatenatedRef() & 0x00FF;
    int encoding = SmsConstants.ENCODING_UNKNOWN;
    int msgCount = parts.size();
    if (msgCount < 1) {
        triggerSentIntentForFailure(sentIntents);
        return;
    }
    TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
    for (int i = 0; i < msgCount; i++) {
        TextEncodingDetails details = calculateLength(parts.get(i), false);
        if (encoding != details.codeUnitSize && (encoding == SmsConstants.ENCODING_UNKNOWN || encoding == SmsConstants.ENCODING_7BIT)) {
            encoding = details.codeUnitSize;
        }
        encodingForParts[i] = details;
    }
    SmsTracker[] trackers = new SmsTracker[msgCount];
    // States to track at the message level (for all parts)
    final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
    final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
    for (int i = 0; i < msgCount; i++) {
        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
        concatRef.refNumber = refNumber;
        // 1-based sequence
        concatRef.seqNumber = i + 1;
        concatRef.msgCount = msgCount;
        // TODO: We currently set this to true since our messaging app will never
        // send more than 255 parts (it converts the message to MMS well before that).
        // However, we should support 3rd party messaging apps that might need 16-bit
        // references
        // Note:  It's not sufficient to just flip this bit to true; it will have
        // ripple effects (several calculations assume 8-bit ref).
        concatRef.isEightBits = true;
        SmsHeader smsHeader = new SmsHeader();
        smsHeader.concatRef = concatRef;
        // Set the national language tables for 3GPP 7-bit encoding, if enabled.
        if (encoding == SmsConstants.ENCODING_7BIT) {
            smsHeader.languageTable = encodingForParts[i].languageTable;
            smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
        }
        PendingIntent sentIntent = null;
        if (sentIntents != null && sentIntents.size() > i) {
            sentIntent = sentIntents.get(i);
        }
        PendingIntent deliveryIntent = null;
        if (deliveryIntents != null && deliveryIntents.size() > i) {
            deliveryIntent = deliveryIntents.get(i);
        }
        trackers[i] = getNewSubmitPduTracker(callingPkg, destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)), unsentPartCount, anyPartFailed, messageUri, fullMessageText, priority, expectMore, validityPeriod, messageId);
        if (trackers[i] == null) {
            triggerSentIntentForFailure(sentIntents);
            return;
        }
        trackers[i].mPersistMessage = persistMessage;
    }
    String carrierPackage = getCarrierAppPackageName();
    if (carrierPackage != null) {
        Rlog.d(TAG, "Found carrier package." + " id: " + getMultiTrackermessageId(trackers));
        MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
        smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
    } else {
        Rlog.v(TAG, "No carrier package." + " id: " + getMultiTrackermessageId(trackers));
        sendSubmitPdu(trackers);
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TextEncodingDetails(com.android.internal.telephony.GsmAlphabet.TextEncodingDetails) PendingIntent(android.app.PendingIntent) VisibleForTesting(com.android.internal.annotations.VisibleForTesting)

Example 2 with TextEncodingDetails

use of com.android.internal.telephony.GsmAlphabet.TextEncodingDetails in project android_frameworks_opt_telephony by LineageOS.

the class CdmaSmsTest method testFragmentText.

@SmallTest
public void testFragmentText() throws Exception {
    boolean isCdmaPhone = (TelephonyManager.getDefault().getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA);
    // Valid 160 character ASCII text.
    String text1 = "123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890" + "12345678901234567890123456789[";
    TextEncodingDetails ted = SmsMessage.calculateLength(text1, false, true);
    assertEquals(ted.msgCount, 1);
    assertEquals(ted.codeUnitCount, 160);
    assertEquals(ted.codeUnitSize, 1);
    if (isCdmaPhone) {
        ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text1);
        assertEquals(fragments.size(), 1);
    }
    /*
           This is not a valid test: we will never encode a single-segment
           EMS message.  Leaving this here, since we may try to support
           this in the future.

        // Valid 160 character GSM text -- the last character is
        // non-ASCII, and so this will currently generate a singleton
        // EMS message, which is not necessarily supported by Verizon.
        String text2 = "123456789012345678901234567890123456789012345678901234567890" +
                "1234567890123456789012345678901234567890123456789012345678901234567890" +
                "12345678901234567890123456789\u00a3";  // Trailing pound-currency sign.
        ted = SmsMessage.calculateLength(text2, false);
        assertEquals(ted.msgCount, 1);
        assertEquals(ted.codeUnitCount, 160);
        assertEquals(ted.codeUnitSize, 1);
        if (isCdmaPhone) {
            ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2);
            assertEquals(fragments.size(), 1);
        }
        */
    // *IF* we supported single-segment EMS, this text would result in a
    // single fragment with 7-bit encoding. But we don't, so this text
    // results in three fragments of 16-bit encoding.
    String text2 = "123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890" + // Trailing pound-currency sign.
    "12345678901234567890123456789\u00a3";
    ted = SmsMessage.calculateLength(text2, false, true);
    assertEquals(3, ted.msgCount);
    assertEquals(160, ted.codeUnitCount);
    assertEquals(3, ted.codeUnitSize);
    if (isCdmaPhone) {
        ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2);
        assertEquals(3, fragments.size());
        for (int i = 0; i < 3; i++) {
            SmsHeader header = getConcatUserDataHeader(i + 1, 3);
            SmsHeader header2 = getOddLengthUserDataHeader();
            encodeDecodeAssertEquals(fragments.get(i), header, -1);
            encodeDecodeAssertEquals(fragments.get(i), header2, -1);
        }
    }
    // Test case for multi-part UTF-16 message.
    String text3 = sUnicodeChars + sUnicodeChars + sUnicodeChars;
    ted = SmsMessage.calculateLength(text3, false, true);
    assertEquals(3, ted.msgCount);
    assertEquals(189, ted.codeUnitCount);
    assertEquals(3, ted.codeUnitSize);
    if (isCdmaPhone) {
        ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text3);
        assertEquals(3, fragments.size());
        for (int i = 0; i < 3; i++) {
            SmsHeader header = getConcatUserDataHeader(i + 1, 3);
            SmsHeader header2 = getOddLengthUserDataHeader();
            encodeDecodeAssertEquals(fragments.get(i), header, -1);
            encodeDecodeAssertEquals(fragments.get(i), header2, -1);
        }
    }
}
Also used : SmsHeader(com.android.internal.telephony.SmsHeader) TextEncodingDetails(com.android.internal.telephony.GsmAlphabet.TextEncodingDetails) SmallTest(android.test.suitebuilder.annotation.SmallTest)

Example 3 with TextEncodingDetails

use of com.android.internal.telephony.GsmAlphabet.TextEncodingDetails in project android_frameworks_opt_telephony by LineageOS.

the class SMSDispatcher method sendMultipartText.

/**
 * Send a multi-part text based SMS.
 *  @param destAddr the address to send the message to
 * @param scAddr is the service center address or null to use
 *   the current default SMSC
 * @param parts an <code>ArrayList</code> of strings that, in order,
 *   comprise the original message
 * @param sentIntents if not null, an <code>ArrayList</code> of
 *   <code>PendingIntent</code>s (one for each message part) that is
 *   broadcast when the corresponding message part has been sent.
 *   The result code will be <code>Activity.RESULT_OK<code> for success,
 *   or one of these errors:
 *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
 *   <code>RESULT_ERROR_RADIO_OFF</code>
 *   <code>RESULT_ERROR_NULL_PDU</code>
 *   <code>RESULT_ERROR_NO_SERVICE</code>.
 *  The per-application based SMS control checks sentIntent. If sentIntent
 *  is NULL the caller will be checked against all unknown applications,
 *  which cause smaller number of SMS to be sent in checking period.
 * @param deliveryIntents if not null, an <code>ArrayList</code> of
 *   <code>PendingIntent</code>s (one for each message part) that is
 *   broadcast when the corresponding message part has been delivered
 *   to the recipient.  The raw pdu of the status report is in the
 * @param messageUri optional URI of the message if it is already stored in the system
 * @param callingPkg the calling package name
 * @param persistMessage whether to save the sent message into SMS DB for a
 *   non-default SMS app.
 */
protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, boolean persistMessage) {
    final String fullMessageText = getMultipartMessageText(parts);
    int refNumber = getNextConcatenatedRef() & 0x00FF;
    int msgCount = parts.size();
    int encoding = SmsConstants.ENCODING_UNKNOWN;
    TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
    for (int i = 0; i < msgCount; i++) {
        TextEncodingDetails details = calculateLength(parts.get(i), false);
        if (encoding != details.codeUnitSize && (encoding == SmsConstants.ENCODING_UNKNOWN || encoding == SmsConstants.ENCODING_7BIT)) {
            encoding = details.codeUnitSize;
        }
        encodingForParts[i] = details;
    }
    SmsTracker[] trackers = new SmsTracker[msgCount];
    // States to track at the message level (for all parts)
    final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
    final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
    for (int i = 0; i < msgCount; i++) {
        SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
        concatRef.refNumber = refNumber;
        // 1-based sequence
        concatRef.seqNumber = i + 1;
        concatRef.msgCount = msgCount;
        // TODO: We currently set this to true since our messaging app will never
        // send more than 255 parts (it converts the message to MMS well before that).
        // However, we should support 3rd party messaging apps that might need 16-bit
        // references
        // Note:  It's not sufficient to just flip this bit to true; it will have
        // ripple effects (several calculations assume 8-bit ref).
        concatRef.isEightBits = true;
        SmsHeader smsHeader = new SmsHeader();
        smsHeader.concatRef = concatRef;
        // Set the national language tables for 3GPP 7-bit encoding, if enabled.
        if (encoding == SmsConstants.ENCODING_7BIT) {
            smsHeader.languageTable = encodingForParts[i].languageTable;
            smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
        }
        PendingIntent sentIntent = null;
        if (sentIntents != null && sentIntents.size() > i) {
            sentIntent = sentIntents.get(i);
        }
        PendingIntent deliveryIntent = null;
        if (deliveryIntents != null && deliveryIntents.size() > i) {
            deliveryIntent = deliveryIntents.get(i);
        }
        trackers[i] = getNewSubmitPduTracker(destAddr, scAddr, parts.get(i), smsHeader, encoding, sentIntent, deliveryIntent, (i == (msgCount - 1)), unsentPartCount, anyPartFailed, messageUri, fullMessageText);
        trackers[i].mPersistMessage = persistMessage;
    }
    if (parts == null || trackers == null || trackers.length == 0 || trackers[0] == null) {
        Rlog.e(TAG, "Cannot send multipart text. parts=" + parts + " trackers=" + trackers);
        return;
    }
    String carrierPackage = getCarrierAppPackageName();
    if (carrierPackage != null) {
        Rlog.d(TAG, "Found carrier package.");
        MultipartSmsSender smsSender = new MultipartSmsSender(parts, trackers);
        smsSender.sendSmsByCarrierApp(carrierPackage, new MultipartSmsSenderCallback(smsSender));
    } else {
        Rlog.v(TAG, "No carrier package.");
        for (SmsTracker tracker : trackers) {
            if (tracker != null) {
                sendSubmitPdu(tracker);
            } else {
                Rlog.e(TAG, "Null tracker.");
            }
        }
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TextEncodingDetails(com.android.internal.telephony.GsmAlphabet.TextEncodingDetails) PendingIntent(android.app.PendingIntent)

Aggregations

TextEncodingDetails (com.android.internal.telephony.GsmAlphabet.TextEncodingDetails)3 PendingIntent (android.app.PendingIntent)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 SmallTest (android.test.suitebuilder.annotation.SmallTest)1 VisibleForTesting (com.android.internal.annotations.VisibleForTesting)1 SmsHeader (com.android.internal.telephony.SmsHeader)1