diff options
Diffstat (limited to 'telephony/java')
24 files changed, 1031 insertions, 1170 deletions
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 5bdc146..44bdaeb 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -325,7 +325,7 @@ public final class SmsManager { * * {@hide} */ - public ArrayList<SmsMessage> getAllMessagesFromIcc() { + public static ArrayList<SmsMessage> getAllMessagesFromIcc() { List<SmsRawData> records = null; try { @@ -470,7 +470,7 @@ public final class SmsManager { * <code>getAllMessagesFromIcc</code> * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. */ - private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { + private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); if (records != null) { int count = records.size(); diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index e75d96d..fc8a145 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -36,7 +36,6 @@ import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; * A Short Message Service message. */ public class SmsMessage { - private static final boolean LOCAL_DEBUG = true; private static final String LOG_TAG = "SMS"; /** @@ -78,6 +77,18 @@ public class SmsMessage { */ public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; + /** + * Indicates a 3GPP format SMS message. + * @hide pending API council approval + */ + public static final String FORMAT_3GPP = "3gpp"; + + /** + * Indicates a 3GPP2 format SMS message. + * @hide pending API council approval + */ + public static final String FORMAT_3GPP2 = "3gpp2"; + /** Contains actual SmsMessage. Only public for debugging and for framework layer. * * @hide @@ -106,30 +117,47 @@ public class SmsMessage { } - /** - * Constructor - * - * @hide - */ - public SmsMessage() { - this(getSmsFacility()); - } - private SmsMessage(SmsMessageBase smb) { mWrappedSmsMessage = smb; } /** * Create an SmsMessage from a raw PDU. + * + * <p><b>This method will soon be deprecated</b> and all applications which handle + * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast + * intent <b>must</b> now pass the new {@code format} String extra from the intent + * into the new method {@code createFromPdu(byte[], String)} which takes an + * extra format parameter. This is required in order to correctly decode the PDU on + * devices that require support for both 3GPP and 3GPP2 formats at the same time, + * such as dual-mode GSM/CDMA and CDMA/LTE phones. */ public static SmsMessage createFromPdu(byte[] pdu) { - SmsMessageBase wrappedMessage; int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); + String format = (PHONE_TYPE_CDMA == activePhone) ? FORMAT_3GPP2 : FORMAT_3GPP; + return createFromPdu(pdu, format); + } - if (PHONE_TYPE_CDMA == activePhone) { + /** + * Create an SmsMessage from a raw PDU with the specified message format. The + * message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format} + * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format + * or "3gpp2" for CDMA/LTE messages in 3GPP2 format. + * + * @param pdu the message PDU from the SMS_RECEIVED_ACTION intent + * @param format the format extra from the SMS_RECEIVED_ACTION intent + * @hide pending API council approval + */ + public static SmsMessage createFromPdu(byte[] pdu, String format) { + SmsMessageBase wrappedMessage; + + if (FORMAT_3GPP2.equals(format)) { wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); - } else { + } else if (FORMAT_3GPP.equals(format)) { wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); + } else { + Log.e(LOG_TAG, "createFromPdu(): unsupported message format " + format); + return null; } return new SmsMessage(wrappedMessage); @@ -144,57 +172,19 @@ public class SmsMessage { * * {@hide} */ - public static SmsMessage newFromCMT(String[] lines){ - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); - } - - return new SmsMessage(wrappedMessage); - } - - /** @hide */ - protected static SmsMessage newFromCMTI(String line) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); - } - - return new SmsMessage(wrappedMessage); - } - - /** @hide */ - public static SmsMessage newFromCDS(String line) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); - } + public static SmsMessage newFromCMT(String[] lines) { + // received SMS in 3GPP format + SmsMessageBase wrappedMessage = + com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); return new SmsMessage(wrappedMessage); } /** @hide */ public static SmsMessage newFromParcel(Parcel p) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); - } + // received SMS in 3GPP2 format + SmsMessageBase wrappedMessage = + com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); return new SmsMessage(wrappedMessage); } @@ -227,6 +217,9 @@ public class SmsMessage { /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header + * + * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices. + * We should probably deprecate it and remove the obsolete test case. */ public static int getTPLayerLengthForPDU(String pdu) { int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); @@ -381,34 +374,6 @@ public class SmsMessage { * @return a <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. - * @hide - */ - public static SubmitPdu getSubmitPdu(String scAddress, - String destinationAddress, String message, - boolean statusReportRequested, byte[] header) { - SubmitPduBase spb; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested, - SmsHeader.fromByteArray(header)); - } else { - spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, - destinationAddress, message, statusReportRequested, header); - } - - return new SubmitPdu(spb); - } - - /** - * Get an SMS-SUBMIT PDU for a destination address and a message. - * This method will not attempt to use any GSM national language 7 bit encodings. - * - * @param scAddress Service Centre address. Null means use default. - * @return a <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message. - * Returns null on encode error. */ public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested) { @@ -603,15 +568,6 @@ public class SmsMessage { } /** - * Return the user data header (UDH). - * - * @hide - */ - public SmsHeader getUserDataHeader() { - return mWrappedSmsMessage.getUserDataHeader(); - } - - /** * Returns the raw PDU for the message. * * @return the raw PDU for the message. @@ -646,7 +602,6 @@ public class SmsMessage { * SmsManager.STATUS_ON_ICC_UNSENT */ public int getStatusOnIcc() { - return mWrappedSmsMessage.getStatusOnIcc(); } @@ -666,7 +621,6 @@ public class SmsMessage { * SmsMessage was not created from a ICC SMS EF record. */ public int getIndexOnIcc() { - return mWrappedSmsMessage.getIndexOnIcc(); } @@ -704,19 +658,4 @@ public class SmsMessage { public boolean isReplyPathPresent() { return mWrappedSmsMessage.isReplyPathPresent(); } - - /** This method returns the reference to a specific - * SmsMessage object, which is used for accessing its static methods. - * @return Specific SmsMessage. - * - * @hide - */ - private static final SmsMessageBase getSmsFacility(){ - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - if (PHONE_TYPE_CDMA == activePhone) { - return new com.android.internal.telephony.cdma.SmsMessage(); - } else { - return new com.android.internal.telephony.gsm.SmsMessage(); - } - } } diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 4af99a6..8d86ec2 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -166,104 +166,6 @@ public class SmsMessage { } /** - * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the - * +CMT unsolicited response (PDU mode, of course) - * +CMT: [<alpha>],<length><CR><LF><pdu> - * - * Only public for debugging and for RIL - * @deprecated Use android.telephony.SmsMessage. - * {@hide} - */ - @Deprecated - public static SmsMessage newFromCMT(String[] lines){ - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); - } - - return new SmsMessage(wrappedMessage); - } - - /** @deprecated Use android.telephony.SmsMessage. - * @hide */ - @Deprecated - protected static SmsMessage newFromCMTI(String line) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); - } - - return new SmsMessage(wrappedMessage); - } - - /** @deprecated Use android.telephony.SmsMessage. - * @hide */ - @Deprecated - public static SmsMessage newFromCDS(String line) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); - } - - return new SmsMessage(wrappedMessage); - } - - /** @deprecated Use android.telephony.SmsMessage. - * @hide */ - @Deprecated - public static SmsMessage newFromParcel(Parcel p) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); - } - - return new SmsMessage(wrappedMessage); - } - - /** - * Create an SmsMessage from an SMS EF record. - * - * @param index Index of SMS record. This should be index in ArrayList - * returned by SmsManager.getAllMessagesFromSim + 1. - * @param data Record data. - * @return An SmsMessage representing the record. - * - * @deprecated Use android.telephony.SmsMessage. - * @hide - */ - @Deprecated - public static SmsMessage createFromEfRecord(int index, byte[] data) { - SmsMessageBase wrappedMessage; - int activePhone = TelephonyManager.getDefault().getCurrentPhoneType(); - - if (PHONE_TYPE_CDMA == activePhone) { - wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( - index, data); - } else { - wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( - index, data); - } - - return new SmsMessage(wrappedMessage); - } - - /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header * @deprecated Use android.telephony.SmsMessage. diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java index f0d2fba..f111dd6 100644 --- a/telephony/java/com/android/internal/telephony/BaseCommands.java +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -79,7 +79,8 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mRilConnectedRegistrants = new RegistrantList(); protected RegistrantList mIccRefreshRegistrants = new RegistrantList(); - protected Registrant mSMSRegistrant; + protected Registrant mGsmSmsRegistrant; + protected Registrant mCdmaSmsRegistrant; protected Registrant mNITZTimeRegistrant; protected Registrant mSignalStrengthRegistrant; protected Registrant mUSSDRegistrant; @@ -358,12 +359,20 @@ public abstract class BaseCommands implements CommandsInterface { mIccStatusChangedRegistrants.remove(h); } - public void setOnNewSMS(Handler h, int what, Object obj) { - mSMSRegistrant = new Registrant (h, what, obj); + public void setOnNewGsmSms(Handler h, int what, Object obj) { + mGsmSmsRegistrant = new Registrant (h, what, obj); } - public void unSetOnNewSMS(Handler h) { - mSMSRegistrant.clear(); + public void unSetOnNewGsmSms(Handler h) { + mGsmSmsRegistrant.clear(); + } + + public void setOnNewCdmaSms(Handler h, int what, Object obj) { + mCdmaSmsRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnNewCdmaSms(Handler h) { + mCdmaSmsRegistrant.clear(); } public void setOnNewGsmBroadcastSms(Handler h, int what, Object obj) { diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 1caea70..33eed38 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -20,8 +20,6 @@ import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import android.os.Message; import android.os.Handler; -import android.os.SystemProperties; - /** * {@hide} @@ -267,14 +265,32 @@ public interface CommandsInterface { void unregisterForRUIMReady(Handler h); /** - * unlike the register* methods, there's only one new SMS handler + * unlike the register* methods, there's only one new 3GPP format SMS handler. + * if you need to unregister, you should also tell the radio to stop + * sending SMS's to you (via AT+CNMI) + * + * AsyncResult.result is a String containing the SMS PDU + */ + void setOnNewGsmSms(Handler h, int what, Object obj); + void unSetOnNewGsmSms(Handler h); + + /** + * unlike the register* methods, there's only one new 3GPP2 format SMS handler. * if you need to unregister, you should also tell the radio to stop * sending SMS's to you (via AT+CNMI) * * AsyncResult.result is a String containing the SMS PDU */ - void setOnNewSMS(Handler h, int what, Object obj); - void unSetOnNewSMS(Handler h); + void setOnNewCdmaSms(Handler h, int what, Object obj); + void unSetOnNewCdmaSms(Handler h); + + /** + * Set the handler for SMS Cell Broadcast messages. + * + * AsyncResult.result is a byte array containing the SMS-CB PDU + */ + void setOnNewGsmBroadcastSms(Handler h, int what, Object obj); + void unSetOnNewGsmBroadcastSms(Handler h); /** * Register for NEW_SMS_ON_SIM unsolicited message diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 444f0d2..ca04eb2 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -1394,7 +1394,7 @@ public interface Phone { String getDeviceSvn(); /** - * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. + * Retrieves the unique subscriber ID, e.g., IMSI for GSM phones. */ String getSubscriberId(); @@ -1756,4 +1756,13 @@ public interface Phone { * @param response a callback message with the String response in the obj field */ void requestIsimAuthentication(String nonce, Message response); + + /** + * Sets the SIM voice message waiting indicator records. + * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported + * @param countWaiting The number of messages waiting, if known. Use + * -1 to indicate that an unknown number of + * messages are waiting + */ + void setVoiceMessageWaiting(int line, int countWaiting); } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 82f3955..a7a4908 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -112,15 +112,17 @@ public abstract class PhoneBase extends Handler implements Phone { /* Instance Variables */ public CommandsInterface mCM; protected IccFileHandler mIccFileHandler; - boolean mDnsCheckDisabled = false; + boolean mDnsCheckDisabled; public DataConnectionTracker mDataConnectionTracker; boolean mDoesRilSendMultipleCallRing; - int mCallRingContinueToken = 0; + int mCallRingContinueToken; int mCallRingDelay; public boolean mIsTheCurrentActivePhone = true; boolean mIsVoiceCapable = true; public IccRecords mIccRecords; public IccCard mIccCard; + public SmsStorageMonitor mSmsStorageMonitor; + public SmsUsageMonitor mSmsUsageMonitor; public SMSDispatcher mSMS; /** @@ -164,7 +166,7 @@ public abstract class PhoneBase extends Handler implements Phone { protected Looper mLooper; /* to insure registrants are in correct thread*/ - protected Context mContext; + protected final Context mContext; /** * PhoneNotifier is an abstraction for all system-wide @@ -238,6 +240,10 @@ public abstract class PhoneBase extends Handler implements Phone { mCallRingDelay = SystemProperties.getInt( TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000); Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay); + + // Initialize device storage and outgoing SMS usage monitors for SMSDispatchers. + mSmsStorageMonitor = new SmsStorageMonitor(this); + mSmsUsageMonitor = new SmsUsageMonitor(context.getContentResolver()); } public void dispose() { @@ -246,9 +252,17 @@ public abstract class PhoneBase extends Handler implements Phone { // Must cleanup all connectionS and needs to use sendMessage! mDataConnectionTracker.cleanUpAllConnections(null); mIsTheCurrentActivePhone = false; + // Dispose the SMS usage and storage monitors + mSmsStorageMonitor.dispose(); + mSmsUsageMonitor.dispose(); } } + public void removeReferences() { + mSmsStorageMonitor = null; + mSmsUsageMonitor = null; + } + /** * When overridden the derived class needs to call * super.handleMessage(msg) so this method has a @@ -1037,37 +1051,6 @@ public abstract class PhoneBase extends Handler implements Phone { } /** - * simulateDataConnection - * - * simulates various data connection states. This messes with - * DataConnectionTracker's internal states, but doesn't actually change - * the underlying radio connection states. - * - * @param state Phone.DataState enum. - */ - public void simulateDataConnection(Phone.DataState state) { - DataConnectionTracker.State dcState; - - switch (state) { - case CONNECTED: - dcState = DataConnectionTracker.State.CONNECTED; - break; - case SUSPENDED: - dcState = DataConnectionTracker.State.CONNECTED; - break; - case DISCONNECTED: - dcState = DataConnectionTracker.State.FAILED; - break; - default: - dcState = DataConnectionTracker.State.CONNECTING; - break; - } - - mDataConnectionTracker.setState(dcState); - notifyDataConnection(null, Phone.APN_TYPE_DEFAULT); - } - - /** * Notify registrants of a new ringing Connection. * Subclasses of Phone probably want to replace this with a * version scoped to their packages @@ -1132,7 +1115,7 @@ public abstract class PhoneBase extends Handler implements Phone { /** * Common error logger method for unexpected calls to CDMA-only methods. */ - private void logUnexpectedCdmaMethodCall(String name) + private static void logUnexpectedCdmaMethodCall(String name) { Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " + "called, CDMAPhone inactive."); @@ -1145,7 +1128,7 @@ public abstract class PhoneBase extends Handler implements Phone { /** * Common error logger method for unexpected calls to GSM/WCDMA-only methods. */ - private void logUnexpectedGsmMethodCall(String name) { + private static void logUnexpectedGsmMethodCall(String name) { Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " + "called, GSMPhone inactive."); } @@ -1167,4 +1150,16 @@ public abstract class PhoneBase extends Handler implements Phone { public int getLteOnCdmaMode() { return mCM.getLteOnCdmaMode(); } + + /** + * Sets the SIM voice message waiting indicator records. + * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported + * @param countWaiting The number of messages waiting, if known. Use + * -1 to indicate that an unknown number of + * messages are waiting + */ + @Override + public void setVoiceMessageWaiting(int line, int countWaiting) { + mIccRecords.setVoiceMessageWaiting(line, countWaiting); + } } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index e0e8d49..b497ec8 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -72,7 +72,7 @@ public class PhoneProxy extends Handler implements Phone { switch(msg.what) { case EVENT_RADIO_TECHNOLOGY_CHANGED: //switch Phone from CDMA to GSM or vice versa - mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName(); + mOutgoingPhone = mActivePhone.getPhoneName(); logd("Switching phone from " + mOutgoingPhone + "Phone to " + (mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") ); boolean oldPowerState = false; // old power state to off @@ -144,23 +144,10 @@ public class PhoneProxy extends Handler implements Phone { super.handleMessage(msg); } - private void logv(String msg) { - Log.v(LOG_TAG, "[PhoneProxy] " + msg); - } - - private void logd(String msg) { + private static void logd(String msg) { Log.d(LOG_TAG, "[PhoneProxy] " + msg); } - private void logw(String msg) { - Log.w(LOG_TAG, "[PhoneProxy] " + msg); - } - - private void loge(String msg) { - Log.e(LOG_TAG, "[PhoneProxy] " + msg); - } - - public ServiceState getServiceState() { return mActivePhone.getServiceState(); } @@ -739,19 +726,19 @@ public class PhoneProxy extends Handler implements Phone { } public int getCdmaEriIconIndex() { - return mActivePhone.getCdmaEriIconIndex(); + return mActivePhone.getCdmaEriIconIndex(); } - public String getCdmaEriText() { - return mActivePhone.getCdmaEriText(); - } + public String getCdmaEriText() { + return mActivePhone.getCdmaEriText(); + } public int getCdmaEriIconMode() { - return mActivePhone.getCdmaEriIconMode(); + return mActivePhone.getCdmaEriIconMode(); } public Phone getActivePhone() { - return mActivePhone; + return mActivePhone; } public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){ @@ -861,4 +848,9 @@ public class PhoneProxy extends Handler implements Phone { public int getLteOnCdmaMode() { return mActivePhone.getLteOnCdmaMode(); } + + @Override + public void setVoiceMessageWaiting(int line, int countWaiting) { + mActivePhone.setVoiceMessageWaiting(line, countWaiting); + } } diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index bd35058..8aae0d4 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -2434,8 +2434,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { SmsMessage sms; sms = SmsMessage.newFromCMT(a); - if (mSMSRegistrant != null) { - mSMSRegistrant + if (mGsmSmsRegistrant != null) { + mGsmSmsRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); } break; @@ -2607,8 +2607,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { SmsMessage sms = (SmsMessage) ret; - if (mSMSRegistrant != null) { - mSMSRegistrant + if (mCdmaSmsRegistrant != null) { + mCdmaSmsRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); } break; diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 76e719c..e4c6028 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -44,10 +44,12 @@ import android.telephony.ServiceState; import android.util.Log; import android.view.WindowManager; +import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Random; @@ -60,68 +62,66 @@ import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED; import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE; - public abstract class SMSDispatcher extends Handler { - private static final String TAG = "SMS"; + static final String TAG = "SMS"; // accessed from inner class private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg"; - /** Default checking period for SMS sent without user permit */ - private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; - - /** Default number of SMS sent in checking period without user permit */ - private static final int DEFAULT_SMS_MAX_COUNT = 100; - /** Default timeout for SMS sent query */ private static final int DEFAULT_SMS_TIMEOUT = 6000; - protected static final String[] RAW_PROJECTION = new String[] { - "pdu", - "sequence", - "destination_port", + /** Permission required to receive SMS and SMS-CB messages. */ + public static final String RECEIVE_SMS_PERMISSION = "android.permission.RECEIVE_SMS"; + + /** Permission required to receive ETWS and CMAS emergency broadcasts. */ + public static final String RECEIVE_EMERGENCY_BROADCAST_PERMISSION = + "android.permission.RECEIVE_EMERGENCY_BROADCAST"; + + /** Query projection for checking for duplicate message segments. */ + private static final String[] PDU_PROJECTION = new String[] { + "pdu" }; - static final protected int EVENT_NEW_SMS = 1; + /** Query projection for combining concatenated message segments. */ + private static final String[] PDU_SEQUENCE_PORT_PROJECTION = new String[] { + "pdu", + "sequence", + "destination_port" + }; - static final protected int EVENT_SEND_SMS_COMPLETE = 2; + private static final int PDU_COLUMN = 0; + private static final int SEQUENCE_COLUMN = 1; + private static final int DESTINATION_PORT_COLUMN = 2; - /** Retry sending a previously failed SMS message */ - static final protected int EVENT_SEND_RETRY = 3; + /** New SMS received. */ + protected static final int EVENT_NEW_SMS = 1; - /** Status report received */ - static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5; + /** SMS send complete. */ + protected static final int EVENT_SEND_SMS_COMPLETE = 2; - /** SIM/RUIM storage is full */ - static final protected int EVENT_ICC_FULL = 6; + /** Retry sending a previously failed SMS message */ + private static final int EVENT_SEND_RETRY = 3; /** SMS confirm required */ - static final protected int EVENT_POST_ALERT = 7; + private static final int EVENT_POST_ALERT = 4; /** Send the user confirmed SMS */ - static final protected int EVENT_SEND_CONFIRMED_SMS = 8; + static final int EVENT_SEND_CONFIRMED_SMS = 5; // accessed from inner class /** Alert is timeout */ - static final protected int EVENT_ALERT_TIMEOUT = 9; + private static final int EVENT_ALERT_TIMEOUT = 6; /** Stop the sending */ - static final protected int EVENT_STOP_SENDING = 10; - - /** Memory status reporting is acknowledged by RIL */ - static final protected int EVENT_REPORT_MEMORY_STATUS_DONE = 11; - - /** Radio is ON */ - static final protected int EVENT_RADIO_ON = 12; + static final int EVENT_STOP_SENDING = 7; // accessed from inner class - /** New broadcast SMS */ - static final protected int EVENT_NEW_BROADCAST_SMS = 13; - - protected Phone mPhone; - protected Context mContext; - protected ContentResolver mResolver; - protected CommandsInterface mCm; + protected final Phone mPhone; + protected final Context mContext; + protected final ContentResolver mResolver; + protected final CommandsInterface mCm; + protected final SmsStorageMonitor mStorageMonitor; protected final WapPushOverSms mWapPush; - protected final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); + protected static final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); /** Maximum number of times to retry sending a failed SMS. */ private static final int MAX_SEND_RETRIES = 3; @@ -136,12 +136,14 @@ public abstract class SMSDispatcher extends Handler { * Message reference for a CONCATENATED_8_BIT_REFERENCE or * CONCATENATED_16_BIT_REFERENCE message set. Should be * incremented for each set of concatenated messages. + * Static field shared by all dispatcher objects. */ - private static int sConcatenatedRef; + private static int sConcatenatedRef = new Random().nextInt(256); - private SmsCounter mCounter; + /** Outgoing message counter. Shared by all dispatchers. */ + private final SmsUsageMonitor mUsageMonitor; - private ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT); + private final ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT); /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ private PowerManager.WakeLock mWakeLock; @@ -150,17 +152,14 @@ public abstract class SMSDispatcher extends Handler { * Hold the wake lock for 5 seconds, which should be enough time for * any receiver(s) to grab its own wake lock. */ - private final int WAKE_LOCK_TIMEOUT = 5000; - - protected boolean mStorageAvailable = true; - protected boolean mReportMemoryStatusPending = false; + private static final int WAKE_LOCK_TIMEOUT = 5000; /* Flags indicating whether the current device allows sms service */ protected boolean mSmsCapable = true; protected boolean mSmsReceiveDisabled; protected boolean mSmsSendDisabled; - protected static int mRemainingMessages = -1; + protected int mRemainingMessages = -1; protected static int getNextConcatenatedRef() { sConcatenatedRef += 1; @@ -168,111 +167,52 @@ public abstract class SMSDispatcher extends Handler { } /** - * Implement the per-application based SMS control, which only allows - * a limit on the number of SMS/MMS messages an app can send in checking - * period. + * Create a new SMS dispatcher. + * @param phone the Phone to use + * @param storageMonitor the SmsStorageMonitor to use + * @param usageMonitor the SmsUsageMonitor to use */ - private class SmsCounter { - private int mCheckPeriod; - private int mMaxAllowed; - private HashMap<String, ArrayList<Long>> mSmsStamp; - - /** - * Create SmsCounter - * @param mMax is the number of SMS allowed without user permit - * @param mPeriod is the checking period - */ - SmsCounter(int mMax, int mPeriod) { - mMaxAllowed = mMax; - mCheckPeriod = mPeriod; - mSmsStamp = new HashMap<String, ArrayList<Long>> (); - } - - /** - * Check to see if an application allow to send new SMS messages - * - * @param appName is the application sending sms - * @param smsWaiting is the number of new sms wants to be sent - * @return true if application is allowed to send the requested number - * of new sms messages - */ - boolean check(String appName, int smsWaiting) { - if (!mSmsStamp.containsKey(appName)) { - mSmsStamp.put(appName, new ArrayList<Long>()); - } - - return isUnderLimit(mSmsStamp.get(appName), smsWaiting); - } - - private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) { - Long ct = System.currentTimeMillis(); - - Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct); - - while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) { - sent.remove(0); - } - - - if ( (sent.size() + smsWaiting) <= mMaxAllowed) { - for (int i = 0; i < smsWaiting; i++ ) { - sent.add(ct); - } - return true; - } - return false; - } - } - - protected SMSDispatcher(PhoneBase phone) { + protected SMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor, + SmsUsageMonitor usageMonitor) { mPhone = phone; mWapPush = new WapPushOverSms(phone, this); mContext = phone.getContext(); mResolver = mContext.getContentResolver(); mCm = phone.mCM; + mStorageMonitor = storageMonitor; + mUsageMonitor = usageMonitor; createWakelock(); - int check_period = Settings.Secure.getInt(mResolver, - Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, - DEFAULT_SMS_CHECK_PERIOD); - int max_count = Settings.Secure.getInt(mResolver, - Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT, - DEFAULT_SMS_MAX_COUNT); - mCounter = new SmsCounter(max_count, check_period); - - mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); - mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); - mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null); - mCm.registerForOn(this, EVENT_RADIO_ON, null); - - // Don't always start message ref at 0. - sConcatenatedRef = new Random().nextInt(256); - - // Register for device storage intents. Use these to notify the RIL - // that storage for SMS is or is not available. - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL); - filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); - mContext.registerReceiver(mResultReceiver, filter); - mSmsCapable = mContext.getResources().getBoolean( com.android.internal.R.bool.config_sms_capable); mSmsReceiveDisabled = !SystemProperties.getBoolean( TelephonyProperties.PROPERTY_SMS_RECEIVE, mSmsCapable); mSmsSendDisabled = !SystemProperties.getBoolean( TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable); - Log.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + Log.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat() + " mSmsReceiveDisabled=" + mSmsReceiveDisabled + " mSmsSendDisabled=" + mSmsSendDisabled); } - public void dispose() { - mCm.unSetOnNewSMS(this); - mCm.unSetOnSmsStatus(this); - mCm.unSetOnIccSmsFull(this); - mCm.unregisterForOn(this); - } + /** Unregister for incoming SMS events. */ + public abstract void dispose(); + + /** + * The format of the message PDU in the associated broadcast intent. + * This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format + * or "3gpp2" for CDMA/LTE messages in 3GPP2 format. + * + * Note: All applications which handle incoming SMS messages by processing the + * SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent + * into the new methods in {@link android.telephony.SmsMessage} which take an + * extra format parameter. This is required in order to correctly decode the PDU on + * devices which require support for both 3GPP and 3GPP2 formats at the same time, + * such as CDMA/LTE devices and GSM/CDMA world phones. + * + * @return the format of the message PDU + */ + protected abstract String getFormat(); @Override protected void finalize() { @@ -338,14 +278,6 @@ public abstract class SMSDispatcher extends Handler { sendSms((SmsTracker) msg.obj); break; - case EVENT_NEW_SMS_STATUS_REPORT: - handleStatusReport((AsyncResult)msg.obj); - break; - - case EVENT_ICC_FULL: - handleIccFull(); - break; - case EVENT_POST_ALERT: handleReachSentLimit((SmsTracker)(msg.obj)); break; @@ -369,7 +301,7 @@ public abstract class SMSDispatcher extends Handler { case EVENT_SEND_CONFIRMED_SMS: if (mSTrackers.isEmpty() == false) { SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1); - if (isMultipartTracker(sTracker)) { + if (sTracker.isMultipart()) { sendMultipartSms(sTracker); } else { sendSms(sTracker); @@ -390,30 +322,6 @@ public abstract class SMSDispatcher extends Handler { removeMessages(EVENT_ALERT_TIMEOUT, msg.obj); } break; - - case EVENT_REPORT_MEMORY_STATUS_DONE: - ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - mReportMemoryStatusPending = true; - Log.v(TAG, "Memory status report to modem pending : mStorageAvailable = " - + mStorageAvailable); - } else { - mReportMemoryStatusPending = false; - } - break; - - case EVENT_RADIO_ON: - if (mReportMemoryStatusPending) { - Log.v(TAG, "Sending pending memory status report : mStorageAvailable = " - + mStorageAvailable); - mCm.reportSmsMemoryStatus(mStorageAvailable, - obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); - } - break; - - case EVENT_NEW_BROADCAST_SMS: - handleBroadcastSms((AsyncResult)msg.obj); - break; } } @@ -440,26 +348,6 @@ public abstract class SMSDispatcher extends Handler { } /** - * Called when SIM_FULL message is received from the RIL. Notifies interested - * parties that SIM storage for SMS messages is full. - */ - private void handleIccFull(){ - // broadcast SIM_FULL intent - Intent intent = new Intent(Intents.SIM_FULL_ACTION); - mWakeLock.acquire(WAKE_LOCK_TIMEOUT); - mContext.sendBroadcast(intent, "android.permission.RECEIVE_SMS"); - } - - /** - * Called when a status report is received. This should correspond to - * a previously successful SEND. - * - * @param ar AsyncResult passed into the message handler. ar.result should - * be a String representing the status report PDU, as ASCII hex. - */ - protected abstract void handleStatusReport(AsyncResult ar); - - /** * Called when SMS send completes. Broadcasts a sentIntent on success. * On failure, either sets up retries or broadcasts a sentIntent with * the failure in the result code. @@ -559,7 +447,7 @@ public abstract class SMSDispatcher extends Handler { * POWER_OFF * @param tracker An SmsTracker for the current message. */ - protected void handleNotInService(int ss, SmsTracker tracker) { + protected static void handleNotInService(int ss, SmsTracker tracker) { if (tracker.mSentIntent != null) { try { if (ss == ServiceState.STATE_POWER_OFF) { @@ -581,86 +469,171 @@ public abstract class SMSDispatcher extends Handler { */ public abstract int dispatchMessage(SmsMessageBase sms); + /** + * Dispatch a normal incoming SMS. This is called from the format-specific + * {@link #dispatchMessage(SmsMessageBase)} if no format-specific handling is required. + * + * @param sms + * @return + */ + protected int dispatchNormalMessage(SmsMessageBase sms) { + SmsHeader smsHeader = sms.getUserDataHeader(); + + // See if message is partial or port addressed. + if ((smsHeader == null) || (smsHeader.concatRef == null)) { + // Message is not partial (not part of concatenated sequence). + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (smsHeader != null && smsHeader.portAddrs != null) { + if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { + // GSM-style WAP indication + return mWapPush.dispatchWapPdu(sms.getUserData()); + } else { + // The message was sent to a port, so concoct a URI for it. + dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort); + } + } else { + // Normal short and non-port-addressed message, dispatch it. + dispatchPdus(pdus); + } + return Activity.RESULT_OK; + } else { + // Process the message part. + SmsHeader.ConcatRef concatRef = smsHeader.concatRef; + SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs; + return processMessagePart(sms.getPdu(), sms.getOriginatingAddress(), + concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount, + sms.getTimestampMillis(), (portAddrs != null ? portAddrs.destPort : -1), false); + } + } /** * If this is the last part send the parts out to the application, otherwise - * the part is stored for later processing. + * the part is stored for later processing. Handles both 3GPP concatenated messages + * as well as 3GPP2 format WAP push messages processed by + * {@link com.android.internal.telephony.cdma.CdmaSMSDispatcher#processCdmaWapPdu}. + * + * @param pdu the message PDU, or the datagram portion of a CDMA WDP datagram segment + * @param address the originating address + * @param referenceNumber distinguishes concatenated messages from the same sender + * @param sequenceNumber the order of this segment in the message + * @param messageCount the number of segments in the message + * @param timestamp the service center timestamp in millis + * @param destPort the destination port for the message, or -1 for no destination port + * @param isCdmaWapPush true if pdu is a CDMA WDP datagram segment and not an SM PDU * - * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null. * @return a result code from {@link Telephony.Sms.Intents}, or * {@link Activity#RESULT_OK} if the message has been broadcast * to applications */ - protected int processMessagePart(SmsMessageBase sms, - SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) { - - // Lookup all other related parts - StringBuilder where = new StringBuilder("reference_number ="); - where.append(concatRef.refNumber); - where.append(" AND address = ?"); - String[] whereArgs = new String[] {sms.getOriginatingAddress()}; - + protected int processMessagePart(byte[] pdu, String address, int referenceNumber, + int sequenceNumber, int messageCount, long timestamp, int destPort, + boolean isCdmaWapPush) { byte[][] pdus = null; Cursor cursor = null; try { - cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); + // used by several query selection arguments + String refNumber = Integer.toString(referenceNumber); + String seqNumber = Integer.toString(sequenceNumber); + + // Check for duplicate message segment + cursor = mResolver.query(mRawUri, PDU_PROJECTION, + "address=? AND reference_number=? AND sequence=?", + new String[] {address, refNumber, seqNumber}, null); + + // moveToNext() returns false if no duplicates were found + if (cursor.moveToNext()) { + Log.w(TAG, "Discarding duplicate message segment from address=" + address + + " refNumber=" + refNumber + " seqNumber=" + seqNumber); + String oldPduString = cursor.getString(PDU_COLUMN); + byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString); + if (!Arrays.equals(oldPdu, pdu)) { + Log.e(TAG, "Warning: dup message segment PDU of length " + pdu.length + + " is different from existing PDU of length " + oldPdu.length); + } + return Intents.RESULT_SMS_HANDLED; + } + cursor.close(); + + // not a dup, query for all other segments of this concatenated message + String where = "address=? AND reference_number=?"; + String[] whereArgs = new String[] {address, refNumber}; + cursor = mResolver.query(mRawUri, PDU_SEQUENCE_PORT_PROJECTION, where, whereArgs, null); + int cursorCount = cursor.getCount(); - if (cursorCount != concatRef.msgCount - 1) { + if (cursorCount != messageCount - 1) { // We don't have all the parts yet, store this one away ContentValues values = new ContentValues(); - values.put("date", new Long(sms.getTimestampMillis())); - values.put("pdu", HexDump.toHexString(sms.getPdu())); - values.put("address", sms.getOriginatingAddress()); - values.put("reference_number", concatRef.refNumber); - values.put("count", concatRef.msgCount); - values.put("sequence", concatRef.seqNumber); - if (portAddrs != null) { - values.put("destination_port", portAddrs.destPort); + values.put("date", timestamp); + values.put("pdu", HexDump.toHexString(pdu)); + values.put("address", address); + values.put("reference_number", referenceNumber); + values.put("count", messageCount); + values.put("sequence", sequenceNumber); + if (destPort != -1) { + values.put("destination_port", destPort); } mResolver.insert(mRawUri, values); return Intents.RESULT_SMS_HANDLED; } // All the parts are in place, deal with them - int pduColumn = cursor.getColumnIndex("pdu"); - int sequenceColumn = cursor.getColumnIndex("sequence"); - - pdus = new byte[concatRef.msgCount][]; + pdus = new byte[messageCount][]; for (int i = 0; i < cursorCount; i++) { cursor.moveToNext(); - int cursorSequence = (int)cursor.getLong(sequenceColumn); + int cursorSequence = cursor.getInt(SEQUENCE_COLUMN); pdus[cursorSequence - 1] = HexDump.hexStringToByteArray( - cursor.getString(pduColumn)); + cursor.getString(PDU_COLUMN)); + + // Read the destination port from the first segment (needed for CDMA WAP PDU). + // It's not a bad idea to prefer the port from the first segment for 3GPP as well. + if (cursorSequence == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) { + destPort = cursor.getInt(DESTINATION_PORT_COLUMN); + } } // This one isn't in the DB, so add it - pdus[concatRef.seqNumber - 1] = sms.getPdu(); + pdus[sequenceNumber - 1] = pdu; // Remove the parts from the database - mResolver.delete(mRawUri, where.toString(), whereArgs); + mResolver.delete(mRawUri, where, whereArgs); } catch (SQLException e) { Log.e(TAG, "Can't access multipart SMS database", e); - // TODO: Would OUT_OF_MEMORY be more appropriate? return Intents.RESULT_SMS_GENERIC_ERROR; } finally { if (cursor != null) cursor.close(); } - /** - * TODO(cleanup): The following code has duplicated logic with - * the radio-specific dispatchMessage code, which is fragile, - * in addition to being redundant. Instead, if this method - * maybe returned the reassembled message (or just contents), - * the following code (which is not really related to - * reconstruction) could be better consolidated. - */ + // Special handling for CDMA WDP datagrams + if (isCdmaWapPush) { + // Build up the data stream + ByteArrayOutputStream output = new ByteArrayOutputStream(); + for (int i = 0; i < messageCount; i++) { + // reassemble the (WSP-)pdu + output.write(pdus[i], 0, pdus[i].length); + } + byte[] datagram = output.toByteArray(); + + // Dispatch the PDU to applications + if (destPort == SmsHeader.PORT_WAP_PUSH) { + // Handle the PUSH + return mWapPush.dispatchWapPdu(datagram); + } else { + pdus = new byte[1][]; + pdus[0] = datagram; + // The messages were sent to any other WAP port + dispatchPortAddressedPdus(pdus, destPort); + return Activity.RESULT_OK; + } + } // Dispatch the PDUs to applications - if (portAddrs != null) { - if (portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { + if (destPort != -1) { + if (destPort == SmsHeader.PORT_WAP_PUSH) { // Build up the data stream ByteArrayOutputStream output = new ByteArrayOutputStream(); - for (int i = 0; i < concatRef.msgCount; i++) { - SmsMessage msg = SmsMessage.createFromPdu(pdus[i]); + for (int i = 0; i < messageCount; i++) { + SmsMessage msg = SmsMessage.createFromPdu(pdus[i], getFormat()); byte[] data = msg.getUserData(); output.write(data, 0, data.length); } @@ -668,7 +641,7 @@ public abstract class SMSDispatcher extends Handler { return mWapPush.dispatchWapPdu(output.toByteArray()); } else { // The messages were sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, portAddrs.destPort); + dispatchPortAddressedPdus(pdus, destPort); } } else { // The messages were not sent to a port @@ -685,7 +658,8 @@ public abstract class SMSDispatcher extends Handler { protected void dispatchPdus(byte[][] pdus) { Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); intent.putExtra("pdus", pdus); - dispatch(intent, "android.permission.RECEIVE_SMS"); + intent.putExtra("format", getFormat()); + dispatch(intent, RECEIVE_SMS_PERMISSION); } /** @@ -698,7 +672,8 @@ public abstract class SMSDispatcher extends Handler { Uri uri = Uri.parse("sms://localhost:" + port); Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); intent.putExtra("pdus", pdus); - dispatch(intent, "android.permission.RECEIVE_SMS"); + intent.putExtra("format", getFormat()); + dispatch(intent, RECEIVE_SMS_PERMISSION); } /** @@ -759,6 +734,16 @@ public abstract class SMSDispatcher extends Handler { String text, PendingIntent sentIntent, PendingIntent deliveryIntent); /** + * Calculate the number of septets needed to encode the message. + * + * @param messageBody the message to encode + * @param use7bitOnly ignore (but still count) illegal characters if true + * @return TextEncodingDetails + */ + protected abstract TextEncodingDetails calculateLength(CharSequence messageBody, + boolean use7bitOnly); + + /** * Send a multi-part text based SMS. * * @param destAddr the address to send the message to @@ -784,9 +769,70 @@ public abstract class SMSDispatcher extends Handler { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - protected abstract void sendMultipartText(String destAddr, String scAddr, + protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, - ArrayList<PendingIntent> deliveryIntents); + ArrayList<PendingIntent> deliveryIntents) { + + int refNumber = getNextConcatenatedRef() & 0x00FF; + int msgCount = parts.size(); + int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN; + + mRemainingMessages = msgCount; + + TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; + for (int i = 0; i < msgCount; i++) { + TextEncodingDetails details = calculateLength(parts.get(i), false); + if (encoding != details.codeUnitSize + && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN + || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) { + encoding = details.codeUnitSize; + } + encodingForParts[i] = details; + } + + for (int i = 0; i < msgCount; i++) { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = i + 1; // 1-based sequence + 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 == android.telephony.SmsMessage.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); + } + + sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding, + sentIntent, deliveryIntent, (i == (msgCount - 1))); + } + + } + + /** + * Create a new SubmitPdu and send it. + */ + protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress, + String message, SmsHeader smsHeader, int encoding, + PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart); /** * Send a SMS @@ -842,7 +888,7 @@ public abstract class SMSDispatcher extends Handler { handleNotInService(ss, tracker); } else { String appName = getAppNameByIntent(sentIntent); - if (mCounter.check(appName, SINGLE_PART_SMS)) { + if (mUsageMonitor.check(appName, SINGLE_PART_SMS)) { sendSms(tracker); } else { sendMessage(obtainMessage(EVENT_POST_ALERT, tracker)); @@ -885,7 +931,7 @@ public abstract class SMSDispatcher extends Handler { DEFAULT_SMS_TIMEOUT); } - protected String getAppNameByIntent(PendingIntent intent) { + protected static String getAppNameByIntent(PendingIntent intent) { Resources r = Resources.getSystem(); return (intent != null) ? intent.getTargetPackage() : r.getString(R.string.sms_control_default_app_name); @@ -903,7 +949,35 @@ public abstract class SMSDispatcher extends Handler { * * @param tracker holds the multipart Sms tracker ready to be sent */ - protected abstract void sendMultipartSms (SmsTracker tracker); + private void sendMultipartSms(SmsTracker tracker) { + ArrayList<String> parts; + ArrayList<PendingIntent> sentIntents; + ArrayList<PendingIntent> deliveryIntents; + + HashMap<String, Object> map = tracker.mData; + + String destinationAddress = (String) map.get("destination"); + String scAddress = (String) map.get("scaddress"); + + parts = (ArrayList<String>) map.get("parts"); + sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents"); + deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents"); + + // check if in service + int ss = mPhone.getServiceState().getState(); + if (ss != ServiceState.STATE_IN_SERVICE) { + for (int i = 0, count = parts.size(); i < count; i++) { + PendingIntent sentIntent = null; + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + handleNotInService(ss, new SmsTracker(null, sentIntent, null)); + } + return; + } + + sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents); + } /** * Send an acknowledge message. @@ -934,66 +1008,38 @@ public abstract class SMSDispatcher extends Handler { } /** - * Check if a SmsTracker holds multi-part Sms - * - * @param tracker a SmsTracker could hold a multi-part Sms - * @return true for tracker holds Multi-parts Sms - */ - private boolean isMultipartTracker (SmsTracker tracker) { - HashMap map = tracker.mData; - return ( map.get("parts") != null); - } - - /** * Keeps track of an SMS that has been sent to the RIL, until it has * successfully been sent, or we're done trying. * */ - static protected class SmsTracker { + protected static final class SmsTracker { // fields need to be public for derived SmsDispatchers - public HashMap<String, Object> mData; + public final HashMap<String, Object> mData; public int mRetryCount; public int mMessageRef; - public PendingIntent mSentIntent; - public PendingIntent mDeliveryIntent; + public final PendingIntent mSentIntent; + public final PendingIntent mDeliveryIntent; - SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, + public SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent) { mData = data; mSentIntent = sentIntent; mDeliveryIntent = deliveryIntent; mRetryCount = 0; } - } - - protected SmsTracker SmsTrackerFactory(HashMap<String, Object> data, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - return new SmsTracker(data, sentIntent, deliveryIntent); - } - - public void initSipStack(boolean isObg) { - // This function should be overridden by the classes that support - // switching modes such as the CdmaSMSDispatcher. - // Not implemented in GsmSMSDispatcher. - Log.e(TAG, "Error! This function should never be executed."); - } - - public void switchToCdma() { - // This function should be overridden by the classes that support - // switching modes such as the CdmaSMSDispatcher. - // Not implemented in GsmSMSDispatcher. - Log.e(TAG, "Error! This function should never be executed."); - } - public void switchToGsm() { - // This function should be overridden by the classes that support - // switching modes such as the CdmaSMSDispatcher. - // Not implemented in GsmSMSDispatcher. - Log.e(TAG, "Error! This function should never be executed."); + /** + * Returns whether this tracker holds a multi-part SMS. + * @return true if the tracker holds a multi-part SMS; false otherwise + */ + protected boolean isMultipart() { + HashMap map = mData; + return map.containsKey("parts"); + } } - private DialogInterface.OnClickListener mListener = + private final DialogInterface.OnClickListener mListener = new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { @@ -1007,42 +1053,32 @@ public abstract class SMSDispatcher extends Handler { } }; - private BroadcastReceiver mResultReceiver = new BroadcastReceiver() { + private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_FULL)) { - mStorageAvailable = false; - mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); - } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)) { - mStorageAvailable = true; - mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); - } else { - // Assume the intent is one of the SMS receive intents that - // was sent as an ordered broadcast. Check result and ACK. - int rc = getResultCode(); - boolean success = (rc == Activity.RESULT_OK) - || (rc == Intents.RESULT_SMS_HANDLED); - - // For a multi-part message, this only ACKs the last part. - // Previous parts were ACK'd as they were received. - acknowledgeLastIncomingSms(success, rc, null); - } + // Assume the intent is one of the SMS receive intents that + // was sent as an ordered broadcast. Check result and ACK. + int rc = getResultCode(); + boolean success = (rc == Activity.RESULT_OK) + || (rc == Intents.RESULT_SMS_HANDLED); + + // For a multi-part message, this only ACKs the last part. + // Previous parts were ACK'd as they were received. + acknowledgeLastIncomingSms(success, rc, null); } }; - protected abstract void handleBroadcastSms(AsyncResult ar); - protected void dispatchBroadcastPdus(byte[][] pdus, boolean isEmergencyMessage) { if (isEmergencyMessage) { Intent intent = new Intent(Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION); intent.putExtra("pdus", pdus); Log.d(TAG, "Dispatching " + pdus.length + " emergency SMS CB pdus"); - dispatch(intent, "android.permission.RECEIVE_EMERGENCY_BROADCAST"); + dispatch(intent, RECEIVE_EMERGENCY_BROADCAST_PERMISSION); } else { Intent intent = new Intent(Intents.SMS_CB_RECEIVED_ACTION); intent.putExtra("pdus", pdus); Log.d(TAG, "Dispatching " + pdus.length + " SMS CB pdus"); - dispatch(intent, "android.permission.RECEIVE_SMS"); + dispatch(intent, RECEIVE_SMS_PERMISSION); } } } diff --git a/telephony/java/com/android/internal/telephony/SmsStorageMonitor.java b/telephony/java/com/android/internal/telephony/SmsStorageMonitor.java new file mode 100644 index 0000000..0c06ffc --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsStorageMonitor.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.PowerManager; +import android.provider.Telephony.Sms.Intents; +import android.util.Log; + +/** + * Monitors the device and ICC storage, and sends the appropriate events. + * + * This code was formerly part of {@link SMSDispatcher}, and has been moved + * into a separate class to support instantiation of multiple SMSDispatchers on + * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. + */ +public final class SmsStorageMonitor extends Handler { + private static final String TAG = "SmsStorageMonitor"; + + /** SIM/RUIM storage is full */ + private static final int EVENT_ICC_FULL = 1; + + /** Memory status reporting is acknowledged by RIL */ + private static final int EVENT_REPORT_MEMORY_STATUS_DONE = 2; + + /** Radio is ON */ + private static final int EVENT_RADIO_ON = 3; + + /** Context from phone object passed to constructor. */ + private final Context mContext; + + /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ + private PowerManager.WakeLock mWakeLock; + + private boolean mReportMemoryStatusPending; + + final CommandsInterface mCm; // accessed from inner class + boolean mStorageAvailable = true; // accessed from inner class + + /** + * Hold the wake lock for 5 seconds, which should be enough time for + * any receiver(s) to grab its own wake lock. + */ + private static final int WAKE_LOCK_TIMEOUT = 5000; + + /** + * Creates an SmsStorageMonitor and registers for events. + * @param phone the Phone to use + */ + public SmsStorageMonitor(PhoneBase phone) { + mContext = phone.getContext(); + mCm = phone.mCM; + + createWakelock(); + + mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null); + mCm.registerForOn(this, EVENT_RADIO_ON, null); + + // Register for device storage intents. Use these to notify the RIL + // that storage for SMS is or is not available. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL); + filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); + mContext.registerReceiver(mResultReceiver, filter); + } + + public void dispose() { + mCm.unSetOnIccSmsFull(this); + mCm.unregisterForOn(this); + mContext.unregisterReceiver(mResultReceiver); + } + + /** + * Handles events coming from the phone stack. Overridden from handler. + * @param msg the message to handle + */ + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_ICC_FULL: + handleIccFull(); + break; + + case EVENT_REPORT_MEMORY_STATUS_DONE: + ar = (AsyncResult) msg.obj; + if (ar.exception != null) { + mReportMemoryStatusPending = true; + Log.v(TAG, "Memory status report to modem pending : mStorageAvailable = " + + mStorageAvailable); + } else { + mReportMemoryStatusPending = false; + } + break; + + case EVENT_RADIO_ON: + if (mReportMemoryStatusPending) { + Log.v(TAG, "Sending pending memory status report : mStorageAvailable = " + + mStorageAvailable); + mCm.reportSmsMemoryStatus(mStorageAvailable, + obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); + } + break; + } + } + + private void createWakelock() { + PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SmsStorageMonitor"); + mWakeLock.setReferenceCounted(true); + } + + /** + * Called when SIM_FULL message is received from the RIL. Notifies interested + * parties that SIM storage for SMS messages is full. + */ + private void handleIccFull() { + // broadcast SIM_FULL intent + Intent intent = new Intent(Intents.SIM_FULL_ACTION); + mWakeLock.acquire(WAKE_LOCK_TIMEOUT); + mContext.sendBroadcast(intent, SMSDispatcher.RECEIVE_SMS_PERMISSION); + } + + /** Returns whether or not there is storage available for an incoming SMS. */ + public boolean isStorageAvailable() { + return mStorageAvailable; + } + + private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_FULL)) { + mStorageAvailable = false; + mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); + } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)) { + mStorageAvailable = true; + mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); + } + } + }; +} diff --git a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java new file mode 100644 index 0000000..bd2ae8b --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.content.ContentResolver; +import android.provider.Settings; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Implement the per-application based SMS control, which limits the number of + * SMS/MMS messages an app can send in the checking period. + * + * This code was formerly part of {@link SMSDispatcher}, and has been moved + * into a separate class to support instantiation of multiple SMSDispatchers on + * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. + */ +public class SmsUsageMonitor { + private static final String TAG = "SmsStorageMonitor"; + + /** Default checking period for SMS sent without user permission. */ + private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; + + /** Default number of SMS sent in checking period without user permission. */ + private static final int DEFAULT_SMS_MAX_COUNT = 100; + + private final int mCheckPeriod; + private final int mMaxAllowed; + private final HashMap<String, ArrayList<Long>> mSmsStamp = + new HashMap<String, ArrayList<Long>>(); + + /** + * Create SMS usage monitor. + * @param resolver the ContentResolver to use to load from secure settings + */ + public SmsUsageMonitor(ContentResolver resolver) { + mMaxAllowed = Settings.Secure.getInt(resolver, + Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT, + DEFAULT_SMS_MAX_COUNT); + + mCheckPeriod = Settings.Secure.getInt(resolver, + Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, + DEFAULT_SMS_CHECK_PERIOD); + } + + /** Clear the SMS application list for disposal. */ + void dispose() { + mSmsStamp.clear(); + } + + /** + * Check to see if an application is allowed to send new SMS messages. + * + * @param appName the application sending sms + * @param smsWaiting the number of new messages desired to send + * @return true if application is allowed to send the requested number + * of new sms messages + */ + public boolean check(String appName, int smsWaiting) { + synchronized (mSmsStamp) { + removeExpiredTimestamps(); + + ArrayList<Long> sentList = mSmsStamp.get(appName); + if (sentList == null) { + sentList = new ArrayList<Long>(); + mSmsStamp.put(appName, sentList); + } + + return isUnderLimit(sentList, smsWaiting); + } + } + + /** + * Remove keys containing only old timestamps. This can happen if an SMS app is used + * to send messages and then uninstalled. + */ + private void removeExpiredTimestamps() { + long beginCheckPeriod = System.currentTimeMillis() - mCheckPeriod; + + synchronized (mSmsStamp) { + Iterator<Map.Entry<String, ArrayList<Long>>> iter = mSmsStamp.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry<String, ArrayList<Long>> entry = iter.next(); + ArrayList<Long> oldList = entry.getValue(); + if (oldList.isEmpty() || oldList.get(oldList.size() - 1) < beginCheckPeriod) { + iter.remove(); + } + } + } + } + + private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) { + Long ct = System.currentTimeMillis(); + long beginCheckPeriod = ct - mCheckPeriod; + + Log.d(TAG, "SMS send size=" + sent.size() + " time=" + ct); + + while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) { + sent.remove(0); + } + + if ((sent.size() + smsWaiting) <= mMaxAllowed) { + for (int i = 0; i < smsWaiting; i++ ) { + sent.add(ct); + } + return true; + } + return false; + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java index 6903025..c2b9e4f 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java @@ -27,6 +27,9 @@ import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SMSDispatcher; +import com.android.internal.telephony.gsm.GsmSMSDispatcher; import com.android.internal.telephony.gsm.SimCard; import com.android.internal.telephony.ims.IsimRecords; @@ -35,14 +38,13 @@ public class CDMALTEPhone extends CDMAPhone { private static final boolean DBG = true; + /** Secondary SMSDispatcher for 3GPP format messages. */ + SMSDispatcher m3gppSMS; + // Constructors public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { - this(context, ci, notifier, false); - } - - public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, - boolean unitTestMode) { super(context, ci, notifier, false); + m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); } @Override @@ -54,6 +56,20 @@ public class CDMALTEPhone extends CDMAPhone { } @Override + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + super.dispose(); + m3gppSMS.dispose(); + } + } + + @Override + public void removeReferences() { + super.removeReferences(); + m3gppSMS = null; + } + + @Override public DataState getDataConnectionState(String apnType) { DataState ret = DataState.DISCONNECTED; @@ -92,13 +108,15 @@ public class CDMALTEPhone extends CDMAPhone { return ret; } + @Override public boolean updateCurrentCarrierInProvider() { if (mIccRecords != null) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); - map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric()); - log("updateCurrentCarrierInProvider insert uri=" + uri); + String operatorNumeric = mIccRecords.getOperatorNumeric(); + map.put(Telephony.Carriers.NUMERIC, operatorNumeric); + log("updateCurrentCarrierInProvider from UICC: numeric=" + operatorNumeric); mContext.getContentResolver().insert(uri, map); return true; } catch (SQLException e) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 286515e..09ee28c 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -17,10 +17,9 @@ package com.android.internal.telephony.cdma; import android.app.ActivityManagerNative; -import android.content.Context; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.content.SharedPreferences; import android.database.SQLException; import android.net.Uri; @@ -31,7 +30,6 @@ import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.Registrant; import android.os.RegistrantList; -import android.os.RemoteException; import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Telephony; @@ -42,20 +40,17 @@ import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.cat.CatService; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.CallTracker; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; -import com.android.internal.telephony.DataConnection; -import com.android.internal.telephony.IccRecords; -import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccException; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.MccTable; import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.OperatorInfo; import com.android.internal.telephony.Phone; @@ -67,19 +62,17 @@ import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.UUSInfo; -import com.android.internal.telephony.CallTracker; - -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import com.android.internal.telephony.cat.CatService; import java.util.ArrayList; import java.util.List; - - import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; + /** * {@hide} */ @@ -109,13 +102,13 @@ public class CDMAPhone extends PhoneBase { CatService mCcatService; // mNvLoadedRegistrants are informed after the EVENT_NV_READY - private RegistrantList mNvLoadedRegistrants = new RegistrantList(); + private final RegistrantList mNvLoadedRegistrants = new RegistrantList(); // mEriFileLoadedRegistrants are informed after the ERI text has been loaded - private RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); + private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started - private RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); + private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); // mEcmExitRespRegistrant is informed after the phone has been exited //the emergency callback mode @@ -131,6 +124,7 @@ public class CDMAPhone extends PhoneBase { // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { + @Override public void run() { exitEmergencyCallbackMode(); } @@ -164,7 +158,7 @@ public class CDMAPhone extends PhoneBase { protected void init(Context context, PhoneNotifier notifier) { mCM.setPhoneType(Phone.PHONE_TYPE_CDMA); mCT = new CdmaCallTracker(this); - mSMS = new CdmaSMSDispatcher(this); + mSMS = new CdmaSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); mDataConnectionTracker = new CdmaDataConnectionTracker (this); mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS); @@ -188,7 +182,7 @@ public class CDMAPhone extends PhoneBase { //Change the system setting SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, - new Integer(Phone.PHONE_TYPE_CDMA).toString()); + Integer.toString(Phone.PHONE_TYPE_CDMA)); // This is needed to handle phone process crashes String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); @@ -220,6 +214,7 @@ public class CDMAPhone extends PhoneBase { notifier.notifyMessageWaitingChanged(this); } + @Override public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { super.dispose(); @@ -253,23 +248,26 @@ public class CDMAPhone extends PhoneBase { } } + @Override public void removeReferences() { - log("removeReferences"); - this.mRuimPhoneBookInterfaceManager = null; - this.mRuimSmsInterfaceManager = null; - this.mSMS = null; - this.mSubInfo = null; - this.mIccRecords = null; - this.mIccFileHandler = null; - this.mIccCard = null; - this.mDataConnectionTracker = null; - this.mCT = null; - this.mSST = null; - this.mEriManager = null; - this.mCcatService = null; - this.mExitEcmRunnable = null; + log("removeReferences"); + super.removeReferences(); + mRuimPhoneBookInterfaceManager = null; + mRuimSmsInterfaceManager = null; + mSMS = null; + mSubInfo = null; + mIccRecords = null; + mIccFileHandler = null; + mIccCard = null; + mDataConnectionTracker = null; + mCT = null; + mSST = null; + mEriManager = null; + mCcatService = null; + mExitEcmRunnable = null; } + @Override protected void finalize() { if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized"); if (mWakeLock.isHeld()) { @@ -813,7 +811,7 @@ public class CDMAPhone extends PhoneBase { return null; } - /** + /** * Notify any interested party of a Phone state change {@link Phone.State} */ /*package*/ void notifyPhoneStateChanged() { @@ -858,18 +856,6 @@ public class CDMAPhone extends PhoneBase { if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange"); } - /*package*/ void - updateMessageWaitingIndicator(boolean mwi) { - // this also calls notifyMessageWaitingIndicator() - mIccRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); - } - - /* This function is overloaded to send number of voicemails instead of sending true/false */ - /*package*/ void - updateMessageWaitingIndicator(int mwi) { - mIccRecords.setVoiceMessageWaiting(1, mwi); - } - @Override public void exitEmergencyCallbackMode() { if (mWakeLock.isHeld()) { @@ -1013,6 +999,7 @@ public class CDMAPhone extends PhoneBase { case EVENT_RUIM_RECORDS_LOADED:{ Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); + updateCurrentCarrierInProvider(); } break; @@ -1172,7 +1159,7 @@ public class CDMAPhone extends PhoneBase { private static final int IS683_CONST_1900MHZ_F_BLOCK = 7; private static final int INVALID_SYSTEM_SELECTION_CODE = -1; - private boolean isIs683OtaSpDialStr(String dialStr) { + private static boolean isIs683OtaSpDialStr(String dialStr) { int sysSelCodeInt; boolean isOtaspDialString = false; int dialStrLen = dialStr.length(); @@ -1203,7 +1190,7 @@ public class CDMAPhone extends PhoneBase { /** * This function extracts the system selection code from the dial string. */ - private int extractSelCodeFromOtaSpNum(String dialStr) { + private static int extractSelCodeFromOtaSpNum(String dialStr) { int dialStrLen = dialStr.length(); int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE; @@ -1226,7 +1213,7 @@ public class CDMAPhone extends PhoneBase { * the dial string "sysSelCodeInt' is the system selection code specified * in the carrier ota sp number schema "sch". */ - private boolean + private static boolean checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) { boolean isOtaSpNum = false; try { @@ -1414,7 +1401,7 @@ public class CDMAPhone extends PhoneBase { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); map.put(Telephony.Carriers.NUMERIC, operatorNumeric); - log("updateCurrentCarrierInProvider insert uri=" + uri); + log("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric); getContext().getContentResolver().insert(uri, map); // Updates MCC MNC device configuration information @@ -1428,6 +1415,16 @@ public class CDMAPhone extends PhoneBase { return false; } + /** + * Sets the "current" field in the telephony provider according to the SIM's operator. + * Implemented in {@link CDMALTEPhone} for CDMA/LTE devices. + * + * @return true for success; false otherwise. + */ + boolean updateCurrentCarrierInProvider() { + return true; + } + public void prepareEri() { mEriManager.loadEriFile(); if(mEriManager.isEriFileLoaded()) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java index e92a276..57aae56 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java @@ -390,6 +390,7 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker { if (operatorNumeric == null) { phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); + mGotCountryCode = false; } else { String isoCountryCode = ""; try { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java index 0617fee..47c638f 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java @@ -26,6 +26,7 @@ import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.gsm.SIMRecords; import com.android.internal.telephony.ims.IsimRecords; @@ -438,4 +439,13 @@ public final class CdmaLteUiccRecords extends SIMRecords { } return true; } + + /** + * Dispatch 3GPP format message. For CDMA/LTE phones, + * send the message to the secondary 3GPP format SMS dispatcher. + */ + @Override + protected int dispatchGsmMessage(SmsMessageBase message) { + return ((CDMALTEPhone) phone).m3gppSMS.dispatchMessage(message); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index 07b0f4f..dded39e 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -25,7 +25,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.database.SQLException; -import android.os.AsyncResult; import android.os.Message; import android.os.SystemProperties; import android.preference.PreferenceManager; @@ -40,6 +39,8 @@ import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; +import com.android.internal.telephony.SmsStorageMonitor; +import com.android.internal.telephony.SmsUsageMonitor; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.WspTypeDecoder; import com.android.internal.telephony.cdma.sms.SmsEnvelope; @@ -47,7 +48,6 @@ import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -60,24 +60,23 @@ final class CdmaSMSDispatcher extends SMSDispatcher { private byte[] mLastDispatchedSmsFingerprint; private byte[] mLastAcknowledgedSmsFingerprint; - private boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean( + private final boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean( com.android.internal.R.bool.config_duplicate_port_omadm_wappush); - CdmaSMSDispatcher(CDMAPhone phone) { - super(phone); + CdmaSMSDispatcher(CDMAPhone phone, SmsStorageMonitor storageMonitor, + SmsUsageMonitor usageMonitor) { + super(phone, storageMonitor, usageMonitor); + mCm.setOnNewCdmaSms(this, EVENT_NEW_SMS, null); + } + + @Override + public void dispose() { + mCm.unSetOnNewCdmaSms(this); } - /** - * Called when a status report is received. This should correspond to - * a previously successful SEND. - * Is a special GSM function, should never be called in CDMA!! - * - * @param ar AsyncResult passed into the message handler. ar.result should - * be a String representing the status report PDU, as ASCII hex. - */ @Override - protected void handleStatusReport(AsyncResult ar) { - Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!"); + protected String getFormat() { + return android.telephony.SmsMessage.FORMAT_3GPP2; } private void handleCdmaStatusReport(SmsMessage sms) { @@ -138,11 +137,11 @@ final class CdmaSMSDispatcher extends SMSDispatcher { Log.d(TAG, "Voicemail count=" + voicemailCount); // Store the voicemail count in preferences. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( - mPhone.getContext()); + mContext); SharedPreferences.Editor editor = sp.edit(); editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount); editor.apply(); - ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount); + mPhone.setVoiceMessageWaiting(1, voicemailCount); handled = true; } else if (((SmsEnvelope.TELESERVICE_WMT == teleService) || (SmsEnvelope.TELESERVICE_WEMT == teleService)) && @@ -160,7 +159,8 @@ final class CdmaSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_HANDLED; } - if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) { + if (!mStorageMonitor.isStorageAvailable() && + sms.getMessageClass() != MessageClass.CLASS_0) { // It's a storable message and there's no storage available. Bail. // (See C.S0015-B v2.0 for a description of "Immediate Display" // messages, which we represent as CLASS_0.) @@ -181,48 +181,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_UNSUPPORTED; } - /* - * TODO(cleanup): Why are we using a getter method for this - * (and for so many other sms fields)? Trivial getters and - * setters like this are direct violations of the style guide. - * If the purpose is to protect against writes (by not - * providing a setter) then any protection is illusory (and - * hence bad) for cases where the values are not primitives, - * such as this call for the header. Since this is an issue - * with the public API it cannot be changed easily, but maybe - * something can be done eventually. - */ - SmsHeader smsHeader = sms.getUserDataHeader(); - - /* - * TODO(cleanup): Since both CDMA and GSM use the same header - * format, this dispatch processing is naturally identical, - * and code should probably not be replicated explicitly. - */ - - // See if message is partial or port addressed. - if ((smsHeader == null) || (smsHeader.concatRef == null)) { - // Message is not partial (not part of concatenated sequence). - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (smsHeader != null && smsHeader.portAddrs != null) { - if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { - // GSM-style WAP indication - return mWapPush.dispatchWapPdu(sms.getUserData()); - } else { - // The message was sent to a port, so concoct a URI for it. - dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort); - } - } else { - // Normal short and non-port-addressed message, dispatch it. - dispatchPdus(pdus); - } - return Activity.RESULT_OK; - } else { - // Process the message part. - return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs); - } + return dispatchNormalMessage(smsb); } /** @@ -236,23 +195,19 @@ final class CdmaSMSDispatcher extends SMSDispatcher { * to applications */ protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) { - int segment; - int totalSegments; int index = 0; - int msgType; - - int sourcePort = 0; - int destinationPort = 0; - msgType = pdu[index++]; - if (msgType != 0){ + int msgType = pdu[index++]; + if (msgType != 0) { Log.w(TAG, "Received a WAP SMS which is not WDP. Discard."); return Intents.RESULT_SMS_HANDLED; } - totalSegments = pdu[index++]; // >=1 - segment = pdu[index++]; // >=0 + int totalSegments = pdu[index++]; // >= 1 + int segment = pdu[index++]; // >= 0 // Only the first segment contains sourcePort and destination Port + int sourcePort = 0; + int destinationPort = 0; if (segment == 0) { //process WDP segment sourcePort = (0xFF & pdu[index++]) << 8; @@ -269,90 +224,16 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } // Lookup all other related parts - StringBuilder where = new StringBuilder("reference_number ="); - where.append(referenceNumber); - where.append(" AND address = ?"); - String[] whereArgs = new String[] {address}; - Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address + ", src-port = " + sourcePort + ", dst-port = " + destinationPort - + ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments); - - byte[][] pdus = null; - Cursor cursor = null; - try { - cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); - int cursorCount = cursor.getCount(); - if (cursorCount != totalSegments - 1) { - // We don't have all the parts yet, store this one away - ContentValues values = new ContentValues(); - values.put("date", (long) 0); - values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index)); - values.put("address", address); - values.put("reference_number", referenceNumber); - values.put("count", totalSegments); - values.put("sequence", segment); - values.put("destination_port", destinationPort); - - mResolver.insert(mRawUri, values); - - return Intents.RESULT_SMS_HANDLED; - } - - // All the parts are in place, deal with them - int pduColumn = cursor.getColumnIndex("pdu"); - int sequenceColumn = cursor.getColumnIndex("sequence"); - - pdus = new byte[totalSegments][]; - for (int i = 0; i < cursorCount; i++) { - cursor.moveToNext(); - int cursorSequence = (int)cursor.getLong(sequenceColumn); - // Read the destination port from the first segment - if (cursorSequence == 0) { - int destinationPortColumn = cursor.getColumnIndex("destination_port"); - destinationPort = (int)cursor.getLong(destinationPortColumn); - } - pdus[cursorSequence] = HexDump.hexStringToByteArray( - cursor.getString(pduColumn)); - } - // The last part will be added later - - // Remove the parts from the database - mResolver.delete(mRawUri, where.toString(), whereArgs); - } catch (SQLException e) { - Log.e(TAG, "Can't access multipart SMS database", e); - return Intents.RESULT_SMS_GENERIC_ERROR; - } finally { - if (cursor != null) cursor.close(); - } + + ", ID = " + referenceNumber + ", segment# = " + segment + '/' + totalSegments); - // Build up the data stream - ByteArrayOutputStream output = new ByteArrayOutputStream(); - for (int i = 0; i < totalSegments; i++) { - // reassemble the (WSP-)pdu - if (i == segment) { - // This one isn't in the DB, so add it - output.write(pdu, index, pdu.length - index); - } else { - output.write(pdus[i], 0, pdus[i].length); - } - } + // pass the user data portion of the PDU to the shared handler in SMSDispatcher + byte[] userData = new byte[pdu.length - index]; + System.arraycopy(pdu, index, userData, 0, pdu.length - index); - byte[] datagram = output.toByteArray(); - // Dispatch the PDU to applications - switch (destinationPort) { - case SmsHeader.PORT_WAP_PUSH: - // Handle the PUSH - return mWapPush.dispatchWapPdu(datagram); - - default:{ - pdus = new byte[1][]; - pdus[0] = datagram; - // The messages were sent to any other WAP port - dispatchPortAddressedPdus(pdus, destinationPort); - return Activity.RESULT_OK; - } - } + return processMessagePart(userData, address, referenceNumber, segment, totalSegments, + 0L, destinationPort, true); } /** {@inheritDoc} */ @@ -375,68 +256,34 @@ final class CdmaSMSDispatcher extends SMSDispatcher { /** {@inheritDoc} */ @Override - protected void sendMultipartText(String destAddr, String scAddr, - ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, - ArrayList<PendingIntent> deliveryIntents) { - - /** - * TODO(cleanup): There is no real code difference between - * this and the GSM version, and hence it should be moved to - * the base class or consolidated somehow, provided calling - * the proper submit pdu stuff can be arranged. - */ - - int refNumber = getNextConcatenatedRef() & 0x00FF; - int msgCount = parts.size(); - int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN; - - for (int i = 0; i < msgCount; i++) { - TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false); - if (encoding != details.codeUnitSize - && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN - || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) { - encoding = details.codeUnitSize; - } - } - - for (int i = 0; i < msgCount; i++) { - SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); - concatRef.refNumber = refNumber; - concatRef.seqNumber = i + 1; // 1-based sequence - concatRef.msgCount = msgCount; - concatRef.isEightBits = true; - SmsHeader smsHeader = new SmsHeader(); - smsHeader.concatRef = concatRef; - - 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); - } + protected TextEncodingDetails calculateLength(CharSequence messageBody, + boolean use7bitOnly) { + return SmsMessage.calculateLength(messageBody, use7bitOnly); + } - UserData uData = new UserData(); - uData.payloadStr = parts.get(i); - uData.userDataHeader = smsHeader; - if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) { - uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; - } else { // assume UTF-16 - uData.msgEncoding = UserData.ENCODING_UNICODE_16; - } - uData.msgEncodingSet = true; + /** {@inheritDoc} */ + @Override + protected void sendNewSubmitPdu(String destinationAddress, String scAddress, + String message, SmsHeader smsHeader, int encoding, + PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { + UserData uData = new UserData(); + uData.payloadStr = message; + uData.userDataHeader = smsHeader; + if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) { + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + } else { // assume UTF-16 + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + } + uData.msgEncodingSet = true; - /* By setting the statusReportRequested bit only for the - * last message fragment, this will result in only one - * callback to the sender when that last fragment delivery - * has been acknowledged. */ - SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr, - uData, (deliveryIntent != null) && (i == (msgCount - 1))); + /* By setting the statusReportRequested bit only for the + * last message fragment, this will result in only one + * callback to the sender when that last fragment delivery + * has been acknowledged. */ + SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destinationAddress, + uData, (deliveryIntent != null) && lastPart); - sendSubmitPdu(submitPdu, sentIntent, deliveryIntent); - } + sendSubmitPdu(submitPdu, sentIntent, deliveryIntent); } protected void sendSubmitPdu(SmsMessage.SubmitPdu pdu, @@ -464,43 +311,27 @@ final class CdmaSMSDispatcher extends SMSDispatcher { byte pdu[] = (byte[]) map.get("pdu"); Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendCdmaSms(pdu, reply); } - /** {@inheritDoc} */ - @Override - protected void sendMultipartSms (SmsTracker tracker) { - Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented"); - } - /** {@inheritDoc} */ @Override - protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ - // FIXME unit test leaves cm == null. this should change - + protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) { String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); if (inEcm.equals("true")) { return; } - if (mCm != null) { - int causeCode = resultToCause(result); - mCm.acknowledgeLastIncomingCdmaSms(success, causeCode, response); + int causeCode = resultToCause(result); + mCm.acknowledgeLastIncomingCdmaSms(success, causeCode, response); - if (causeCode == 0) { - mLastAcknowledgedSmsFingerprint = mLastDispatchedSmsFingerprint; - } - mLastDispatchedSmsFingerprint = null; + if (causeCode == 0) { + mLastAcknowledgedSmsFingerprint = mLastDispatchedSmsFingerprint; } + mLastDispatchedSmsFingerprint = null; } - protected void handleBroadcastSms(AsyncResult ar) { - // Not supported - Log.e(TAG, "Error! Not implemented for CDMA."); - } - - private int resultToCause(int rc) { + private static int resultToCause(int rc) { switch (rc) { case Activity.RESULT_OK: case Intents.RESULT_SMS_HANDLED: @@ -527,7 +358,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { * @return True if OrigPdu is OmaDM Push Message which has duplicate ports. * False if OrigPdu is NOT OmaDM Push Message which has duplicate ports. */ - private boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) { + private static boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) { index += 4; byte[] omaPdu = new byte[origPdu.length - index]; System.arraycopy(origPdu, index, omaPdu, 0, omaPdu.length); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 0aed77e..8f5a2eb 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -964,6 +964,7 @@ public class CdmaServiceStateTracker extends ServiceStateTracker { if (operatorNumeric == null) { phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); + mGotCountryCode = false; } else { String isoCountryCode = ""; try{ diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index be5c616..1409cab 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -114,30 +114,6 @@ public class SmsMessage extends SmsMessageBase { } /** - * Note: This function is a GSM specific functionality which is not supported in CDMA mode. - */ - public static SmsMessage newFromCMT(String[] lines) { - Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode."); - return null; - } - - /** - * Note: This function is a GSM specific functionality which is not supported in CDMA mode. - */ - public static SmsMessage newFromCMTI(String line) { - Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode."); - return null; - } - - /** - * Note: This function is a GSM specific functionality which is not supported in CDMA mode. - */ - public static SmsMessage newFromCDS(String line) { - Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode."); - return null; - } - - /** * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp. * Note: Only primitive fields are set. */ diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index d325aaa..e1f4c4b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -56,9 +56,6 @@ import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; -import com.android.internal.telephony.DataConnection; -import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; import com.android.internal.telephony.IccSmsInterfaceManager; @@ -140,7 +137,7 @@ public class GSMPhone extends PhoneBase { mCM.setPhoneType(Phone.PHONE_TYPE_GSM); mCT = new GsmCallTracker(this); mSST = new GsmServiceStateTracker (this); - mSMS = new GsmSMSDispatcher(this); + mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor); mIccFileHandler = new SIMFileHandler(this); mIccRecords = new SIMRecords(this); mDataConnectionTracker = new GsmDataConnectionTracker (this); @@ -199,6 +196,7 @@ public class GSMPhone extends PhoneBase { new Integer(Phone.PHONE_TYPE_GSM).toString()); } + @Override public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { super.dispose(); @@ -228,19 +226,22 @@ public class GSMPhone extends PhoneBase { } } + @Override public void removeReferences() { - this.mSimulatedRadioControl = null; - this.mStkService = null; - this.mSimPhoneBookIntManager = null; - this.mSimSmsIntManager = null; - this.mSMS = null; - this.mSubInfo = null; - this.mIccRecords = null; - this.mIccFileHandler = null; - this.mIccCard = null; - this.mDataConnectionTracker = null; - this.mCT = null; - this.mSST = null; + Log.d(LOG_TAG, "removeReferences"); + super.removeReferences(); + mSimulatedRadioControl = null; + mStkService = null; + mSimPhoneBookIntManager = null; + mSimSmsIntManager = null; + mSMS = null; + mSubInfo = null; + mIccRecords = null; + mIccFileHandler = null; + mIccCard = null; + mDataConnectionTracker = null; + mCT = null; + mSST = null; } protected void finalize() { @@ -406,17 +407,6 @@ public class GSMPhone extends PhoneBase { } public void - notifyDataConnectionFailed(String reason, String apnType) { - mNotifier.notifyDataConnectionFailed(this, reason, apnType); - } - - /*package*/ void - updateMessageWaitingIndicator(boolean mwi) { - // this also calls notifyMessageWaitingIndicator() - mIccRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); - } - - public void notifyCallForwardingIndicator() { mNotifier.notifyCallForwardingChanged(this); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 52ca453..4e1cc9a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -30,13 +30,15 @@ import android.telephony.SmsCbMessage; import android.telephony.gsm.GsmCellLocation; import android.util.Log; -import com.android.internal.telephony.BaseCommands; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.SMSDispatcher; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; +import com.android.internal.telephony.SmsStorageMonitor; +import com.android.internal.telephony.SmsUsageMonitor; import com.android.internal.telephony.TelephonyProperties; import java.util.ArrayList; @@ -45,16 +47,55 @@ import java.util.Iterator; import static android.telephony.SmsMessage.MessageClass; -final class GsmSMSDispatcher extends SMSDispatcher { +public final class GsmSMSDispatcher extends SMSDispatcher { private static final String TAG = "GSM"; - private GSMPhone mGsmPhone; + /** Status report received */ + private static final int EVENT_NEW_SMS_STATUS_REPORT = 100; - GsmSMSDispatcher(GSMPhone phone) { - super(phone); - mGsmPhone = phone; + /** New broadcast SMS */ + private static final int EVENT_NEW_BROADCAST_SMS = 101; - ((BaseCommands)mCm).setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null); + public GsmSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor, + SmsUsageMonitor usageMonitor) { + super(phone, storageMonitor, usageMonitor); + mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null); + mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); + mCm.setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null); + } + + @Override + public void dispose() { + mCm.unSetOnNewGsmSms(this); + mCm.unSetOnSmsStatus(this); + mCm.unSetOnNewGsmBroadcastSms(this); + } + + @Override + protected String getFormat() { + return android.telephony.SmsMessage.FORMAT_3GPP; + } + + /** + * Handles 3GPP format-specific events coming from the phone stack. + * Other events are handled by {@link SMSDispatcher#handleMessage}. + * + * @param msg the message to handle + */ + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_NEW_SMS_STATUS_REPORT: + handleStatusReport((AsyncResult) msg.obj); + break; + + case EVENT_NEW_BROADCAST_SMS: + handleBroadcastSms((AsyncResult)msg.obj); + break; + + default: + super.handleMessage(msg); + } } /** @@ -64,8 +105,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ - @Override - protected void handleStatusReport(AsyncResult ar) { + private void handleStatusReport(AsyncResult ar) { String pduString = (String) ar.result; SmsMessage sms = SmsMessage.newFromCDS(pduString); @@ -94,17 +134,17 @@ final class GsmSMSDispatcher extends SMSDispatcher { acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null); } - /** {@inheritDoc} */ @Override public int dispatchMessage(SmsMessageBase smsb) { // If sms is null, means there was a parsing error. if (smsb == null) { + Log.e(TAG, "dispatchMessage: message is null"); return Intents.RESULT_SMS_GENERIC_ERROR; } + SmsMessage sms = (SmsMessage) smsb; - boolean handled = false; if (sms.isTypeZero()) { // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be @@ -121,14 +161,15 @@ final class GsmSMSDispatcher extends SMSDispatcher { } // Special case the message waiting indicator messages + boolean handled = false; if (sms.isMWISetMessage()) { - mGsmPhone.updateMessageWaitingIndicator(true); + mPhone.setVoiceMessageWaiting(1, -1); // line 1: unknown number of msgs waiting handled = sms.isMwiDontStore(); if (false) { Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled); } } else if (sms.isMWIClearMessage()) { - mGsmPhone.updateMessageWaitingIndicator(false); + mPhone.setVoiceMessageWaiting(1, 0); // line 1: no msgs waiting handled = sms.isMwiDontStore(); if (false) { Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled); @@ -139,35 +180,14 @@ final class GsmSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_HANDLED; } - if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) { + if (!mStorageMonitor.isStorageAvailable() && + sms.getMessageClass() != MessageClass.CLASS_0) { // It's a storable message and there's no storage available. Bail. // (See TS 23.038 for a description of class 0 messages.) return Intents.RESULT_SMS_OUT_OF_MEMORY; } - SmsHeader smsHeader = sms.getUserDataHeader(); - // See if message is partial or port addressed. - if ((smsHeader == null) || (smsHeader.concatRef == null)) { - // Message is not partial (not part of concatenated sequence). - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (smsHeader != null && smsHeader.portAddrs != null) { - if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) { - return mWapPush.dispatchWapPdu(sms.getUserData()); - } else { - // The message was sent to a port, so concoct a URI for it. - dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort); - } - } else { - // Normal short and non-port-addressed message, dispatch it. - dispatchPdus(pdus); - } - return Activity.RESULT_OK; - } else { - // Process the message part. - return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs); - } + return dispatchNormalMessage(smsb); } /** {@inheritDoc} */ @@ -190,158 +210,20 @@ final class GsmSMSDispatcher extends SMSDispatcher { /** {@inheritDoc} */ @Override - protected void sendMultipartText(String destinationAddress, String scAddress, - ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, - ArrayList<PendingIntent> deliveryIntents) { - - int refNumber = getNextConcatenatedRef() & 0x00FF; - int msgCount = parts.size(); - int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN; - - mRemainingMessages = msgCount; - - TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; - for (int i = 0; i < msgCount; i++) { - TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false); - if (encoding != details.codeUnitSize - && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN - || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) { - encoding = details.codeUnitSize; - } - encodingForParts[i] = details; - } - - for (int i = 0; i < msgCount; i++) { - SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); - concatRef.refNumber = refNumber; - concatRef.seqNumber = i + 1; // 1-based sequence - 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; - if (encoding == android.telephony.SmsMessage.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); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader), - encoding, smsHeader.languageTable, smsHeader.languageShiftTable); - - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); - } + protected TextEncodingDetails calculateLength(CharSequence messageBody, + boolean use7bitOnly) { + return SmsMessage.calculateLength(messageBody, use7bitOnly); } - /** - * Send a multi-part text based SMS which already passed SMS control check. - * - * It is the working function for sendMultipartText(). - * - * @param destinationAddress the address to send the message to - * @param scAddress 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>. - * @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 - * extended data ("pdu"). - */ - private void sendMultipartTextWithPermit(String destinationAddress, - String scAddress, ArrayList<String> parts, - ArrayList<PendingIntent> sentIntents, - ArrayList<PendingIntent> deliveryIntents) { - - // check if in service - int ss = mPhone.getServiceState().getState(); - if (ss != ServiceState.STATE_IN_SERVICE) { - for (int i = 0, count = parts.size(); i < count; i++) { - PendingIntent sentIntent = null; - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - SmsTracker tracker = SmsTrackerFactory(null, sentIntent, null); - handleNotInService(ss, tracker); - } - return; - } - - int refNumber = getNextConcatenatedRef() & 0x00FF; - int msgCount = parts.size(); - int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN; - - mRemainingMessages = msgCount; - - TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount]; - for (int i = 0; i < msgCount; i++) { - TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false); - if (encoding != details.codeUnitSize - && (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN - || encoding == android.telephony.SmsMessage.ENCODING_7BIT)) { - encoding = details.codeUnitSize; - } - encodingForParts[i] = details; - } - - for (int i = 0; i < msgCount; i++) { - SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); - concatRef.refNumber = refNumber; - concatRef.seqNumber = i + 1; // 1-based sequence - concatRef.msgCount = msgCount; - concatRef.isEightBits = false; - SmsHeader smsHeader = new SmsHeader(); - smsHeader.concatRef = concatRef; - if (encoding == android.telephony.SmsMessage.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); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader), - encoding, smsHeader.languageTable, smsHeader.languageShiftTable); - - HashMap<String, Object> map = new HashMap<String, Object>(); - map.put("smsc", pdus.encodedScAddress); - map.put("pdu", pdus.encodedMessage); - - SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent); - sendSms(tracker); - } + /** {@inheritDoc} */ + @Override + protected void sendNewSubmitPdu(String destinationAddress, String scAddress, + String message, SmsHeader smsHeader, int encoding, + PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) { + SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader), + encoding, smsHeader.languageTable, smsHeader.languageShiftTable); + sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent); } /** {@inheritDoc} */ @@ -353,45 +235,16 @@ final class GsmSMSDispatcher extends SMSDispatcher { byte pdu[] = (byte[]) map.get("pdu"); Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendSMS(IccUtils.bytesToHexString(smsc), - IccUtils.bytesToHexString(pdu), reply); - } - - /** - * Send the multi-part SMS based on multipart Sms tracker - * - * @param tracker holds the multipart Sms tracker ready to be sent - */ - @Override - protected void sendMultipartSms (SmsTracker tracker) { - ArrayList<String> parts; - ArrayList<PendingIntent> sentIntents; - ArrayList<PendingIntent> deliveryIntents; - - HashMap<String, Object> map = tracker.mData; - - String destinationAddress = (String) map.get("destination"); - String scAddress = (String) map.get("scaddress"); - - parts = (ArrayList<String>) map.get("parts"); - sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents"); - deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents"); - - sendMultipartTextWithPermit(destinationAddress, - scAddress, parts, sentIntents, deliveryIntents); - + mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply); } /** {@inheritDoc} */ @Override - protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ - // FIXME unit test leaves cm == null. this should change - if (mCm != null) { - mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); - } + protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) { + mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response); } - private int resultToCause(int rc) { + private static int resultToCause(int rc) { switch (rc) { case Activity.RESULT_OK: case Intents.RESULT_SMS_HANDLED: @@ -485,10 +338,12 @@ final class GsmSMSDispatcher extends SMSDispatcher { private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap = new HashMap<SmsCbConcatInfo, byte[][]>(); - @Override - protected void handleBroadcastSms(AsyncResult ar) { + /** + * Handle 3GPP format SMS-CB message. + * @param ar the AsyncResult containing the received PDUs + */ + private void handleBroadcastSms(AsyncResult ar) { try { - byte[][] pdus = null; byte[] receivedPdu = (byte[])ar.result; if (false) { @@ -507,10 +362,11 @@ final class GsmSMSDispatcher extends SMSDispatcher { SmsCbHeader header = new SmsCbHeader(receivedPdu); String plmn = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); - GsmCellLocation cellLocation = (GsmCellLocation)mGsmPhone.getCellLocation(); + GsmCellLocation cellLocation = (GsmCellLocation) mPhone.getCellLocation(); int lac = cellLocation.getLac(); int cid = cellLocation.getCid(); + byte[][] pdus; if (header.nrOfPages > 1) { // Multi-page message SmsCbConcatInfo concatInfo = new SmsCbConcatInfo(header, plmn, lac, cid); @@ -563,5 +419,4 @@ final class GsmSMSDispatcher extends SMSDispatcher { Log.e(TAG, "Error in decoding SMS CB pdu", e); } } - } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index d3645fa..eea2780 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -846,6 +846,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (operatorNumeric == null) { phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); + mGotCountryCode = false; } else { String iso = ""; try{ diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 73c319c..5d6f181 100755 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -38,6 +38,7 @@ import com.android.internal.telephony.IccVmNotSupportedException; import com.android.internal.telephony.MccTable; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.SmsMessageBase; import java.util.ArrayList; @@ -1160,6 +1161,15 @@ public class SIMRecords extends IccRecords { } } + /** + * Dispatch 3GPP format message. Overridden for CDMA/LTE phones by + * {@link com.android.internal.telephony.cdma.CdmaLteUiccRecords} + * to send messages to the secondary 3GPP format SMS dispatcher. + */ + protected int dispatchGsmMessage(SmsMessageBase message) { + return phone.mSMS.dispatchMessage(message); + } + private void handleSms(byte[] ba) { if (ba[0] != 0) Log.d("ENF", "status : " + ba[0]); @@ -1175,7 +1185,7 @@ public class SIMRecords extends IccRecords { System.arraycopy(ba, 1, pdu, 0, n - 1); SmsMessage message = SmsMessage.createFromPdu(pdu); - phone.mSMS.dispatchMessage(message); + dispatchGsmMessage(message); } } @@ -1201,7 +1211,7 @@ public class SIMRecords extends IccRecords { System.arraycopy(ba, 1, pdu, 0, n - 1); SmsMessage message = SmsMessage.createFromPdu(pdu); - phone.mSMS.dispatchMessage(message); + dispatchGsmMessage(message); // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 // 1 == "received by MS from network; message read" diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 3784e7c..ea030e6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -137,14 +137,6 @@ public class SmsMessage extends SmsMessageBase { } /** @hide */ - public static SmsMessage newFromCMTI(String line) { - // the thinking here is not to read the message immediately - // FTA test case - Log.e(LOG_TAG, "newFromCMTI: not yet supported"); - return null; - } - - /** @hide */ public static SmsMessage newFromCDS(String line) { try { SmsMessage msg = new SmsMessage(); @@ -157,15 +149,6 @@ public class SmsMessage extends SmsMessageBase { } /** - * Note: This functionality is currently not supported in GSM mode. - * @hide - */ - public static SmsMessageBase newFromParcel(Parcel p){ - Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode."); - return null; - } - - /** * Create an SmsMessage from an SMS EF record. * * @param index Index of SMS record. This should be index in ArrayList |