2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.telephony;
19 import android.os.Binder;
20 import android.os.Parcel;
21 import android.content.res.Resources;
22 import android.text.TextUtils;
24 import com.android.internal.telephony.GsmAlphabet;
25 import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
26 import com.android.internal.telephony.SmsConstants;
27 import com.android.internal.telephony.SmsMessageBase;
28 import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
29 import com.android.internal.telephony.Sms7BitEncodingTranslator;
31 import java.lang.Math;
32 import java.util.ArrayList;
33 import java.util.Arrays;
35 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
39 * A Short Message Service message.
40 * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
42 public class SmsMessage {
43 private static final String LOG_TAG = "SmsMessage";
46 * SMS Class enumeration.
50 public enum MessageClass{
51 UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
54 /** User data text encoding code unit size */
55 public static final int ENCODING_UNKNOWN = 0;
56 public static final int ENCODING_7BIT = 1;
57 public static final int ENCODING_8BIT = 2;
58 public static final int ENCODING_16BIT = 3;
60 * @hide This value is not defined in global standard. Only in Korea, this is used.
62 public static final int ENCODING_KSC5601 = 4;
64 /** The maximum number of payload bytes per message */
65 public static final int MAX_USER_DATA_BYTES = 140;
68 * The maximum number of payload bytes per message if a user data header
69 * is present. This assumes the header only contains the
70 * CONCATENATED_8_BIT_REFERENCE element.
72 public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
74 /** The maximum number of payload septets per message */
75 public static final int MAX_USER_DATA_SEPTETS = 160;
78 * The maximum number of payload septets per message if a user data header
79 * is present. This assumes the header only contains the
80 * CONCATENATED_8_BIT_REFERENCE element.
82 public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
85 * Indicates a 3GPP format SMS message.
86 * @hide pending API council approval
88 public static final String FORMAT_3GPP = "3gpp";
91 * Indicates a 3GPP2 format SMS message.
92 * @hide pending API council approval
94 public static final String FORMAT_3GPP2 = "3gpp2";
96 /** Contains actual SmsMessage. Only public for debugging and for framework layer.
100 public SmsMessageBase mWrappedSmsMessage;
102 /** Indicates the subId
106 private int mSubId = 0;
108 /** set Subscription information
112 public void setSubId(int subId) {
116 /** get Subscription information
120 public int getSubId() {
124 public static class SubmitPdu {
126 public byte[] encodedScAddress; // Null if not applicable.
127 public byte[] encodedMessage;
130 public String toString() {
131 return "SubmitPdu: encodedScAddress = "
132 + Arrays.toString(encodedScAddress)
133 + ", encodedMessage = "
134 + Arrays.toString(encodedMessage);
140 protected SubmitPdu(SubmitPduBase spb) {
141 this.encodedMessage = spb.encodedMessage;
142 this.encodedScAddress = spb.encodedScAddress;
147 private SmsMessage(SmsMessageBase smb) {
148 mWrappedSmsMessage = smb;
152 * Create an SmsMessage from a raw PDU. Guess format based on Voice
153 * technology first, if it fails use other format.
154 * All applications which handle
155 * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast
156 * intent <b>must</b> now pass the new {@code format} String extra from the intent
157 * into the new method {@code createFromPdu(byte[], String)} which takes an
158 * extra format parameter. This is required in order to correctly decode the PDU on
159 * devices that require support for both 3GPP and 3GPP2 formats at the same time,
160 * such as dual-mode GSM/CDMA and CDMA/LTE phones.
161 * @deprecated Use {@link #createFromPdu(byte[], String)} instead.
164 public static SmsMessage createFromPdu(byte[] pdu) {
165 SmsMessage message = null;
167 // cdma(3gpp2) vs gsm(3gpp) format info was not given,
168 // guess from active voice phone type
169 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
170 String format = (PHONE_TYPE_CDMA == activePhone) ?
171 SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
172 message = createFromPdu(pdu, format);
174 if (null == message || null == message.mWrappedSmsMessage) {
175 // decoding pdu failed based on activePhone type, must be other format
176 format = (PHONE_TYPE_CDMA == activePhone) ?
177 SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2;
178 message = createFromPdu(pdu, format);
184 * Create an SmsMessage from a raw PDU with the specified message format. The
185 * message format is passed in the
186 * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} as the {@code format}
187 * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
188 * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
190 * @param pdu the message PDU from the
191 * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
192 * @param format the format extra from the
193 * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
195 public static SmsMessage createFromPdu(byte[] pdu, String format) {
196 SmsMessageBase wrappedMessage;
198 if (SmsConstants.FORMAT_3GPP2.equals(format)) {
199 wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
200 } else if (SmsConstants.FORMAT_3GPP.equals(format)) {
201 wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
203 Rlog.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
207 if (wrappedMessage != null) {
208 return new SmsMessage(wrappedMessage);
210 Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null");
216 * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
217 * +CMT unsolicited response (PDU mode, of course)
218 * +CMT: [<alpha>],<length><CR><LF><pdu>
220 * Only public for debugging and for RIL
224 public static SmsMessage newFromCMT(String[] lines) {
225 // received SMS in 3GPP format
226 SmsMessageBase wrappedMessage =
227 com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
229 if (wrappedMessage != null) {
230 return new SmsMessage(wrappedMessage);
232 Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
238 public static SmsMessage newFromParcel(Parcel p) {
239 // received SMS in 3GPP2 format
240 SmsMessageBase wrappedMessage =
241 com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
243 return new SmsMessage(wrappedMessage);
247 * Create an SmsMessage from an SMS EF record.
249 * @param index Index of SMS record. This should be index in ArrayList
250 * returned by SmsManager.getAllMessagesFromSim + 1.
251 * @param data Record data.
252 * @return An SmsMessage representing the record.
256 public static SmsMessage createFromEfRecord(int index, byte[] data) {
257 SmsMessageBase wrappedMessage;
260 wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
263 wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
267 if (wrappedMessage != null) {
268 return new SmsMessage(wrappedMessage);
270 Rlog.e(LOG_TAG, "createFromEfRecord(): wrappedMessage is null");
276 * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
277 * length in bytes (not hex chars) less the SMSC header
279 * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices.
280 * We should probably deprecate it and remove the obsolete test case.
282 public static int getTPLayerLengthForPDU(String pdu) {
284 return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
286 return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
291 * TODO(cleanup): It would make some sense if the result of
292 * preprocessing a message to determine the proper encoding (i.e.
293 * the resulting data structure from calculateLength) could be
294 * passed as an argument to the actual final encoding function.
295 * This would better ensure that the logic behind size calculation
296 * actually matched the encoding.
300 * Calculates the number of SMS's required to encode the message body and
301 * the number of characters remaining until the next message.
303 * @param msgBody the message to encode
304 * @param use7bitOnly if true, characters that are not part of the
305 * radio-specific 7-bit encoding are counted as single
306 * space chars. If false, and if the messageBody contains
307 * non-7-bit encodable characters, length is calculated
308 * using a 16-bit encoding.
309 * @return an int[4] with int[0] being the number of SMS's
310 * required, int[1] the number of code units used, and
311 * int[2] is the number of code units remaining until the
312 * next message. int[3] is an indicator of the encoding
313 * code unit size (see the ENCODING_* definitions in SmsConstants)
315 public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
316 // this function is for MO SMS
317 TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
318 com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly,
320 com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
321 int ret[] = new int[4];
322 ret[0] = ted.msgCount;
323 ret[1] = ted.codeUnitCount;
324 ret[2] = ted.codeUnitsRemaining;
325 ret[3] = ted.codeUnitSize;
330 * Divide a message text into several fragments, none bigger than
331 * the maximum SMS message text size.
333 * @param text text, must not be null.
334 * @return an <code>ArrayList</code> of strings that, in order,
335 * comprise the original msg text
339 public static ArrayList<String> fragmentText(String text) {
340 // This function is for MO SMS
341 TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
342 com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false, true) :
343 com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);
345 // TODO(cleanup): The code here could be rolled into the logic
346 // below cleanly if these MAX_* constants were defined more
350 if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
352 if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
353 udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
354 } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
355 udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
360 if (ted.msgCount > 1) {
361 udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
364 if (udhLength != 0) {
365 udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
368 limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;
370 if (ted.msgCount > 1) {
371 limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
372 // If EMS is not supported, break down EMS into single segment SMS
373 // and add page info " x/y".
374 // In the case of UCS2 encoding, we need 8 bytes for this,
375 // but we only have 6 bytes from UDH, so truncate the limit for
376 // each segment by 2 bytes (1 char).
377 // Make sure total number of segments is less than 10.
378 if (!hasEmsSupport() && ted.msgCount < 10) {
382 limit = SmsConstants.MAX_USER_DATA_BYTES;
386 String newMsgBody = null;
387 Resources r = Resources.getSystem();
388 if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
389 newMsgBody = Sms7BitEncodingTranslator.translate(text);
391 if (TextUtils.isEmpty(newMsgBody)) {
394 int pos = 0; // Index in code units.
395 int textLen = newMsgBody.length();
396 ArrayList<String> result = new ArrayList<String>(ted.msgCount);
397 while (pos < textLen) {
398 int nextPos = 0; // Counts code units.
399 if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
400 if (useCdmaFormatForMoSms() && ted.msgCount == 1) {
401 // For a singleton CDMA message, the encoding must be ASCII...
402 nextPos = pos + Math.min(limit, textLen - pos);
404 // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
405 nextPos = GsmAlphabet.findGsmSeptetLimitIndex(newMsgBody, pos, limit,
406 ted.languageTable, ted.languageShiftTable);
408 } else { // Assume unicode.
409 nextPos = SmsMessageBase.findNextUnicodePosition(pos, limit, newMsgBody);
411 if ((nextPos <= pos) || (nextPos > textLen)) {
412 Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
413 nextPos + " >= " + textLen + ")");
416 result.add(newMsgBody.substring(pos, nextPos));
423 * Calculates the number of SMS's required to encode the message body and
424 * the number of characters remaining until the next message, given the
427 * @param messageBody the message to encode
428 * @param use7bitOnly if true, characters that are not part of the radio
429 * specific (GSM / CDMA) alphabet encoding are converted to as a
430 * single space characters. If false, a messageBody containing
431 * non-GSM or non-CDMA alphabet characters are encoded using
433 * @return an int[4] with int[0] being the number of SMS's required, int[1]
434 * the number of code units used, and int[2] is the number of code
435 * units remaining until the next message. int[3] is the encoding
436 * type that should be used for the message.
438 public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
439 return calculateLength((CharSequence)messageBody, use7bitOnly);
443 * TODO(cleanup): It looks like there is now no useful reason why
444 * apps should generate pdus themselves using these routines,
445 * instead of handing the raw data to SMSDispatcher (and thereby
446 * have the phone process do the encoding). Moreover, CDMA now
447 * has shared state (in the form of the msgId system property)
448 * which can only be modified by the phone process, and hence
449 * makes the output of these routines incorrect. Since they now
450 * serve no purpose, they should probably just return null
451 * directly, and be deprecated. Going further in that direction,
452 * the above parsers of serialized pdu data should probably also
453 * be gotten rid of, hiding all but the necessarily visible
454 * structured data from client apps. A possible concern with
455 * doing this is that apps may be using these routines to generate
456 * pdus that are then sent elsewhere, some network server, for
457 * example, and that always returning null would thereby break
458 * otherwise useful apps.
462 * Get an SMS-SUBMIT PDU for a destination address and a message.
463 * This method will not attempt to use any GSM national language 7 bit encodings.
465 * @param scAddress Service Centre address. Null means use default.
466 * @return a <code>SubmitPdu</code> containing the encoded SC
467 * address, if applicable, and the encoded message.
468 * Returns null on encode error.
470 public static SubmitPdu getSubmitPdu(String scAddress,
471 String destinationAddress, String message, boolean statusReportRequested) {
474 if (useCdmaFormatForMoSms()) {
475 spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
476 destinationAddress, message, statusReportRequested, null);
478 spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
479 destinationAddress, message, statusReportRequested);
482 return new SubmitPdu(spb);
486 * Get an SMS-SUBMIT PDU for a data message to a destination address & port.
487 * This method will not attempt to use any GSM national language 7 bit encodings.
489 * @param scAddress Service Centre address. null == use default
490 * @param destinationAddress the address of the destination for the message
491 * @param destinationPort the port to deliver the message to at the
493 * @param data the data for the message
494 * @return a <code>SubmitPdu</code> containing the encoded SC
495 * address, if applicable, and the encoded message.
496 * Returns null on encode error.
498 public static SubmitPdu getSubmitPdu(String scAddress,
499 String destinationAddress, short destinationPort, byte[] data,
500 boolean statusReportRequested) {
503 if (useCdmaFormatForMoSms()) {
504 spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
505 destinationAddress, destinationPort, data, statusReportRequested);
507 spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
508 destinationAddress, destinationPort, data, statusReportRequested);
511 return new SubmitPdu(spb);
515 * Returns the address of the SMS service center that relayed this message
516 * or null if there is none.
518 public String getServiceCenterAddress() {
519 return mWrappedSmsMessage.getServiceCenterAddress();
523 * Returns the originating address (sender) of this SMS message in String
524 * form or null if unavailable
526 public String getOriginatingAddress() {
527 return mWrappedSmsMessage.getOriginatingAddress();
531 * Returns the originating address, or email from address if this message
532 * was from an email gateway. Returns null if originating address
535 public String getDisplayOriginatingAddress() {
536 return mWrappedSmsMessage.getDisplayOriginatingAddress();
540 * Returns the message body as a String, if it exists and is text based.
541 * @return message body is there is one, otherwise null
543 public String getMessageBody() {
544 return mWrappedSmsMessage.getMessageBody();
548 * Returns the class of this message.
550 public MessageClass getMessageClass() {
551 switch(mWrappedSmsMessage.getMessageClass()) {
552 case CLASS_0: return MessageClass.CLASS_0;
553 case CLASS_1: return MessageClass.CLASS_1;
554 case CLASS_2: return MessageClass.CLASS_2;
555 case CLASS_3: return MessageClass.CLASS_3;
556 default: return MessageClass.UNKNOWN;
562 * Returns the message body, or email message body if this message was from
563 * an email gateway. Returns null if message body unavailable.
565 public String getDisplayMessageBody() {
566 return mWrappedSmsMessage.getDisplayMessageBody();
570 * Unofficial convention of a subject line enclosed in parens empty string
573 public String getPseudoSubject() {
574 return mWrappedSmsMessage.getPseudoSubject();
578 * Returns the service centre timestamp in currentTimeMillis() format
580 public long getTimestampMillis() {
581 return mWrappedSmsMessage.getTimestampMillis();
585 * Returns true if message is an email.
587 * @return true if this message came through an email gateway and email
588 * sender / subject / parsed body are available
590 public boolean isEmail() {
591 return mWrappedSmsMessage.isEmail();
595 * @return if isEmail() is true, body of the email sent through the gateway.
598 public String getEmailBody() {
599 return mWrappedSmsMessage.getEmailBody();
603 * @return if isEmail() is true, email from address of email sent through
604 * the gateway. null otherwise
606 public String getEmailFrom() {
607 return mWrappedSmsMessage.getEmailFrom();
611 * Get protocol identifier.
613 public int getProtocolIdentifier() {
614 return mWrappedSmsMessage.getProtocolIdentifier();
618 * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
621 public boolean isReplace() {
622 return mWrappedSmsMessage.isReplace();
626 * Returns true for CPHS MWI toggle message.
628 * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
631 public boolean isCphsMwiMessage() {
632 return mWrappedSmsMessage.isCphsMwiMessage();
636 * returns true if this message is a CPHS voicemail / message waiting
637 * indicator (MWI) clear message
639 public boolean isMWIClearMessage() {
640 return mWrappedSmsMessage.isMWIClearMessage();
644 * returns true if this message is a CPHS voicemail / message waiting
645 * indicator (MWI) set message
647 public boolean isMWISetMessage() {
648 return mWrappedSmsMessage.isMWISetMessage();
652 * returns true if this message is a "Message Waiting Indication Group:
653 * Discard Message" notification and should not be stored.
655 public boolean isMwiDontStore() {
656 return mWrappedSmsMessage.isMwiDontStore();
660 * returns the user data section minus the user data header if one was
663 public byte[] getUserData() {
664 return mWrappedSmsMessage.getUserData();
668 * Returns the raw PDU for the message.
670 * @return the raw PDU for the message.
672 public byte[] getPdu() {
673 return mWrappedSmsMessage.getPdu();
677 * Returns the status of the message on the SIM (read, unread, sent, unsent).
679 * @return the status of the message on the SIM. These are:
680 * SmsManager.STATUS_ON_SIM_FREE
681 * SmsManager.STATUS_ON_SIM_READ
682 * SmsManager.STATUS_ON_SIM_UNREAD
683 * SmsManager.STATUS_ON_SIM_SEND
684 * SmsManager.STATUS_ON_SIM_UNSENT
685 * @deprecated Use getStatusOnIcc instead.
687 @Deprecated public int getStatusOnSim() {
688 return mWrappedSmsMessage.getStatusOnIcc();
692 * Returns the status of the message on the ICC (read, unread, sent, unsent).
694 * @return the status of the message on the ICC. These are:
695 * SmsManager.STATUS_ON_ICC_FREE
696 * SmsManager.STATUS_ON_ICC_READ
697 * SmsManager.STATUS_ON_ICC_UNREAD
698 * SmsManager.STATUS_ON_ICC_SEND
699 * SmsManager.STATUS_ON_ICC_UNSENT
701 public int getStatusOnIcc() {
702 return mWrappedSmsMessage.getStatusOnIcc();
706 * Returns the record index of the message on the SIM (1-based index).
707 * @return the record index of the message on the SIM, or -1 if this
708 * SmsMessage was not created from a SIM SMS EF record.
709 * @deprecated Use getIndexOnIcc instead.
711 @Deprecated public int getIndexOnSim() {
712 return mWrappedSmsMessage.getIndexOnIcc();
716 * Returns the record index of the message on the ICC (1-based index).
717 * @return the record index of the message on the ICC, or -1 if this
718 * SmsMessage was not created from a ICC SMS EF record.
720 public int getIndexOnIcc() {
721 return mWrappedSmsMessage.getIndexOnIcc();
726 * For an SMS-STATUS-REPORT message, this returns the status field from
727 * the status report. This field indicates the status of a previously
728 * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
729 * description of values.
731 * For not interfering with status codes from GSM, the value is
732 * shifted to the bits 31-16.
733 * The value is composed of an error class (bits 25-24) and a status code (bits 23-16).
734 * Possible codes are described in C.S0015-B, v2.0, 4.5.21.
736 * @return 0 indicates the previously sent message was received.
737 * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21
738 * for a description of other possible values.
740 public int getStatus() {
741 return mWrappedSmsMessage.getStatus();
745 * Return true iff the message is a SMS-STATUS-REPORT message.
747 public boolean isStatusReportMessage() {
748 return mWrappedSmsMessage.isStatusReportMessage();
752 * Returns true iff the <code>TP-Reply-Path</code> bit is set in
755 public boolean isReplyPathPresent() {
756 return mWrappedSmsMessage.isReplyPathPresent();
760 * Determines whether or not to use CDMA format for MO SMS.
761 * If SMS over IMS is supported, then format is based on IMS SMS format,
762 * otherwise format is based on current phone type.
764 * @return true if Cdma format should be used for MO SMS, false otherwise.
766 private static boolean useCdmaFormatForMoSms() {
767 if (!SmsManager.getDefault().isImsSmsSupported()) {
768 // use Voice technology to determine SMS format.
769 return isCdmaVoice();
771 // IMS is registered with SMS support, check the SMS format supported
772 return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
776 * Determines whether or not to current phone type is cdma.
778 * @return true if current phone type is cdma, false otherwise.
780 private static boolean isCdmaVoice() {
781 int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
782 return (PHONE_TYPE_CDMA == activePhone);
786 * Decide if the carrier supports long SMS.
789 public static boolean hasEmsSupport() {
790 if (!isNoEmsSupportConfigListExisted()) {
796 final long identity = Binder.clearCallingIdentity();
798 simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
799 gid = TelephonyManager.getDefault().getGroupIdLevel1();
801 Binder.restoreCallingIdentity(identity);
804 if (!TextUtils.isEmpty(simOperator)) {
805 for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
806 if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
807 (TextUtils.isEmpty(currentConfig.mGid1) ||
808 (!TextUtils.isEmpty(currentConfig.mGid1) &&
809 currentConfig.mGid1.equalsIgnoreCase(gid)))) {
818 * Check where to add " x/y" in each SMS segment, begin or end.
821 public static boolean shouldAppendPageNumberAsPrefix() {
822 if (!isNoEmsSupportConfigListExisted()) {
828 final long identity = Binder.clearCallingIdentity();
830 simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
831 gid = TelephonyManager.getDefault().getGroupIdLevel1();
833 Binder.restoreCallingIdentity(identity);
836 for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
837 if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
838 (TextUtils.isEmpty(currentConfig.mGid1) ||
839 (!TextUtils.isEmpty(currentConfig.mGid1)
840 && currentConfig.mGid1.equalsIgnoreCase(gid)))) {
841 return currentConfig.mIsPrefix;
847 private static class NoEmsSupportConfig {
848 String mOperatorNumber;
852 public NoEmsSupportConfig(String[] config) {
853 mOperatorNumber = config[0];
854 mIsPrefix = "prefix".equals(config[1]);
855 mGid1 = config.length > 2 ? config[2] : null;
859 public String toString() {
860 return "NoEmsSupportConfig { mOperatorNumber = " + mOperatorNumber
861 + ", mIsPrefix = " + mIsPrefix + ", mGid1 = " + mGid1 + " }";
865 private static NoEmsSupportConfig[] mNoEmsSupportConfigList = null;
866 private static boolean mIsNoEmsSupportConfigListLoaded = false;
868 private static boolean isNoEmsSupportConfigListExisted() {
869 if (!mIsNoEmsSupportConfigListLoaded) {
870 Resources r = Resources.getSystem();
872 String[] listArray = r.getStringArray(
873 com.android.internal.R.array.no_ems_support_sim_operators);
874 if ((listArray != null) && (listArray.length > 0)) {
875 mNoEmsSupportConfigList = new NoEmsSupportConfig[listArray.length];
876 for (int i=0; i<listArray.length; i++) {
877 mNoEmsSupportConfigList[i] = new NoEmsSupportConfig(listArray[i].split(";"));
880 mIsNoEmsSupportConfigListLoaded = true;
884 if (mNoEmsSupportConfigList != null && mNoEmsSupportConfigList.length != 0) {