Merge "Enable support for multiple SMSDispatchers in CDMALTEPhone."
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 237a892..79995d0 100755
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -666,6 +666,7 @@
public static SmsMessage[] getMessagesFromIntent(
Intent intent) {
Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
+ String format = intent.getStringExtra("format");
byte[][] pduObjs = new byte[messages.length][];
for (int i = 0; i < messages.length; i++) {
@@ -676,7 +677,7 @@
SmsMessage[] msgs = new SmsMessage[pduCount];
for (int i = 0; i < pduCount; i++) {
pdus[i] = pduObjs[i];
- msgs[i] = SmsMessage.createFromPdu(pdus[i]);
+ msgs[i] = SmsMessage.createFromPdu(pdus[i], format);
}
return msgs;
}
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 @@
*
* {@hide}
*/
- public ArrayList<SmsMessage> getAllMessagesFromIcc() {
+ public static ArrayList<SmsMessage> getAllMessagesFromIcc() {
List<SmsRawData> records = null;
try {
@@ -470,7 +470,7 @@
* <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 @@
* 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 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 @@
}
- /**
- * 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 @@
*
* {@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 @@
/**
* 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 @@
* @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 @@
}
/**
- * 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 @@
* SmsManager.STATUS_ON_ICC_UNSENT
*/
public int getStatusOnIcc() {
-
return mWrappedSmsMessage.getStatusOnIcc();
}
@@ -666,7 +621,6 @@
* SmsMessage was not created from a ICC SMS EF record.
*/
public int getIndexOnIcc() {
-
return mWrappedSmsMessage.getIndexOnIcc();
}
@@ -704,19 +658,4 @@
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 @@
}
/**
- * 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 @@
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 @@
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 android.os.Message;
import android.os.Handler;
-import android.os.SystemProperties;
-
/**
* {@hide}
@@ -267,14 +265,32 @@
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 setOnNewSMS(Handler h, int what, Object obj);
- void unSetOnNewSMS(Handler h);
+ 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 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 @@
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 @@
* @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 @@
/* 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 @@
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 @@
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 @@
// 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 @@
}
/**
- * 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 @@
/**
* 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 @@
/**
* 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 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 @@
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 @@
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 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 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 @@
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 @@
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.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_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;
+
+ /** New SMS received. */
+ protected static final int EVENT_NEW_SMS = 1;
+
+ /** SMS send complete. */
+ protected static final int EVENT_SEND_SMS_COMPLETE = 2;
/** Retry sending a previously failed SMS message */
- static final protected int EVENT_SEND_RETRY = 3;
-
- /** Status report received */
- static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5;
-
- /** SIM/RUIM storage is full */
- static final protected int EVENT_ICC_FULL = 6;
+ 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;
+ static final int EVENT_STOP_SENDING = 7; // accessed from inner class
- /** 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;
-
- /** 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 @@
* 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 @@
* 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 @@
}
/**
- * 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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
* 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 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}.
*
- * NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null.
+ * @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
+ *
* @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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
*
* @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 @@
}
/**
- * 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;
}
+
+ /**
+ * 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");
+ }
}
- 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.");
- }
-
- private DialogInterface.OnClickListener mListener =
+ private final DialogInterface.OnClickListener mListener =
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
@@ -1007,42 +1053,32 @@
}
};
- 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);
+ // 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);
- }
+ // 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 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 @@
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 @@
}
@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 @@
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.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.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.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 @@
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 @@
// 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 @@
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 @@
//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 @@
notifier.notifyMessageWaitingChanged(this);
}
+ @Override
public void dispose() {
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
super.dispose();
@@ -253,23 +248,26 @@
}
}
+ @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 @@
return null;
}
- /**
+ /**
* Notify any interested party of a Phone state change {@link Phone.State}
*/
/*package*/ void notifyPhoneStateChanged() {
@@ -858,18 +856,6 @@
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 @@
case EVENT_RUIM_RECORDS_LOADED:{
Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
+ updateCurrentCarrierInProvider();
}
break;
@@ -1172,7 +1159,7 @@
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 @@
/**
* 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 @@
* 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 @@
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 @@
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/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.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 @@
}
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.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.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.util.HexDump;
import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -60,24 +60,23 @@
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);
}
- /**
- * 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!");
+ public void dispose() {
+ mCm.unSetOnNewCdmaSms(this);
+ }
+
+ @Override
+ protected String getFormat() {
+ return android.telephony.SmsMessage.FORMAT_3GPP2;
}
private void handleCdmaStatusReport(SmsMessage sms) {
@@ -138,11 +137,11 @@
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 @@
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 @@
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 @@
* 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 @@
}
// 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);
+ + ", 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);
+ // 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);
- 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();
- }
-
- // 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);
- }
- }
-
- 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 @@
/** {@inheritDoc} */
@Override
- protected void sendMultipartText(String destAddr, String scAddr,
- ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
- ArrayList<PendingIntent> deliveryIntents) {
+ protected TextEncodingDetails calculateLength(CharSequence messageBody,
+ boolean use7bitOnly) {
+ return SmsMessage.calculateLength(messageBody, use7bitOnly);
+ }
- /**
- * 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;
- }
+ /** {@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;
- 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;
+ /* 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);
- 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);
- }
-
- 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;
-
- /* 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)));
-
- sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
- }
+ sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
}
protected void sendSubmitPdu(SmsMessage.SubmitPdu pdu,
@@ -464,43 +311,27 @@
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 @@
* @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/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 @@
}
/**
- * 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.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 @@
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 @@
new Integer(Phone.PHONE_TYPE_GSM).toString());
}
+ @Override
public void dispose() {
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
super.dispose();
@@ -228,19 +226,22 @@
}
}
+ @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 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.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 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 @@
* @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 @@
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 @@
}
// 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 @@
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 @@
/** {@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 @@
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 @@
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 @@
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 @@
Log.e(TAG, "Error in decoding SMS CB pdu", e);
}
}
-
}
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.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 @@
}
}
+ /**
+ * 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 @@
System.arraycopy(ba, 1, pdu, 0, n - 1);
SmsMessage message = SmsMessage.createFromPdu(pdu);
- phone.mSMS.dispatchMessage(message);
+ dispatchGsmMessage(message);
}
}
@@ -1201,7 +1211,7 @@
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 @@
}
/** @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 @@
}
/**
- * 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