am bece9cb7: Merge "Enable support for multiple SMSDispatchers in CDMALTEPhone."
* commit 'bece9cb7944daa012ca95fc7f6c73f6fad035892': Enable support for multiple SMSDispatchers in CDMALTEPhone.
This commit is contained in:
@@ -666,6 +666,7 @@ public final class Telephony {
|
||||
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 @@ public final class Telephony {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ public final class SmsManager {
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public ArrayList<SmsMessage> getAllMessagesFromIcc() {
|
||||
public static ArrayList<SmsMessage> getAllMessagesFromIcc() {
|
||||
List<SmsRawData> records = null;
|
||||
|
||||
try {
|
||||
@@ -470,7 +470,7 @@ public final class SmsManager {
|
||||
* <code>getAllMessagesFromIcc</code>
|
||||
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
|
||||
*/
|
||||
private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
|
||||
private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
|
||||
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
|
||||
if (records != null) {
|
||||
int count = records.size();
|
||||
|
||||
@@ -36,7 +36,6 @@ import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
|
||||
* A Short Message Service message.
|
||||
*/
|
||||
public class SmsMessage {
|
||||
private static final boolean LOCAL_DEBUG = true;
|
||||
private static final String LOG_TAG = "SMS";
|
||||
|
||||
/**
|
||||
@@ -78,6 +77,18 @@ public class SmsMessage {
|
||||
*/
|
||||
public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
|
||||
|
||||
/**
|
||||
* Indicates a 3GPP format SMS message.
|
||||
* @hide pending API council approval
|
||||
*/
|
||||
public static final String FORMAT_3GPP = "3gpp";
|
||||
|
||||
/**
|
||||
* Indicates a 3GPP2 format SMS message.
|
||||
* @hide pending API council approval
|
||||
*/
|
||||
public static final String FORMAT_3GPP2 = "3gpp2";
|
||||
|
||||
/** Contains actual SmsMessage. Only public for debugging and for framework layer.
|
||||
*
|
||||
* @hide
|
||||
@@ -106,30 +117,47 @@ public class SmsMessage {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public SmsMessage() {
|
||||
this(getSmsFacility());
|
||||
}
|
||||
|
||||
private SmsMessage(SmsMessageBase smb) {
|
||||
mWrappedSmsMessage = smb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from a raw PDU.
|
||||
*
|
||||
* <p><b>This method will soon be deprecated</b> and all applications which handle
|
||||
* incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast
|
||||
* intent <b>must</b> now pass the new {@code format} String extra from the intent
|
||||
* into the new method {@code createFromPdu(byte[], String)} which takes an
|
||||
* extra format parameter. This is required in order to correctly decode the PDU on
|
||||
* devices that require support for both 3GPP and 3GPP2 formats at the same time,
|
||||
* such as dual-mode GSM/CDMA and CDMA/LTE phones.
|
||||
*/
|
||||
public static SmsMessage createFromPdu(byte[] pdu) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
String format = (PHONE_TYPE_CDMA == activePhone) ? FORMAT_3GPP2 : FORMAT_3GPP;
|
||||
return createFromPdu(pdu, format);
|
||||
}
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
/**
|
||||
* Create an SmsMessage from a raw PDU with the specified message format. The
|
||||
* message format is passed in the {@code SMS_RECEIVED_ACTION} as the {@code format}
|
||||
* String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
|
||||
* or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
|
||||
*
|
||||
* @param pdu the message PDU from the SMS_RECEIVED_ACTION intent
|
||||
* @param format the format extra from the SMS_RECEIVED_ACTION intent
|
||||
* @hide pending API council approval
|
||||
*/
|
||||
public static SmsMessage createFromPdu(byte[] pdu, String format) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
|
||||
if (FORMAT_3GPP2.equals(format)) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
|
||||
} else {
|
||||
} else if (FORMAT_3GPP.equals(format)) {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
@@ -144,57 +172,19 @@ public class SmsMessage {
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static SmsMessage newFromCMT(String[] lines){
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected static SmsMessage newFromCMTI(String line) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromCDS(String line) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line);
|
||||
}
|
||||
public static SmsMessage newFromCMT(String[] lines) {
|
||||
// received SMS in 3GPP format
|
||||
SmsMessageBase wrappedMessage =
|
||||
com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromParcel(Parcel p) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p);
|
||||
}
|
||||
// received SMS in 3GPP2 format
|
||||
SmsMessageBase wrappedMessage =
|
||||
com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
@@ -227,6 +217,9 @@ public class SmsMessage {
|
||||
/**
|
||||
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
|
||||
* length in bytes (not hex chars) less the SMSC header
|
||||
*
|
||||
* FIXME: This method is only used by a CTS test case that isn't run on CDMA devices.
|
||||
* We should probably deprecate it and remove the obsolete test case.
|
||||
*/
|
||||
public static int getTPLayerLengthForPDU(String pdu) {
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
@@ -373,34 +366,6 @@ public class SmsMessage {
|
||||
* otherwise useful apps.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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.
|
||||
@@ -602,15 +567,6 @@ public class SmsMessage {
|
||||
return mWrappedSmsMessage.getUserData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user data header (UDH).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public SmsHeader getUserDataHeader() {
|
||||
return mWrappedSmsMessage.getUserDataHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw PDU for the message.
|
||||
*
|
||||
@@ -646,7 +602,6 @@ public class SmsMessage {
|
||||
* SmsManager.STATUS_ON_ICC_UNSENT
|
||||
*/
|
||||
public int getStatusOnIcc() {
|
||||
|
||||
return mWrappedSmsMessage.getStatusOnIcc();
|
||||
}
|
||||
|
||||
@@ -666,7 +621,6 @@ public class SmsMessage {
|
||||
* SmsMessage was not created from a ICC SMS EF record.
|
||||
*/
|
||||
public int getIndexOnIcc() {
|
||||
|
||||
return mWrappedSmsMessage.getIndexOnIcc();
|
||||
}
|
||||
|
||||
@@ -704,19 +658,4 @@ public class SmsMessage {
|
||||
public boolean isReplyPathPresent() {
|
||||
return mWrappedSmsMessage.isReplyPathPresent();
|
||||
}
|
||||
|
||||
/** This method returns the reference to a specific
|
||||
* SmsMessage object, which is used for accessing its static methods.
|
||||
* @return Specific SmsMessage.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private static final SmsMessageBase getSmsFacility(){
|
||||
int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
return new com.android.internal.telephony.cdma.SmsMessage();
|
||||
} else {
|
||||
return new com.android.internal.telephony.gsm.SmsMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,104 +165,6 @@ public class SmsMessage {
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -79,7 +79,8 @@ public abstract class BaseCommands implements CommandsInterface {
|
||||
protected RegistrantList mRilConnectedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mIccRefreshRegistrants = new RegistrantList();
|
||||
|
||||
protected Registrant mSMSRegistrant;
|
||||
protected Registrant mGsmSmsRegistrant;
|
||||
protected Registrant mCdmaSmsRegistrant;
|
||||
protected Registrant mNITZTimeRegistrant;
|
||||
protected Registrant mSignalStrengthRegistrant;
|
||||
protected Registrant mUSSDRegistrant;
|
||||
@@ -358,12 +359,20 @@ public abstract class BaseCommands implements CommandsInterface {
|
||||
mIccStatusChangedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void setOnNewSMS(Handler h, int what, Object obj) {
|
||||
mSMSRegistrant = new Registrant (h, what, obj);
|
||||
public void setOnNewGsmSms(Handler h, int what, Object obj) {
|
||||
mGsmSmsRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnNewSMS(Handler h) {
|
||||
mSMSRegistrant.clear();
|
||||
public void unSetOnNewGsmSms(Handler h) {
|
||||
mGsmSmsRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnNewCdmaSms(Handler h, int what, Object obj) {
|
||||
mCdmaSmsRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnNewCdmaSms(Handler h) {
|
||||
mCdmaSmsRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnNewGsmBroadcastSms(Handler h, int what, Object obj) {
|
||||
|
||||
@@ -20,8 +20,6 @@ import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
|
||||
|
||||
import android.os.Message;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemProperties;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@@ -267,14 +265,32 @@ public interface CommandsInterface {
|
||||
void unregisterForRUIMReady(Handler h);
|
||||
|
||||
/**
|
||||
* unlike the register* methods, there's only one new SMS handler
|
||||
* unlike the register* methods, there's only one new 3GPP format SMS handler.
|
||||
* if you need to unregister, you should also tell the radio to stop
|
||||
* sending SMS's to you (via AT+CNMI)
|
||||
*
|
||||
* AsyncResult.result is a String containing the SMS PDU
|
||||
*/
|
||||
void 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
|
||||
|
||||
@@ -1394,7 +1394,7 @@ public interface Phone {
|
||||
String getDeviceSvn();
|
||||
|
||||
/**
|
||||
* Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.
|
||||
* Retrieves the unique subscriber ID, e.g., IMSI for GSM phones.
|
||||
*/
|
||||
String getSubscriberId();
|
||||
|
||||
@@ -1756,4 +1756,13 @@ public interface Phone {
|
||||
* @param response a callback message with the String response in the obj field
|
||||
*/
|
||||
void requestIsimAuthentication(String nonce, Message response);
|
||||
|
||||
/**
|
||||
* Sets the SIM voice message waiting indicator records.
|
||||
* @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
|
||||
* @param countWaiting The number of messages waiting, if known. Use
|
||||
* -1 to indicate that an unknown number of
|
||||
* messages are waiting
|
||||
*/
|
||||
void setVoiceMessageWaiting(int line, int countWaiting);
|
||||
}
|
||||
|
||||
@@ -112,15 +112,17 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
/* Instance Variables */
|
||||
public CommandsInterface mCM;
|
||||
protected IccFileHandler mIccFileHandler;
|
||||
boolean mDnsCheckDisabled = false;
|
||||
boolean mDnsCheckDisabled;
|
||||
public DataConnectionTracker mDataConnectionTracker;
|
||||
boolean mDoesRilSendMultipleCallRing;
|
||||
int mCallRingContinueToken = 0;
|
||||
int mCallRingContinueToken;
|
||||
int mCallRingDelay;
|
||||
public boolean mIsTheCurrentActivePhone = true;
|
||||
boolean mIsVoiceCapable = true;
|
||||
public IccRecords mIccRecords;
|
||||
public IccCard mIccCard;
|
||||
public SmsStorageMonitor mSmsStorageMonitor;
|
||||
public SmsUsageMonitor mSmsUsageMonitor;
|
||||
public SMSDispatcher mSMS;
|
||||
|
||||
/**
|
||||
@@ -164,7 +166,7 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
|
||||
protected Looper mLooper; /* to insure registrants are in correct thread*/
|
||||
|
||||
protected Context mContext;
|
||||
protected final Context mContext;
|
||||
|
||||
/**
|
||||
* PhoneNotifier is an abstraction for all system-wide
|
||||
@@ -238,6 +240,10 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
mCallRingDelay = SystemProperties.getInt(
|
||||
TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000);
|
||||
Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay);
|
||||
|
||||
// Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
|
||||
mSmsStorageMonitor = new SmsStorageMonitor(this);
|
||||
mSmsUsageMonitor = new SmsUsageMonitor(context.getContentResolver());
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
@@ -246,9 +252,17 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
// Must cleanup all connectionS and needs to use sendMessage!
|
||||
mDataConnectionTracker.cleanUpAllConnections(null);
|
||||
mIsTheCurrentActivePhone = false;
|
||||
// Dispose the SMS usage and storage monitors
|
||||
mSmsStorageMonitor.dispose();
|
||||
mSmsUsageMonitor.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeReferences() {
|
||||
mSmsStorageMonitor = null;
|
||||
mSmsUsageMonitor = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* When overridden the derived class needs to call
|
||||
* super.handleMessage(msg) so this method has a
|
||||
@@ -1036,37 +1050,6 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
(mDataConnectionTracker.isDataPossible(apnType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -1132,7 +1115,7 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
/**
|
||||
* Common error logger method for unexpected calls to CDMA-only methods.
|
||||
*/
|
||||
private void logUnexpectedCdmaMethodCall(String name)
|
||||
private static void logUnexpectedCdmaMethodCall(String name)
|
||||
{
|
||||
Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
|
||||
"called, CDMAPhone inactive.");
|
||||
@@ -1145,7 +1128,7 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
/**
|
||||
* Common error logger method for unexpected calls to GSM/WCDMA-only methods.
|
||||
*/
|
||||
private void logUnexpectedGsmMethodCall(String name) {
|
||||
private static void logUnexpectedGsmMethodCall(String name) {
|
||||
Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " +
|
||||
"called, GSMPhone inactive.");
|
||||
}
|
||||
@@ -1167,4 +1150,16 @@ public abstract class PhoneBase extends Handler implements Phone {
|
||||
public int getLteOnCdmaMode() {
|
||||
return mCM.getLteOnCdmaMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SIM voice message waiting indicator records.
|
||||
* @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
|
||||
* @param countWaiting The number of messages waiting, if known. Use
|
||||
* -1 to indicate that an unknown number of
|
||||
* messages are waiting
|
||||
*/
|
||||
@Override
|
||||
public void setVoiceMessageWaiting(int line, int countWaiting) {
|
||||
mIccRecords.setVoiceMessageWaiting(line, countWaiting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class PhoneProxy extends Handler implements Phone {
|
||||
switch(msg.what) {
|
||||
case EVENT_RADIO_TECHNOLOGY_CHANGED:
|
||||
//switch Phone from CDMA to GSM or vice versa
|
||||
mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName();
|
||||
mOutgoingPhone = mActivePhone.getPhoneName();
|
||||
logd("Switching phone from " + mOutgoingPhone + "Phone to " +
|
||||
(mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") );
|
||||
boolean oldPowerState = false; // old power state to off
|
||||
@@ -144,23 +144,10 @@ public class PhoneProxy extends Handler implements Phone {
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
|
||||
private void logv(String msg) {
|
||||
Log.v(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void logd(String msg) {
|
||||
private static void logd(String msg) {
|
||||
Log.d(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void logw(String msg) {
|
||||
Log.w(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void loge(String msg) {
|
||||
Log.e(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
|
||||
public ServiceState getServiceState() {
|
||||
return mActivePhone.getServiceState();
|
||||
}
|
||||
@@ -739,19 +726,19 @@ public class PhoneProxy extends Handler implements Phone {
|
||||
}
|
||||
|
||||
public int getCdmaEriIconIndex() {
|
||||
return mActivePhone.getCdmaEriIconIndex();
|
||||
return mActivePhone.getCdmaEriIconIndex();
|
||||
}
|
||||
|
||||
public String getCdmaEriText() {
|
||||
return mActivePhone.getCdmaEriText();
|
||||
}
|
||||
public String getCdmaEriText() {
|
||||
return mActivePhone.getCdmaEriText();
|
||||
}
|
||||
|
||||
public int getCdmaEriIconMode() {
|
||||
return mActivePhone.getCdmaEriIconMode();
|
||||
return mActivePhone.getCdmaEriIconMode();
|
||||
}
|
||||
|
||||
public Phone getActivePhone() {
|
||||
return mActivePhone;
|
||||
return mActivePhone;
|
||||
}
|
||||
|
||||
public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete){
|
||||
@@ -861,4 +848,9 @@ public class PhoneProxy extends Handler implements Phone {
|
||||
public int getLteOnCdmaMode() {
|
||||
return mActivePhone.getLteOnCdmaMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVoiceMessageWaiting(int line, int countWaiting) {
|
||||
mActivePhone.setVoiceMessageWaiting(line, countWaiting);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2434,8 +2434,8 @@ public final class RIL extends BaseCommands implements CommandsInterface {
|
||||
SmsMessage sms;
|
||||
|
||||
sms = SmsMessage.newFromCMT(a);
|
||||
if (mSMSRegistrant != null) {
|
||||
mSMSRegistrant
|
||||
if (mGsmSmsRegistrant != null) {
|
||||
mGsmSmsRegistrant
|
||||
.notifyRegistrant(new AsyncResult(null, sms, null));
|
||||
}
|
||||
break;
|
||||
@@ -2607,8 +2607,8 @@ public final class RIL extends BaseCommands implements CommandsInterface {
|
||||
|
||||
SmsMessage sms = (SmsMessage) ret;
|
||||
|
||||
if (mSMSRegistrant != null) {
|
||||
mSMSRegistrant
|
||||
if (mCdmaSmsRegistrant != null) {
|
||||
mCdmaSmsRegistrant
|
||||
.notifyRegistrant(new AsyncResult(null, sms, null));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -44,10 +44,12 @@ import android.telephony.ServiceState;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -60,68 +62,66 @@ import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
|
||||
|
||||
|
||||
public abstract class SMSDispatcher extends Handler {
|
||||
private static final String TAG = "SMS";
|
||||
static final String TAG = "SMS"; // accessed from inner class
|
||||
private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
|
||||
|
||||
/** Default checking period for SMS sent without user permit */
|
||||
private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
|
||||
|
||||
/** Default number of SMS sent in checking period without user permit */
|
||||
private static final int DEFAULT_SMS_MAX_COUNT = 100;
|
||||
|
||||
/** Default timeout for SMS sent query */
|
||||
private static final int DEFAULT_SMS_TIMEOUT = 6000;
|
||||
|
||||
protected static final String[] RAW_PROJECTION = new String[] {
|
||||
"pdu",
|
||||
"sequence",
|
||||
"destination_port",
|
||||
/** Permission required to receive SMS and SMS-CB messages. */
|
||||
public static final String RECEIVE_SMS_PERMISSION = "android.permission.RECEIVE_SMS";
|
||||
|
||||
/** Permission required to receive ETWS and CMAS emergency broadcasts. */
|
||||
public static final String RECEIVE_EMERGENCY_BROADCAST_PERMISSION =
|
||||
"android.permission.RECEIVE_EMERGENCY_BROADCAST";
|
||||
|
||||
/** Query projection for checking for duplicate message segments. */
|
||||
private static final String[] PDU_PROJECTION = new String[] {
|
||||
"pdu"
|
||||
};
|
||||
|
||||
static final protected int EVENT_NEW_SMS = 1;
|
||||
/** Query projection for combining concatenated message segments. */
|
||||
private static final String[] PDU_SEQUENCE_PORT_PROJECTION = new String[] {
|
||||
"pdu",
|
||||
"sequence",
|
||||
"destination_port"
|
||||
};
|
||||
|
||||
static final protected int EVENT_SEND_SMS_COMPLETE = 2;
|
||||
private static final int PDU_COLUMN = 0;
|
||||
private static final int SEQUENCE_COLUMN = 1;
|
||||
private static final int DESTINATION_PORT_COLUMN = 2;
|
||||
|
||||
/** 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 @@ public abstract class SMSDispatcher extends Handler {
|
||||
* Message reference for a CONCATENATED_8_BIT_REFERENCE or
|
||||
* CONCATENATED_16_BIT_REFERENCE message set. Should be
|
||||
* incremented for each set of concatenated messages.
|
||||
* Static field shared by all dispatcher objects.
|
||||
*/
|
||||
private static int sConcatenatedRef;
|
||||
private static int sConcatenatedRef = new Random().nextInt(256);
|
||||
|
||||
private SmsCounter mCounter;
|
||||
/** Outgoing message counter. Shared by all dispatchers. */
|
||||
private final SmsUsageMonitor mUsageMonitor;
|
||||
|
||||
private ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT);
|
||||
private final ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT);
|
||||
|
||||
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
@@ -150,17 +152,14 @@ public abstract class SMSDispatcher extends Handler {
|
||||
* Hold the wake lock for 5 seconds, which should be enough time for
|
||||
* any receiver(s) to grab its own wake lock.
|
||||
*/
|
||||
private final int WAKE_LOCK_TIMEOUT = 5000;
|
||||
|
||||
protected boolean mStorageAvailable = true;
|
||||
protected boolean mReportMemoryStatusPending = false;
|
||||
private static final int WAKE_LOCK_TIMEOUT = 5000;
|
||||
|
||||
/* Flags indicating whether the current device allows sms service */
|
||||
protected boolean mSmsCapable = true;
|
||||
protected boolean mSmsReceiveDisabled;
|
||||
protected boolean mSmsSendDisabled;
|
||||
|
||||
protected static int mRemainingMessages = -1;
|
||||
protected int mRemainingMessages = -1;
|
||||
|
||||
protected static int getNextConcatenatedRef() {
|
||||
sConcatenatedRef += 1;
|
||||
@@ -168,111 +167,52 @@ public abstract class SMSDispatcher extends Handler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the per-application based SMS control, which only allows
|
||||
* a limit on the number of SMS/MMS messages an app can send in checking
|
||||
* period.
|
||||
* Create a new SMS dispatcher.
|
||||
* @param phone the Phone to use
|
||||
* @param storageMonitor the SmsStorageMonitor to use
|
||||
* @param usageMonitor the SmsUsageMonitor to use
|
||||
*/
|
||||
private class SmsCounter {
|
||||
private int mCheckPeriod;
|
||||
private int mMaxAllowed;
|
||||
private HashMap<String, ArrayList<Long>> mSmsStamp;
|
||||
|
||||
/**
|
||||
* Create SmsCounter
|
||||
* @param mMax is the number of SMS allowed without user permit
|
||||
* @param mPeriod is the checking period
|
||||
*/
|
||||
SmsCounter(int mMax, int mPeriod) {
|
||||
mMaxAllowed = mMax;
|
||||
mCheckPeriod = mPeriod;
|
||||
mSmsStamp = new HashMap<String, ArrayList<Long>> ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if an application allow to send new SMS messages
|
||||
*
|
||||
* @param appName is the application sending sms
|
||||
* @param smsWaiting is the number of new sms wants to be sent
|
||||
* @return true if application is allowed to send the requested number
|
||||
* of new sms messages
|
||||
*/
|
||||
boolean check(String appName, int smsWaiting) {
|
||||
if (!mSmsStamp.containsKey(appName)) {
|
||||
mSmsStamp.put(appName, new ArrayList<Long>());
|
||||
}
|
||||
|
||||
return isUnderLimit(mSmsStamp.get(appName), smsWaiting);
|
||||
}
|
||||
|
||||
private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) {
|
||||
Long ct = System.currentTimeMillis();
|
||||
|
||||
Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct);
|
||||
|
||||
while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
|
||||
sent.remove(0);
|
||||
}
|
||||
|
||||
|
||||
if ( (sent.size() + smsWaiting) <= mMaxAllowed) {
|
||||
for (int i = 0; i < smsWaiting; i++ ) {
|
||||
sent.add(ct);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected SMSDispatcher(PhoneBase phone) {
|
||||
protected SMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
|
||||
SmsUsageMonitor usageMonitor) {
|
||||
mPhone = phone;
|
||||
mWapPush = new WapPushOverSms(phone, this);
|
||||
mContext = phone.getContext();
|
||||
mResolver = mContext.getContentResolver();
|
||||
mCm = phone.mCM;
|
||||
mStorageMonitor = storageMonitor;
|
||||
mUsageMonitor = usageMonitor;
|
||||
|
||||
createWakelock();
|
||||
|
||||
int check_period = Settings.Secure.getInt(mResolver,
|
||||
Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS,
|
||||
DEFAULT_SMS_CHECK_PERIOD);
|
||||
int max_count = Settings.Secure.getInt(mResolver,
|
||||
Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT,
|
||||
DEFAULT_SMS_MAX_COUNT);
|
||||
mCounter = new SmsCounter(max_count, check_period);
|
||||
|
||||
mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
|
||||
mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
|
||||
mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null);
|
||||
mCm.registerForOn(this, EVENT_RADIO_ON, null);
|
||||
|
||||
// Don't always start message ref at 0.
|
||||
sConcatenatedRef = new Random().nextInt(256);
|
||||
|
||||
// Register for device storage intents. Use these to notify the RIL
|
||||
// that storage for SMS is or is not available.
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL);
|
||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
|
||||
mContext.registerReceiver(mResultReceiver, filter);
|
||||
|
||||
mSmsCapable = mContext.getResources().getBoolean(
|
||||
com.android.internal.R.bool.config_sms_capable);
|
||||
mSmsReceiveDisabled = !SystemProperties.getBoolean(
|
||||
TelephonyProperties.PROPERTY_SMS_RECEIVE, mSmsCapable);
|
||||
mSmsSendDisabled = !SystemProperties.getBoolean(
|
||||
TelephonyProperties.PROPERTY_SMS_SEND, mSmsCapable);
|
||||
Log.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable
|
||||
Log.d(TAG, "SMSDispatcher: ctor mSmsCapable=" + mSmsCapable + " format=" + getFormat()
|
||||
+ " mSmsReceiveDisabled=" + mSmsReceiveDisabled
|
||||
+ " mSmsSendDisabled=" + mSmsSendDisabled);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
mCm.unSetOnNewSMS(this);
|
||||
mCm.unSetOnSmsStatus(this);
|
||||
mCm.unSetOnIccSmsFull(this);
|
||||
mCm.unregisterForOn(this);
|
||||
}
|
||||
/** Unregister for incoming SMS events. */
|
||||
public abstract void dispose();
|
||||
|
||||
/**
|
||||
* The format of the message PDU in the associated broadcast intent.
|
||||
* This will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
|
||||
* or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
|
||||
*
|
||||
* Note: All applications which handle incoming SMS messages by processing the
|
||||
* SMS_RECEIVED_ACTION broadcast intent MUST pass the "format" extra from the intent
|
||||
* into the new methods in {@link android.telephony.SmsMessage} which take an
|
||||
* extra format parameter. This is required in order to correctly decode the PDU on
|
||||
* devices which require support for both 3GPP and 3GPP2 formats at the same time,
|
||||
* such as CDMA/LTE devices and GSM/CDMA world phones.
|
||||
*
|
||||
* @return the format of the message PDU
|
||||
*/
|
||||
protected abstract String getFormat();
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
@@ -338,14 +278,6 @@ public abstract class SMSDispatcher extends Handler {
|
||||
sendSms((SmsTracker) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_NEW_SMS_STATUS_REPORT:
|
||||
handleStatusReport((AsyncResult)msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_ICC_FULL:
|
||||
handleIccFull();
|
||||
break;
|
||||
|
||||
case EVENT_POST_ALERT:
|
||||
handleReachSentLimit((SmsTracker)(msg.obj));
|
||||
break;
|
||||
@@ -369,7 +301,7 @@ public abstract class SMSDispatcher extends Handler {
|
||||
case EVENT_SEND_CONFIRMED_SMS:
|
||||
if (mSTrackers.isEmpty() == false) {
|
||||
SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1);
|
||||
if (isMultipartTracker(sTracker)) {
|
||||
if (sTracker.isMultipart()) {
|
||||
sendMultipartSms(sTracker);
|
||||
} else {
|
||||
sendSms(sTracker);
|
||||
@@ -390,30 +322,6 @@ public abstract class SMSDispatcher extends Handler {
|
||||
removeMessages(EVENT_ALERT_TIMEOUT, msg.obj);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_REPORT_MEMORY_STATUS_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
if (ar.exception != null) {
|
||||
mReportMemoryStatusPending = true;
|
||||
Log.v(TAG, "Memory status report to modem pending : mStorageAvailable = "
|
||||
+ mStorageAvailable);
|
||||
} else {
|
||||
mReportMemoryStatusPending = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_ON:
|
||||
if (mReportMemoryStatusPending) {
|
||||
Log.v(TAG, "Sending pending memory status report : mStorageAvailable = "
|
||||
+ mStorageAvailable);
|
||||
mCm.reportSmsMemoryStatus(mStorageAvailable,
|
||||
obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_NEW_BROADCAST_SMS:
|
||||
handleBroadcastSms((AsyncResult)msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,26 +347,6 @@ public abstract class SMSDispatcher extends Handler {
|
||||
this, Activity.RESULT_OK, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -559,7 +447,7 @@ public abstract class SMSDispatcher extends Handler {
|
||||
* POWER_OFF
|
||||
* @param tracker An SmsTracker for the current message.
|
||||
*/
|
||||
protected void handleNotInService(int ss, SmsTracker tracker) {
|
||||
protected static void handleNotInService(int ss, SmsTracker tracker) {
|
||||
if (tracker.mSentIntent != null) {
|
||||
try {
|
||||
if (ss == ServiceState.STATE_POWER_OFF) {
|
||||
@@ -581,86 +469,171 @@ public abstract class SMSDispatcher extends Handler {
|
||||
*/
|
||||
public abstract int dispatchMessage(SmsMessageBase sms);
|
||||
|
||||
/**
|
||||
* Dispatch a normal incoming SMS. This is called from the format-specific
|
||||
* {@link #dispatchMessage(SmsMessageBase)} if no format-specific handling is required.
|
||||
*
|
||||
* @param sms
|
||||
* @return
|
||||
*/
|
||||
protected int dispatchNormalMessage(SmsMessageBase sms) {
|
||||
SmsHeader smsHeader = sms.getUserDataHeader();
|
||||
|
||||
// See if message is partial or port addressed.
|
||||
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
|
||||
// Message is not partial (not part of concatenated sequence).
|
||||
byte[][] pdus = new byte[1][];
|
||||
pdus[0] = sms.getPdu();
|
||||
|
||||
if (smsHeader != null && smsHeader.portAddrs != null) {
|
||||
if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
// GSM-style WAP indication
|
||||
return mWapPush.dispatchWapPdu(sms.getUserData());
|
||||
} else {
|
||||
// The message was sent to a port, so concoct a URI for it.
|
||||
dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
|
||||
}
|
||||
} else {
|
||||
// Normal short and non-port-addressed message, dispatch it.
|
||||
dispatchPdus(pdus);
|
||||
}
|
||||
return Activity.RESULT_OK;
|
||||
} else {
|
||||
// Process the message part.
|
||||
SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
|
||||
SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
|
||||
return processMessagePart(sms.getPdu(), sms.getOriginatingAddress(),
|
||||
concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount,
|
||||
sms.getTimestampMillis(), (portAddrs != null ? portAddrs.destPort : -1), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is the last part send the parts out to the application, otherwise
|
||||
* the part is stored for later processing.
|
||||
* the part is stored for later processing. Handles both 3GPP concatenated messages
|
||||
* as well as 3GPP2 format WAP push messages processed by
|
||||
* {@link com.android.internal.telephony.cdma.CdmaSMSDispatcher#processCdmaWapPdu}.
|
||||
*
|
||||
* @param pdu the message PDU, or the datagram portion of a CDMA WDP datagram segment
|
||||
* @param address the originating address
|
||||
* @param referenceNumber distinguishes concatenated messages from the same sender
|
||||
* @param sequenceNumber the order of this segment in the message
|
||||
* @param messageCount the number of segments in the message
|
||||
* @param timestamp the service center timestamp in millis
|
||||
* @param destPort the destination port for the message, or -1 for no destination port
|
||||
* @param isCdmaWapPush true if pdu is a CDMA WDP datagram segment and not an SM PDU
|
||||
*
|
||||
* NOTE: concatRef (naturally) needs to be non-null, but portAddrs can be null.
|
||||
* @return a result code from {@link Telephony.Sms.Intents}, or
|
||||
* {@link Activity#RESULT_OK} if the message has been broadcast
|
||||
* to applications
|
||||
*/
|
||||
protected int processMessagePart(SmsMessageBase sms,
|
||||
SmsHeader.ConcatRef concatRef, SmsHeader.PortAddrs portAddrs) {
|
||||
|
||||
// Lookup all other related parts
|
||||
StringBuilder where = new StringBuilder("reference_number =");
|
||||
where.append(concatRef.refNumber);
|
||||
where.append(" AND address = ?");
|
||||
String[] whereArgs = new String[] {sms.getOriginatingAddress()};
|
||||
|
||||
protected int processMessagePart(byte[] pdu, String address, int referenceNumber,
|
||||
int sequenceNumber, int messageCount, long timestamp, int destPort,
|
||||
boolean isCdmaWapPush) {
|
||||
byte[][] pdus = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
|
||||
// used by several query selection arguments
|
||||
String refNumber = Integer.toString(referenceNumber);
|
||||
String seqNumber = Integer.toString(sequenceNumber);
|
||||
|
||||
// Check for duplicate message segment
|
||||
cursor = mResolver.query(mRawUri, PDU_PROJECTION,
|
||||
"address=? AND reference_number=? AND sequence=?",
|
||||
new String[] {address, refNumber, seqNumber}, null);
|
||||
|
||||
// moveToNext() returns false if no duplicates were found
|
||||
if (cursor.moveToNext()) {
|
||||
Log.w(TAG, "Discarding duplicate message segment from address=" + address
|
||||
+ " refNumber=" + refNumber + " seqNumber=" + seqNumber);
|
||||
String oldPduString = cursor.getString(PDU_COLUMN);
|
||||
byte[] oldPdu = HexDump.hexStringToByteArray(oldPduString);
|
||||
if (!Arrays.equals(oldPdu, pdu)) {
|
||||
Log.e(TAG, "Warning: dup message segment PDU of length " + pdu.length
|
||||
+ " is different from existing PDU of length " + oldPdu.length);
|
||||
}
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
// not a dup, query for all other segments of this concatenated message
|
||||
String where = "address=? AND reference_number=?";
|
||||
String[] whereArgs = new String[] {address, refNumber};
|
||||
cursor = mResolver.query(mRawUri, PDU_SEQUENCE_PORT_PROJECTION, where, whereArgs, null);
|
||||
|
||||
int cursorCount = cursor.getCount();
|
||||
if (cursorCount != concatRef.msgCount - 1) {
|
||||
if (cursorCount != messageCount - 1) {
|
||||
// We don't have all the parts yet, store this one away
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("date", new Long(sms.getTimestampMillis()));
|
||||
values.put("pdu", HexDump.toHexString(sms.getPdu()));
|
||||
values.put("address", sms.getOriginatingAddress());
|
||||
values.put("reference_number", concatRef.refNumber);
|
||||
values.put("count", concatRef.msgCount);
|
||||
values.put("sequence", concatRef.seqNumber);
|
||||
if (portAddrs != null) {
|
||||
values.put("destination_port", portAddrs.destPort);
|
||||
values.put("date", timestamp);
|
||||
values.put("pdu", HexDump.toHexString(pdu));
|
||||
values.put("address", address);
|
||||
values.put("reference_number", referenceNumber);
|
||||
values.put("count", messageCount);
|
||||
values.put("sequence", sequenceNumber);
|
||||
if (destPort != -1) {
|
||||
values.put("destination_port", destPort);
|
||||
}
|
||||
mResolver.insert(mRawUri, values);
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
|
||||
// All the parts are in place, deal with them
|
||||
int pduColumn = cursor.getColumnIndex("pdu");
|
||||
int sequenceColumn = cursor.getColumnIndex("sequence");
|
||||
|
||||
pdus = new byte[concatRef.msgCount][];
|
||||
pdus = new byte[messageCount][];
|
||||
for (int i = 0; i < cursorCount; i++) {
|
||||
cursor.moveToNext();
|
||||
int cursorSequence = (int)cursor.getLong(sequenceColumn);
|
||||
int cursorSequence = cursor.getInt(SEQUENCE_COLUMN);
|
||||
pdus[cursorSequence - 1] = HexDump.hexStringToByteArray(
|
||||
cursor.getString(pduColumn));
|
||||
cursor.getString(PDU_COLUMN));
|
||||
|
||||
// Read the destination port from the first segment (needed for CDMA WAP PDU).
|
||||
// It's not a bad idea to prefer the port from the first segment for 3GPP as well.
|
||||
if (cursorSequence == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) {
|
||||
destPort = cursor.getInt(DESTINATION_PORT_COLUMN);
|
||||
}
|
||||
}
|
||||
// This one isn't in the DB, so add it
|
||||
pdus[concatRef.seqNumber - 1] = sms.getPdu();
|
||||
pdus[sequenceNumber - 1] = pdu;
|
||||
|
||||
// Remove the parts from the database
|
||||
mResolver.delete(mRawUri, where.toString(), whereArgs);
|
||||
mResolver.delete(mRawUri, where, whereArgs);
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "Can't access multipart SMS database", e);
|
||||
// TODO: Would OUT_OF_MEMORY be more appropriate?
|
||||
return Intents.RESULT_SMS_GENERIC_ERROR;
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(cleanup): The following code has duplicated logic with
|
||||
* the radio-specific dispatchMessage code, which is fragile,
|
||||
* in addition to being redundant. Instead, if this method
|
||||
* maybe returned the reassembled message (or just contents),
|
||||
* the following code (which is not really related to
|
||||
* reconstruction) could be better consolidated.
|
||||
*/
|
||||
// Special handling for CDMA WDP datagrams
|
||||
if (isCdmaWapPush) {
|
||||
// Build up the data stream
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < messageCount; i++) {
|
||||
// reassemble the (WSP-)pdu
|
||||
output.write(pdus[i], 0, pdus[i].length);
|
||||
}
|
||||
byte[] datagram = output.toByteArray();
|
||||
|
||||
// Dispatch the PDU to applications
|
||||
if (destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
// Handle the PUSH
|
||||
return mWapPush.dispatchWapPdu(datagram);
|
||||
} else {
|
||||
pdus = new byte[1][];
|
||||
pdus[0] = datagram;
|
||||
// The messages were sent to any other WAP port
|
||||
dispatchPortAddressedPdus(pdus, destPort);
|
||||
return Activity.RESULT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch the PDUs to applications
|
||||
if (portAddrs != null) {
|
||||
if (portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
if (destPort != -1) {
|
||||
if (destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
// Build up the data stream
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < concatRef.msgCount; i++) {
|
||||
SmsMessage msg = SmsMessage.createFromPdu(pdus[i]);
|
||||
for (int i = 0; i < messageCount; i++) {
|
||||
SmsMessage msg = SmsMessage.createFromPdu(pdus[i], getFormat());
|
||||
byte[] data = msg.getUserData();
|
||||
output.write(data, 0, data.length);
|
||||
}
|
||||
@@ -668,7 +641,7 @@ public abstract class SMSDispatcher extends Handler {
|
||||
return mWapPush.dispatchWapPdu(output.toByteArray());
|
||||
} else {
|
||||
// The messages were sent to a port, so concoct a URI for it
|
||||
dispatchPortAddressedPdus(pdus, portAddrs.destPort);
|
||||
dispatchPortAddressedPdus(pdus, destPort);
|
||||
}
|
||||
} else {
|
||||
// The messages were not sent to a port
|
||||
@@ -685,7 +658,8 @@ public abstract class SMSDispatcher extends Handler {
|
||||
protected void dispatchPdus(byte[][] pdus) {
|
||||
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
|
||||
intent.putExtra("pdus", pdus);
|
||||
dispatch(intent, "android.permission.RECEIVE_SMS");
|
||||
intent.putExtra("format", getFormat());
|
||||
dispatch(intent, RECEIVE_SMS_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,7 +672,8 @@ public abstract class SMSDispatcher extends Handler {
|
||||
Uri uri = Uri.parse("sms://localhost:" + port);
|
||||
Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
|
||||
intent.putExtra("pdus", pdus);
|
||||
dispatch(intent, "android.permission.RECEIVE_SMS");
|
||||
intent.putExtra("format", getFormat());
|
||||
dispatch(intent, RECEIVE_SMS_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -758,6 +733,16 @@ public abstract class SMSDispatcher extends Handler {
|
||||
protected abstract void sendText(String destAddr, String scAddr,
|
||||
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.
|
||||
*
|
||||
@@ -784,9 +769,70 @@ public abstract class SMSDispatcher extends Handler {
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*/
|
||||
protected abstract void sendMultipartText(String destAddr, String scAddr,
|
||||
protected void sendMultipartText(String destAddr, String scAddr,
|
||||
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents);
|
||||
ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
int refNumber = getNextConcatenatedRef() & 0x00FF;
|
||||
int msgCount = parts.size();
|
||||
int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
|
||||
|
||||
mRemainingMessages = msgCount;
|
||||
|
||||
TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
TextEncodingDetails details = calculateLength(parts.get(i), false);
|
||||
if (encoding != details.codeUnitSize
|
||||
&& (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
|
||||
|| encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
|
||||
encoding = details.codeUnitSize;
|
||||
}
|
||||
encodingForParts[i] = details;
|
||||
}
|
||||
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
|
||||
concatRef.refNumber = refNumber;
|
||||
concatRef.seqNumber = i + 1; // 1-based sequence
|
||||
concatRef.msgCount = msgCount;
|
||||
// TODO: We currently set this to true since our messaging app will never
|
||||
// send more than 255 parts (it converts the message to MMS well before that).
|
||||
// However, we should support 3rd party messaging apps that might need 16-bit
|
||||
// references
|
||||
// Note: It's not sufficient to just flip this bit to true; it will have
|
||||
// ripple effects (several calculations assume 8-bit ref).
|
||||
concatRef.isEightBits = true;
|
||||
SmsHeader smsHeader = new SmsHeader();
|
||||
smsHeader.concatRef = concatRef;
|
||||
|
||||
// Set the national language tables for 3GPP 7-bit encoding, if enabled.
|
||||
if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
|
||||
smsHeader.languageTable = encodingForParts[i].languageTable;
|
||||
smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
|
||||
}
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
|
||||
PendingIntent deliveryIntent = null;
|
||||
if (deliveryIntents != null && deliveryIntents.size() > i) {
|
||||
deliveryIntent = deliveryIntents.get(i);
|
||||
}
|
||||
|
||||
sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
|
||||
sentIntent, deliveryIntent, (i == (msgCount - 1)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SubmitPdu and send it.
|
||||
*/
|
||||
protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
|
||||
String message, SmsHeader smsHeader, int encoding,
|
||||
PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart);
|
||||
|
||||
/**
|
||||
* Send a SMS
|
||||
@@ -842,7 +888,7 @@ public abstract class SMSDispatcher extends Handler {
|
||||
handleNotInService(ss, tracker);
|
||||
} else {
|
||||
String appName = getAppNameByIntent(sentIntent);
|
||||
if (mCounter.check(appName, SINGLE_PART_SMS)) {
|
||||
if (mUsageMonitor.check(appName, SINGLE_PART_SMS)) {
|
||||
sendSms(tracker);
|
||||
} else {
|
||||
sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
|
||||
@@ -885,7 +931,7 @@ public abstract class SMSDispatcher extends Handler {
|
||||
DEFAULT_SMS_TIMEOUT);
|
||||
}
|
||||
|
||||
protected String getAppNameByIntent(PendingIntent intent) {
|
||||
protected static String getAppNameByIntent(PendingIntent intent) {
|
||||
Resources r = Resources.getSystem();
|
||||
return (intent != null) ? intent.getTargetPackage()
|
||||
: r.getString(R.string.sms_control_default_app_name);
|
||||
@@ -903,7 +949,35 @@ public abstract class SMSDispatcher extends Handler {
|
||||
*
|
||||
* @param tracker holds the multipart Sms tracker ready to be sent
|
||||
*/
|
||||
protected abstract void sendMultipartSms (SmsTracker tracker);
|
||||
private void sendMultipartSms(SmsTracker tracker) {
|
||||
ArrayList<String> parts;
|
||||
ArrayList<PendingIntent> sentIntents;
|
||||
ArrayList<PendingIntent> deliveryIntents;
|
||||
|
||||
HashMap<String, Object> map = tracker.mData;
|
||||
|
||||
String destinationAddress = (String) map.get("destination");
|
||||
String scAddress = (String) map.get("scaddress");
|
||||
|
||||
parts = (ArrayList<String>) map.get("parts");
|
||||
sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
|
||||
deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
|
||||
|
||||
// check if in service
|
||||
int ss = mPhone.getServiceState().getState();
|
||||
if (ss != ServiceState.STATE_IN_SERVICE) {
|
||||
for (int i = 0, count = parts.size(); i < count; i++) {
|
||||
PendingIntent sentIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
handleNotInService(ss, new SmsTracker(null, sentIntent, null));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an acknowledge message.
|
||||
@@ -933,67 +1007,39 @@ public abstract class SMSDispatcher extends Handler {
|
||||
acknowledgeLastIncomingSms(success, result, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public abstract class SMSDispatcher extends Handler {
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
|
||||
private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_FULL)) {
|
||||
mStorageAvailable = false;
|
||||
mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
|
||||
} else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)) {
|
||||
mStorageAvailable = true;
|
||||
mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
|
||||
} else {
|
||||
// Assume the intent is one of the SMS receive intents that
|
||||
// was sent as an ordered broadcast. Check result and ACK.
|
||||
int rc = getResultCode();
|
||||
boolean success = (rc == Activity.RESULT_OK)
|
||||
|| (rc == Intents.RESULT_SMS_HANDLED);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,9 @@ import android.util.Log;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneNotifier;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
import com.android.internal.telephony.SMSDispatcher;
|
||||
import com.android.internal.telephony.gsm.GsmSMSDispatcher;
|
||||
import com.android.internal.telephony.gsm.SimCard;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
|
||||
@@ -35,14 +38,13 @@ public class CDMALTEPhone extends CDMAPhone {
|
||||
|
||||
private static final boolean DBG = true;
|
||||
|
||||
/** Secondary SMSDispatcher for 3GPP format messages. */
|
||||
SMSDispatcher m3gppSMS;
|
||||
|
||||
// Constructors
|
||||
public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
|
||||
this(context, ci, notifier, false);
|
||||
}
|
||||
|
||||
public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
|
||||
boolean unitTestMode) {
|
||||
super(context, ci, notifier, false);
|
||||
m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,6 +55,20 @@ public class CDMALTEPhone extends CDMAPhone {
|
||||
mIccFileHandler = new CdmaLteUiccFileHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
super.dispose();
|
||||
m3gppSMS.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReferences() {
|
||||
super.removeReferences();
|
||||
m3gppSMS = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataState getDataConnectionState(String apnType) {
|
||||
DataState ret = DataState.DISCONNECTED;
|
||||
@@ -92,13 +108,15 @@ public class CDMALTEPhone extends CDMAPhone {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCurrentCarrierInProvider() {
|
||||
if (mIccRecords != null) {
|
||||
try {
|
||||
Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
|
||||
ContentValues map = new ContentValues();
|
||||
map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric());
|
||||
log("updateCurrentCarrierInProvider insert uri=" + uri);
|
||||
String operatorNumeric = mIccRecords.getOperatorNumeric();
|
||||
map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
|
||||
log("updateCurrentCarrierInProvider from UICC: numeric=" + operatorNumeric);
|
||||
mContext.getContentResolver().insert(uri, map);
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.content.Context;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.SQLException;
|
||||
import android.net.Uri;
|
||||
@@ -31,7 +30,6 @@ import android.os.PowerManager;
|
||||
import android.os.PowerManager.WakeLock;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Telephony;
|
||||
@@ -42,20 +40,17 @@ import android.telephony.SignalStrength;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.cat.CatService;
|
||||
import com.android.internal.telephony.Call;
|
||||
import com.android.internal.telephony.CallStateException;
|
||||
import com.android.internal.telephony.CallTracker;
|
||||
import com.android.internal.telephony.CommandException;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.Connection;
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.IccRecords;
|
||||
import com.android.internal.telephony.MccTable;
|
||||
import com.android.internal.telephony.IccCard;
|
||||
import com.android.internal.telephony.IccException;
|
||||
import com.android.internal.telephony.IccFileHandler;
|
||||
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
|
||||
import com.android.internal.telephony.IccSmsInterfaceManager;
|
||||
import com.android.internal.telephony.MccTable;
|
||||
import com.android.internal.telephony.MmiCode;
|
||||
import com.android.internal.telephony.OperatorInfo;
|
||||
import com.android.internal.telephony.Phone;
|
||||
@@ -67,19 +62,17 @@ import com.android.internal.telephony.ServiceStateTracker;
|
||||
import com.android.internal.telephony.TelephonyIntents;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
import com.android.internal.telephony.UUSInfo;
|
||||
import com.android.internal.telephony.CallTracker;
|
||||
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
|
||||
import com.android.internal.telephony.cat.CatService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
@@ -109,13 +102,13 @@ public class CDMAPhone extends PhoneBase {
|
||||
CatService mCcatService;
|
||||
|
||||
// mNvLoadedRegistrants are informed after the EVENT_NV_READY
|
||||
private RegistrantList mNvLoadedRegistrants = new RegistrantList();
|
||||
private final RegistrantList mNvLoadedRegistrants = new RegistrantList();
|
||||
|
||||
// mEriFileLoadedRegistrants are informed after the ERI text has been loaded
|
||||
private RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
|
||||
private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
|
||||
|
||||
// mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started
|
||||
private RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
|
||||
private final RegistrantList mEcmTimerResetRegistrants = new RegistrantList();
|
||||
|
||||
// mEcmExitRespRegistrant is informed after the phone has been exited
|
||||
//the emergency callback mode
|
||||
@@ -131,6 +124,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
|
||||
// A runnable which is used to automatically exit from Ecm after a period of time.
|
||||
private Runnable mExitEcmRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
exitEmergencyCallbackMode();
|
||||
}
|
||||
@@ -164,7 +158,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
protected void init(Context context, PhoneNotifier notifier) {
|
||||
mCM.setPhoneType(Phone.PHONE_TYPE_CDMA);
|
||||
mCT = new CdmaCallTracker(this);
|
||||
mSMS = new CdmaSMSDispatcher(this);
|
||||
mSMS = new CdmaSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
|
||||
mDataConnectionTracker = new CdmaDataConnectionTracker (this);
|
||||
mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
|
||||
mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
|
||||
@@ -188,7 +182,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
|
||||
//Change the system setting
|
||||
SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
|
||||
new Integer(Phone.PHONE_TYPE_CDMA).toString());
|
||||
Integer.toString(Phone.PHONE_TYPE_CDMA));
|
||||
|
||||
// This is needed to handle phone process crashes
|
||||
String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
|
||||
@@ -220,6 +214,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
notifier.notifyMessageWaitingChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
super.dispose();
|
||||
@@ -253,23 +248,26 @@ public class CDMAPhone extends PhoneBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReferences() {
|
||||
log("removeReferences");
|
||||
this.mRuimPhoneBookInterfaceManager = null;
|
||||
this.mRuimSmsInterfaceManager = null;
|
||||
this.mSMS = null;
|
||||
this.mSubInfo = null;
|
||||
this.mIccRecords = null;
|
||||
this.mIccFileHandler = null;
|
||||
this.mIccCard = null;
|
||||
this.mDataConnectionTracker = null;
|
||||
this.mCT = null;
|
||||
this.mSST = null;
|
||||
this.mEriManager = null;
|
||||
this.mCcatService = null;
|
||||
this.mExitEcmRunnable = null;
|
||||
log("removeReferences");
|
||||
super.removeReferences();
|
||||
mRuimPhoneBookInterfaceManager = null;
|
||||
mRuimSmsInterfaceManager = null;
|
||||
mSMS = null;
|
||||
mSubInfo = null;
|
||||
mIccRecords = null;
|
||||
mIccFileHandler = null;
|
||||
mIccCard = null;
|
||||
mDataConnectionTracker = null;
|
||||
mCT = null;
|
||||
mSST = null;
|
||||
mEriManager = null;
|
||||
mCcatService = null;
|
||||
mExitEcmRunnable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized");
|
||||
if (mWakeLock.isHeld()) {
|
||||
@@ -813,7 +811,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Notify any interested party of a Phone state change {@link Phone.State}
|
||||
*/
|
||||
/*package*/ void notifyPhoneStateChanged() {
|
||||
@@ -858,18 +856,6 @@ public class CDMAPhone extends PhoneBase {
|
||||
if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange");
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
updateMessageWaitingIndicator(boolean mwi) {
|
||||
// this also calls notifyMessageWaitingIndicator()
|
||||
mIccRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
|
||||
}
|
||||
|
||||
/* This function is overloaded to send number of voicemails instead of sending true/false */
|
||||
/*package*/ void
|
||||
updateMessageWaitingIndicator(int mwi) {
|
||||
mIccRecords.setVoiceMessageWaiting(1, mwi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEmergencyCallbackMode() {
|
||||
if (mWakeLock.isHeld()) {
|
||||
@@ -1013,6 +999,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
|
||||
case EVENT_RUIM_RECORDS_LOADED:{
|
||||
Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
|
||||
updateCurrentCarrierInProvider();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1172,7 +1159,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
private static final int IS683_CONST_1900MHZ_F_BLOCK = 7;
|
||||
private static final int INVALID_SYSTEM_SELECTION_CODE = -1;
|
||||
|
||||
private boolean isIs683OtaSpDialStr(String dialStr) {
|
||||
private static boolean isIs683OtaSpDialStr(String dialStr) {
|
||||
int sysSelCodeInt;
|
||||
boolean isOtaspDialString = false;
|
||||
int dialStrLen = dialStr.length();
|
||||
@@ -1203,7 +1190,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
/**
|
||||
* This function extracts the system selection code from the dial string.
|
||||
*/
|
||||
private int extractSelCodeFromOtaSpNum(String dialStr) {
|
||||
private static int extractSelCodeFromOtaSpNum(String dialStr) {
|
||||
int dialStrLen = dialStr.length();
|
||||
int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE;
|
||||
|
||||
@@ -1226,7 +1213,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
* the dial string "sysSelCodeInt' is the system selection code specified
|
||||
* in the carrier ota sp number schema "sch".
|
||||
*/
|
||||
private boolean
|
||||
private static boolean
|
||||
checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) {
|
||||
boolean isOtaSpNum = false;
|
||||
try {
|
||||
@@ -1414,7 +1401,7 @@ public class CDMAPhone extends PhoneBase {
|
||||
Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
|
||||
ContentValues map = new ContentValues();
|
||||
map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
|
||||
log("updateCurrentCarrierInProvider insert uri=" + uri);
|
||||
log("updateCurrentCarrierInProvider from system: numeric=" + operatorNumeric);
|
||||
getContext().getContentResolver().insert(uri, map);
|
||||
|
||||
// Updates MCC MNC device configuration information
|
||||
@@ -1428,6 +1415,16 @@ public class CDMAPhone extends PhoneBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "current" field in the telephony provider according to the SIM's operator.
|
||||
* Implemented in {@link CDMALTEPhone} for CDMA/LTE devices.
|
||||
*
|
||||
* @return true for success; false otherwise.
|
||||
*/
|
||||
boolean updateCurrentCarrierInProvider() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void prepareEri() {
|
||||
mEriManager.loadEriFile();
|
||||
if(mEriManager.isEriFileLoaded()) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.internal.telephony.IccFileHandler;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.MccTable;
|
||||
import com.android.internal.telephony.PhoneBase;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.cdma.sms.UserData;
|
||||
import com.android.internal.telephony.gsm.SIMRecords;
|
||||
import com.android.internal.telephony.ims.IsimRecords;
|
||||
@@ -438,4 +439,13 @@ public final class CdmaLteUiccRecords extends SIMRecords {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch 3GPP format message. For CDMA/LTE phones,
|
||||
* send the message to the secondary 3GPP format SMS dispatcher.
|
||||
*/
|
||||
@Override
|
||||
protected int dispatchGsmMessage(SmsMessageBase message) {
|
||||
return ((CDMALTEPhone) phone).m3gppSMS.dispatchMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Message;
|
||||
import android.os.SystemProperties;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -40,6 +39,8 @@ import com.android.internal.telephony.SMSDispatcher;
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
|
||||
import com.android.internal.telephony.SmsStorageMonitor;
|
||||
import com.android.internal.telephony.SmsUsageMonitor;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
import com.android.internal.telephony.WspTypeDecoder;
|
||||
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
|
||||
@@ -47,7 +48,6 @@ import com.android.internal.telephony.cdma.sms.UserData;
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -60,24 +60,23 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
private byte[] mLastDispatchedSmsFingerprint;
|
||||
private byte[] mLastAcknowledgedSmsFingerprint;
|
||||
|
||||
private boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
|
||||
private final boolean mCheckForDuplicatePortsInOmadmWapPush = Resources.getSystem().getBoolean(
|
||||
com.android.internal.R.bool.config_duplicate_port_omadm_wappush);
|
||||
|
||||
CdmaSMSDispatcher(CDMAPhone phone) {
|
||||
super(phone);
|
||||
CdmaSMSDispatcher(CDMAPhone phone, SmsStorageMonitor storageMonitor,
|
||||
SmsUsageMonitor usageMonitor) {
|
||||
super(phone, storageMonitor, usageMonitor);
|
||||
mCm.setOnNewCdmaSms(this, EVENT_NEW_SMS, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
Log.d(TAG, "Voicemail count=" + voicemailCount);
|
||||
// Store the voicemail count in preferences.
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
|
||||
mPhone.getContext());
|
||||
mContext);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
|
||||
editor.apply();
|
||||
((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
|
||||
mPhone.setVoiceMessageWaiting(1, voicemailCount);
|
||||
handled = true;
|
||||
} else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
|
||||
(SmsEnvelope.TELESERVICE_WEMT == teleService)) &&
|
||||
@@ -160,7 +159,8 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
|
||||
if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) {
|
||||
if (!mStorageMonitor.isStorageAvailable() &&
|
||||
sms.getMessageClass() != MessageClass.CLASS_0) {
|
||||
// It's a storable message and there's no storage available. Bail.
|
||||
// (See C.S0015-B v2.0 for a description of "Immediate Display"
|
||||
// messages, which we represent as CLASS_0.)
|
||||
@@ -181,48 +181,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
return Intents.RESULT_SMS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO(cleanup): Why are we using a getter method for this
|
||||
* (and for so many other sms fields)? Trivial getters and
|
||||
* setters like this are direct violations of the style guide.
|
||||
* If the purpose is to protect against writes (by not
|
||||
* providing a setter) then any protection is illusory (and
|
||||
* hence bad) for cases where the values are not primitives,
|
||||
* such as this call for the header. Since this is an issue
|
||||
* with the public API it cannot be changed easily, but maybe
|
||||
* something can be done eventually.
|
||||
*/
|
||||
SmsHeader smsHeader = sms.getUserDataHeader();
|
||||
|
||||
/*
|
||||
* TODO(cleanup): Since both CDMA and GSM use the same header
|
||||
* format, this dispatch processing is naturally identical,
|
||||
* and code should probably not be replicated explicitly.
|
||||
*/
|
||||
|
||||
// See if message is partial or port addressed.
|
||||
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
|
||||
// Message is not partial (not part of concatenated sequence).
|
||||
byte[][] pdus = new byte[1][];
|
||||
pdus[0] = sms.getPdu();
|
||||
|
||||
if (smsHeader != null && smsHeader.portAddrs != null) {
|
||||
if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
// GSM-style WAP indication
|
||||
return mWapPush.dispatchWapPdu(sms.getUserData());
|
||||
} else {
|
||||
// The message was sent to a port, so concoct a URI for it.
|
||||
dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
|
||||
}
|
||||
} else {
|
||||
// Normal short and non-port-addressed message, dispatch it.
|
||||
dispatchPdus(pdus);
|
||||
}
|
||||
return Activity.RESULT_OK;
|
||||
} else {
|
||||
// Process the message part.
|
||||
return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
|
||||
}
|
||||
return dispatchNormalMessage(smsb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,23 +195,19 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
* to applications
|
||||
*/
|
||||
protected int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
|
||||
int segment;
|
||||
int totalSegments;
|
||||
int index = 0;
|
||||
int msgType;
|
||||
|
||||
int sourcePort = 0;
|
||||
int destinationPort = 0;
|
||||
|
||||
msgType = pdu[index++];
|
||||
if (msgType != 0){
|
||||
int msgType = pdu[index++];
|
||||
if (msgType != 0) {
|
||||
Log.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
totalSegments = pdu[index++]; // >=1
|
||||
segment = pdu[index++]; // >=0
|
||||
int totalSegments = pdu[index++]; // >= 1
|
||||
int segment = pdu[index++]; // >= 0
|
||||
|
||||
// Only the first segment contains sourcePort and destination Port
|
||||
int sourcePort = 0;
|
||||
int destinationPort = 0;
|
||||
if (segment == 0) {
|
||||
//process WDP segment
|
||||
sourcePort = (0xFF & pdu[index++]) << 8;
|
||||
@@ -269,90 +224,16 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
}
|
||||
|
||||
// Lookup all other related parts
|
||||
StringBuilder where = new StringBuilder("reference_number =");
|
||||
where.append(referenceNumber);
|
||||
where.append(" AND address = ?");
|
||||
String[] whereArgs = new String[] {address};
|
||||
|
||||
Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address
|
||||
+ ", src-port = " + sourcePort + ", dst-port = " + destinationPort
|
||||
+ ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments);
|
||||
+ ", 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 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
|
||||
/** {@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 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
byte pdu[] = (byte[]) map.get("pdu");
|
||||
|
||||
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
|
||||
|
||||
mCm.sendCdmaSms(pdu, reply);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void sendMultipartSms (SmsTracker tracker) {
|
||||
Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
|
||||
// FIXME unit test leaves cm == null. this should change
|
||||
|
||||
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) {
|
||||
String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
|
||||
if (inEcm.equals("true")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCm != null) {
|
||||
int causeCode = resultToCause(result);
|
||||
mCm.acknowledgeLastIncomingCdmaSms(success, causeCode, response);
|
||||
int causeCode = resultToCause(result);
|
||||
mCm.acknowledgeLastIncomingCdmaSms(success, causeCode, response);
|
||||
|
||||
if (causeCode == 0) {
|
||||
mLastAcknowledgedSmsFingerprint = mLastDispatchedSmsFingerprint;
|
||||
}
|
||||
mLastDispatchedSmsFingerprint = null;
|
||||
if (causeCode == 0) {
|
||||
mLastAcknowledgedSmsFingerprint = mLastDispatchedSmsFingerprint;
|
||||
}
|
||||
mLastDispatchedSmsFingerprint = null;
|
||||
}
|
||||
|
||||
protected void handleBroadcastSms(AsyncResult ar) {
|
||||
// Not supported
|
||||
Log.e(TAG, "Error! Not implemented for CDMA.");
|
||||
}
|
||||
|
||||
private int resultToCause(int rc) {
|
||||
private static int resultToCause(int rc) {
|
||||
switch (rc) {
|
||||
case Activity.RESULT_OK:
|
||||
case Intents.RESULT_SMS_HANDLED:
|
||||
@@ -527,7 +358,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
* @return True if OrigPdu is OmaDM Push Message which has duplicate ports.
|
||||
* False if OrigPdu is NOT OmaDM Push Message which has duplicate ports.
|
||||
*/
|
||||
private boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) {
|
||||
private static boolean checkDuplicatePortOmadmWappush(byte[] origPdu, int index) {
|
||||
index += 4;
|
||||
byte[] omaPdu = new byte[origPdu.length - index];
|
||||
System.arraycopy(origPdu, index, omaPdu, 0, omaPdu.length);
|
||||
|
||||
@@ -113,30 +113,6 @@ public class SmsMessage extends SmsMessageBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCMT(String[] lines) {
|
||||
Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCMTI(String line) {
|
||||
Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCDS(String line) {
|
||||
Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
|
||||
* Note: Only primitive fields are set.
|
||||
|
||||
@@ -56,9 +56,6 @@ import com.android.internal.telephony.CallForwardInfo;
|
||||
import com.android.internal.telephony.CallStateException;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.Connection;
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.DataConnectionTracker;
|
||||
import com.android.internal.telephony.IccCard;
|
||||
import com.android.internal.telephony.IccFileHandler;
|
||||
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
|
||||
import com.android.internal.telephony.IccSmsInterfaceManager;
|
||||
@@ -140,7 +137,7 @@ public class GSMPhone extends PhoneBase {
|
||||
mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
|
||||
mCT = new GsmCallTracker(this);
|
||||
mSST = new GsmServiceStateTracker (this);
|
||||
mSMS = new GsmSMSDispatcher(this);
|
||||
mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
|
||||
mIccFileHandler = new SIMFileHandler(this);
|
||||
mIccRecords = new SIMRecords(this);
|
||||
mDataConnectionTracker = new GsmDataConnectionTracker (this);
|
||||
@@ -199,6 +196,7 @@ public class GSMPhone extends PhoneBase {
|
||||
new Integer(Phone.PHONE_TYPE_GSM).toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
super.dispose();
|
||||
@@ -228,19 +226,22 @@ public class GSMPhone extends PhoneBase {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeReferences() {
|
||||
this.mSimulatedRadioControl = null;
|
||||
this.mStkService = null;
|
||||
this.mSimPhoneBookIntManager = null;
|
||||
this.mSimSmsIntManager = null;
|
||||
this.mSMS = null;
|
||||
this.mSubInfo = null;
|
||||
this.mIccRecords = null;
|
||||
this.mIccFileHandler = null;
|
||||
this.mIccCard = null;
|
||||
this.mDataConnectionTracker = null;
|
||||
this.mCT = null;
|
||||
this.mSST = null;
|
||||
Log.d(LOG_TAG, "removeReferences");
|
||||
super.removeReferences();
|
||||
mSimulatedRadioControl = null;
|
||||
mStkService = null;
|
||||
mSimPhoneBookIntManager = null;
|
||||
mSimSmsIntManager = null;
|
||||
mSMS = null;
|
||||
mSubInfo = null;
|
||||
mIccRecords = null;
|
||||
mIccFileHandler = null;
|
||||
mIccCard = null;
|
||||
mDataConnectionTracker = null;
|
||||
mCT = null;
|
||||
mSST = null;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
@@ -405,17 +406,6 @@ public class GSMPhone extends PhoneBase {
|
||||
mNotifier.notifySignalStrength(this);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -30,13 +30,15 @@ import android.telephony.SmsCbMessage;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.BaseCommands;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.PhoneBase;
|
||||
import com.android.internal.telephony.SMSDispatcher;
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
|
||||
import com.android.internal.telephony.SmsStorageMonitor;
|
||||
import com.android.internal.telephony.SmsUsageMonitor;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -45,16 +47,55 @@ import java.util.Iterator;
|
||||
|
||||
import static android.telephony.SmsMessage.MessageClass;
|
||||
|
||||
final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
public final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
private static final String TAG = "GSM";
|
||||
|
||||
private GSMPhone mGsmPhone;
|
||||
/** Status report received */
|
||||
private static final int EVENT_NEW_SMS_STATUS_REPORT = 100;
|
||||
|
||||
GsmSMSDispatcher(GSMPhone phone) {
|
||||
super(phone);
|
||||
mGsmPhone = phone;
|
||||
/** New broadcast SMS */
|
||||
private static final int EVENT_NEW_BROADCAST_SMS = 101;
|
||||
|
||||
((BaseCommands)mCm).setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null);
|
||||
public GsmSMSDispatcher(PhoneBase phone, SmsStorageMonitor storageMonitor,
|
||||
SmsUsageMonitor usageMonitor) {
|
||||
super(phone, storageMonitor, usageMonitor);
|
||||
mCm.setOnNewGsmSms(this, EVENT_NEW_SMS, null);
|
||||
mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
|
||||
mCm.setOnNewGsmBroadcastSms(this, EVENT_NEW_BROADCAST_SMS, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
mCm.unSetOnNewGsmSms(this);
|
||||
mCm.unSetOnSmsStatus(this);
|
||||
mCm.unSetOnNewGsmBroadcastSms(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFormat() {
|
||||
return android.telephony.SmsMessage.FORMAT_3GPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles 3GPP format-specific events coming from the phone stack.
|
||||
* Other events are handled by {@link SMSDispatcher#handleMessage}.
|
||||
*
|
||||
* @param msg the message to handle
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case EVENT_NEW_SMS_STATUS_REPORT:
|
||||
handleStatusReport((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_NEW_BROADCAST_SMS:
|
||||
handleBroadcastSms((AsyncResult)msg.obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,8 +105,7 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
* @param ar AsyncResult passed into the message handler. ar.result should
|
||||
* be a String representing the status report PDU, as ASCII hex.
|
||||
*/
|
||||
@Override
|
||||
protected void handleStatusReport(AsyncResult ar) {
|
||||
private void handleStatusReport(AsyncResult ar) {
|
||||
String pduString = (String) ar.result;
|
||||
SmsMessage sms = SmsMessage.newFromCDS(pduString);
|
||||
|
||||
@@ -94,17 +134,17 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
acknowledgeLastIncomingSms(true, Intents.RESULT_SMS_HANDLED, null);
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int dispatchMessage(SmsMessageBase smsb) {
|
||||
|
||||
// If sms is null, means there was a parsing error.
|
||||
if (smsb == null) {
|
||||
Log.e(TAG, "dispatchMessage: message is null");
|
||||
return Intents.RESULT_SMS_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
SmsMessage sms = (SmsMessage) smsb;
|
||||
boolean handled = false;
|
||||
|
||||
if (sms.isTypeZero()) {
|
||||
// As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
|
||||
@@ -121,14 +161,15 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
}
|
||||
|
||||
// Special case the message waiting indicator messages
|
||||
boolean handled = false;
|
||||
if (sms.isMWISetMessage()) {
|
||||
mGsmPhone.updateMessageWaitingIndicator(true);
|
||||
mPhone.setVoiceMessageWaiting(1, -1); // line 1: unknown number of msgs waiting
|
||||
handled = sms.isMwiDontStore();
|
||||
if (false) {
|
||||
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
|
||||
}
|
||||
} else if (sms.isMWIClearMessage()) {
|
||||
mGsmPhone.updateMessageWaitingIndicator(false);
|
||||
mPhone.setVoiceMessageWaiting(1, 0); // line 1: no msgs waiting
|
||||
handled = sms.isMwiDontStore();
|
||||
if (false) {
|
||||
Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
|
||||
@@ -139,35 +180,14 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
return Intents.RESULT_SMS_HANDLED;
|
||||
}
|
||||
|
||||
if (!mStorageAvailable && (sms.getMessageClass() != MessageClass.CLASS_0)) {
|
||||
if (!mStorageMonitor.isStorageAvailable() &&
|
||||
sms.getMessageClass() != MessageClass.CLASS_0) {
|
||||
// It's a storable message and there's no storage available. Bail.
|
||||
// (See TS 23.038 for a description of class 0 messages.)
|
||||
return Intents.RESULT_SMS_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
SmsHeader smsHeader = sms.getUserDataHeader();
|
||||
// See if message is partial or port addressed.
|
||||
if ((smsHeader == null) || (smsHeader.concatRef == null)) {
|
||||
// Message is not partial (not part of concatenated sequence).
|
||||
byte[][] pdus = new byte[1][];
|
||||
pdus[0] = sms.getPdu();
|
||||
|
||||
if (smsHeader != null && smsHeader.portAddrs != null) {
|
||||
if (smsHeader.portAddrs.destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
return mWapPush.dispatchWapPdu(sms.getUserData());
|
||||
} else {
|
||||
// The message was sent to a port, so concoct a URI for it.
|
||||
dispatchPortAddressedPdus(pdus, smsHeader.portAddrs.destPort);
|
||||
}
|
||||
} else {
|
||||
// Normal short and non-port-addressed message, dispatch it.
|
||||
dispatchPdus(pdus);
|
||||
}
|
||||
return Activity.RESULT_OK;
|
||||
} else {
|
||||
// Process the message part.
|
||||
return processMessagePart(sms, smsHeader.concatRef, smsHeader.portAddrs);
|
||||
}
|
||||
return dispatchNormalMessage(smsb);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -190,158 +210,20 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void sendMultipartText(String destinationAddress, String scAddress,
|
||||
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
int refNumber = getNextConcatenatedRef() & 0x00FF;
|
||||
int msgCount = parts.size();
|
||||
int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
|
||||
|
||||
mRemainingMessages = msgCount;
|
||||
|
||||
TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
|
||||
if (encoding != details.codeUnitSize
|
||||
&& (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
|
||||
|| encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
|
||||
encoding = details.codeUnitSize;
|
||||
}
|
||||
encodingForParts[i] = details;
|
||||
}
|
||||
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
|
||||
concatRef.refNumber = refNumber;
|
||||
concatRef.seqNumber = i + 1; // 1-based sequence
|
||||
concatRef.msgCount = msgCount;
|
||||
// TODO: We currently set this to true since our messaging app will never
|
||||
// send more than 255 parts (it converts the message to MMS well before that).
|
||||
// However, we should support 3rd party messaging apps that might need 16-bit
|
||||
// references
|
||||
// Note: It's not sufficient to just flip this bit to true; it will have
|
||||
// ripple effects (several calculations assume 8-bit ref).
|
||||
concatRef.isEightBits = true;
|
||||
SmsHeader smsHeader = new SmsHeader();
|
||||
smsHeader.concatRef = concatRef;
|
||||
if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
|
||||
smsHeader.languageTable = encodingForParts[i].languageTable;
|
||||
smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
|
||||
}
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
|
||||
PendingIntent deliveryIntent = null;
|
||||
if (deliveryIntents != null && deliveryIntents.size() > i) {
|
||||
deliveryIntent = deliveryIntents.get(i);
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
|
||||
encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
|
||||
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
protected TextEncodingDetails calculateLength(CharSequence messageBody,
|
||||
boolean use7bitOnly) {
|
||||
return SmsMessage.calculateLength(messageBody, use7bitOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS which already passed SMS control check.
|
||||
*
|
||||
* It is the working function for sendMultipartText().
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*/
|
||||
private void sendMultipartTextWithPermit(String destinationAddress,
|
||||
String scAddress, ArrayList<String> parts,
|
||||
ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
// check if in service
|
||||
int ss = mPhone.getServiceState().getState();
|
||||
if (ss != ServiceState.STATE_IN_SERVICE) {
|
||||
for (int i = 0, count = parts.size(); i < count; i++) {
|
||||
PendingIntent sentIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
SmsTracker tracker = SmsTrackerFactory(null, sentIntent, null);
|
||||
handleNotInService(ss, tracker);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int refNumber = getNextConcatenatedRef() & 0x00FF;
|
||||
int msgCount = parts.size();
|
||||
int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
|
||||
|
||||
mRemainingMessages = msgCount;
|
||||
|
||||
TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
|
||||
if (encoding != details.codeUnitSize
|
||||
&& (encoding == android.telephony.SmsMessage.ENCODING_UNKNOWN
|
||||
|| encoding == android.telephony.SmsMessage.ENCODING_7BIT)) {
|
||||
encoding = details.codeUnitSize;
|
||||
}
|
||||
encodingForParts[i] = details;
|
||||
}
|
||||
|
||||
for (int i = 0; i < msgCount; i++) {
|
||||
SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
|
||||
concatRef.refNumber = refNumber;
|
||||
concatRef.seqNumber = i + 1; // 1-based sequence
|
||||
concatRef.msgCount = msgCount;
|
||||
concatRef.isEightBits = false;
|
||||
SmsHeader smsHeader = new SmsHeader();
|
||||
smsHeader.concatRef = concatRef;
|
||||
if (encoding == android.telephony.SmsMessage.ENCODING_7BIT) {
|
||||
smsHeader.languageTable = encodingForParts[i].languageTable;
|
||||
smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
|
||||
}
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
|
||||
PendingIntent deliveryIntent = null;
|
||||
if (deliveryIntents != null && deliveryIntents.size() > i) {
|
||||
deliveryIntent = deliveryIntents.get(i);
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
parts.get(i), deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
|
||||
encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("smsc", pdus.encodedScAddress);
|
||||
map.put("pdu", pdus.encodedMessage);
|
||||
|
||||
SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent);
|
||||
sendSms(tracker);
|
||||
}
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
|
||||
String message, SmsHeader smsHeader, int encoding,
|
||||
PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart) {
|
||||
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
|
||||
encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
|
||||
sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -353,45 +235,16 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
byte pdu[] = (byte[]) map.get("pdu");
|
||||
|
||||
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
|
||||
mCm.sendSMS(IccUtils.bytesToHexString(smsc),
|
||||
IccUtils.bytesToHexString(pdu), reply);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the multi-part SMS based on multipart Sms tracker
|
||||
*
|
||||
* @param tracker holds the multipart Sms tracker ready to be sent
|
||||
*/
|
||||
@Override
|
||||
protected void sendMultipartSms (SmsTracker tracker) {
|
||||
ArrayList<String> parts;
|
||||
ArrayList<PendingIntent> sentIntents;
|
||||
ArrayList<PendingIntent> deliveryIntents;
|
||||
|
||||
HashMap<String, Object> map = tracker.mData;
|
||||
|
||||
String destinationAddress = (String) map.get("destination");
|
||||
String scAddress = (String) map.get("scaddress");
|
||||
|
||||
parts = (ArrayList<String>) map.get("parts");
|
||||
sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
|
||||
deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
|
||||
|
||||
sendMultipartTextWithPermit(destinationAddress,
|
||||
scAddress, parts, sentIntents, deliveryIntents);
|
||||
|
||||
mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){
|
||||
// FIXME unit test leaves cm == null. this should change
|
||||
if (mCm != null) {
|
||||
mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response);
|
||||
}
|
||||
protected void acknowledgeLastIncomingSms(boolean success, int result, Message response) {
|
||||
mCm.acknowledgeLastIncomingGsmSms(success, resultToCause(result), response);
|
||||
}
|
||||
|
||||
private int resultToCause(int rc) {
|
||||
private static int resultToCause(int rc) {
|
||||
switch (rc) {
|
||||
case Activity.RESULT_OK:
|
||||
case Intents.RESULT_SMS_HANDLED:
|
||||
@@ -485,10 +338,12 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
private final HashMap<SmsCbConcatInfo, byte[][]> mSmsCbPageMap =
|
||||
new HashMap<SmsCbConcatInfo, byte[][]>();
|
||||
|
||||
@Override
|
||||
protected void handleBroadcastSms(AsyncResult ar) {
|
||||
/**
|
||||
* Handle 3GPP format SMS-CB message.
|
||||
* @param ar the AsyncResult containing the received PDUs
|
||||
*/
|
||||
private void handleBroadcastSms(AsyncResult ar) {
|
||||
try {
|
||||
byte[][] pdus = null;
|
||||
byte[] receivedPdu = (byte[])ar.result;
|
||||
|
||||
if (false) {
|
||||
@@ -507,10 +362,11 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
|
||||
SmsCbHeader header = new SmsCbHeader(receivedPdu);
|
||||
String plmn = SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
|
||||
GsmCellLocation cellLocation = (GsmCellLocation)mGsmPhone.getCellLocation();
|
||||
GsmCellLocation cellLocation = (GsmCellLocation) mPhone.getCellLocation();
|
||||
int lac = cellLocation.getLac();
|
||||
int cid = cellLocation.getCid();
|
||||
|
||||
byte[][] pdus;
|
||||
if (header.nrOfPages > 1) {
|
||||
// Multi-page message
|
||||
SmsCbConcatInfo concatInfo = new SmsCbConcatInfo(header, plmn, lac, cid);
|
||||
@@ -563,5 +419,4 @@ final class GsmSMSDispatcher extends SMSDispatcher {
|
||||
Log.e(TAG, "Error in decoding SMS CB pdu", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.android.internal.telephony.IccVmNotSupportedException;
|
||||
import com.android.internal.telephony.MccTable;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneBase;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -1160,6 +1161,15 @@ public class SIMRecords extends IccRecords {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch 3GPP format message. Overridden for CDMA/LTE phones by
|
||||
* {@link com.android.internal.telephony.cdma.CdmaLteUiccRecords}
|
||||
* to send messages to the secondary 3GPP format SMS dispatcher.
|
||||
*/
|
||||
protected int dispatchGsmMessage(SmsMessageBase message) {
|
||||
return phone.mSMS.dispatchMessage(message);
|
||||
}
|
||||
|
||||
private void handleSms(byte[] ba) {
|
||||
if (ba[0] != 0)
|
||||
Log.d("ENF", "status : " + ba[0]);
|
||||
@@ -1175,7 +1185,7 @@ public class SIMRecords extends IccRecords {
|
||||
System.arraycopy(ba, 1, pdu, 0, n - 1);
|
||||
SmsMessage message = SmsMessage.createFromPdu(pdu);
|
||||
|
||||
phone.mSMS.dispatchMessage(message);
|
||||
dispatchGsmMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1201,7 +1211,7 @@ public class SIMRecords extends IccRecords {
|
||||
System.arraycopy(ba, 1, pdu, 0, n - 1);
|
||||
SmsMessage message = SmsMessage.createFromPdu(pdu);
|
||||
|
||||
phone.mSMS.dispatchMessage(message);
|
||||
dispatchGsmMessage(message);
|
||||
|
||||
// 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3
|
||||
// 1 == "received by MS from network; message read"
|
||||
|
||||
@@ -136,14 +136,6 @@ public class SmsMessage extends SmsMessageBase {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromCMTI(String line) {
|
||||
// the thinking here is not to read the message immediately
|
||||
// FTA test case
|
||||
Log.e(LOG_TAG, "newFromCMTI: not yet supported");
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromCDS(String line) {
|
||||
try {
|
||||
@@ -156,15 +148,6 @@ public class SmsMessage extends SmsMessageBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This functionality is currently not supported in GSM mode.
|
||||
* @hide
|
||||
*/
|
||||
public static SmsMessageBase newFromParcel(Parcel p){
|
||||
Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from an SMS EF record.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user