Android Open Source - SMSSentTime Sms Receiver






From Project

Back to project page SMSSentTime.

License

The source code is released under:

GNU General Public License

If you think the Android project SMSSentTime listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package at.zweng.smssenttimefix;
//from  w w  w  .jav a2 s. c  o  m
import static at.zweng.smssenttimefix.Constants.ACTION_SMS_RCVD;
import static at.zweng.smssenttimefix.Constants.DEBUG_ENABLED_DEFAULT_VALUE;
import static at.zweng.smssenttimefix.Constants.EXTRA_BODIES;
import static at.zweng.smssenttimefix.Constants.EXTRA_ORIGINATORS;
import static at.zweng.smssenttimefix.Constants.EXTRA_SC_ADRESSES;
import static at.zweng.smssenttimefix.Constants.EXTRA_SC_TIMESTAMPS;
import static at.zweng.smssenttimefix.Constants.PREF_DBG_DEBUG_ENABLED;
import static at.zweng.smssenttimefix.Constants.PREF_DBG_FILENAME;
import static at.zweng.smssenttimefix.Constants.PREF_SVC_ENABLED;
import static at.zweng.smssenttimefix.Constants.TAG;

import java.util.ArrayList;
import java.util.List;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.telephony.gsm.SmsMessage;
import android.util.Log;
import android.widget.Toast;

/**
 * Broadcast receiver, registered to get informed about new incoming SMS by the
 * Android framework. If we get a new SMS we remember the original sent
 * timestamp from the SMSC and start a service which changes the date in the
 * SMS-DB after the sms got stored by the SMS application.
 * 
 * @author John Zweng
 */

// Info: we use the deprecated class "SmsMessage" to
// ensure compatibility to older Android SDK levels.
@SuppressWarnings("deprecation")
public class SmsReceiver extends BroadcastReceiver {

  /**
   * our context we are running in
   */
  private Context ctx;

  /**
   * SD card logger
   */
  private static SDCardLogger SD;

  /**
   * Gets called from Android framework whenever a SMS is received
   */
  @Override
  public void onReceive(Context context, Intent intent) {
    Log.i(TAG, "BroadcastReceiver: Incoming SMS received.");

    // get logger
    SD = SDCardLogger.getLogger(context.getSharedPreferences(
        PREF_DBG_FILENAME, 0).getBoolean(PREF_DBG_DEBUG_ENABLED,
        DEBUG_ENABLED_DEFAULT_VALUE));

    // only if logging is really enabled
    if (SD.isLoggingEnabled()) {
      Toast toast = Toast.makeText(context,
          context.getString(R.string.dbg_toastOnSMSReceived),
          Toast.LENGTH_LONG);
      toast.show();
    }

    SD.log("BroadcastReceiver: Android notified us that an incoming SMS arrived (onReceive broadcast)");
    try {
      this.ctx = context;
      if (!PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean(
          PREF_SVC_ENABLED, true)) {
        // Log.i(TAG,
        // "BroadcastReceiver: Received SMS, but SMS Time Fix DISABLED"
        // + " in preferences. Will do nothing and exit immediately!");
        SD.log("BroadcastReceiver: SMS Sent Time is DISABLED in preferences, will do nothing.");
        return;
      }

      // Do some checks and log:
      if (intent == null) {
        Log.w(TAG,
            "BroadcastReceiver: Received SMS, but Intent was null. Will exit and do nothing.");
        SD.log("BroadcastReceiver: Received SMS, but Intent was null. Will exit and do nothing.");
        return;
      }
      if (intent.getAction() == null) {
        Log.w(TAG,
            "BroadcastReceiver: Received SMS, but Intent action was null. Will exit and do nothing");
        SD.log("BroadcastReceiver: Received SMS, but Intent action was null. Will exit and do nothing");
        return;
      }
      SD.log("BroadcastReceiver: SMS Sent Time is ENABLED.");
      String action = intent.getAction();
      // Log.d(TAG, "BroadcastReceiver: Received intent action: " +
      // action);

      if (!action.equals(ACTION_SMS_RCVD)) {
        Log.w(TAG,
            "BroadcastReceiver: Intent action was not for an incoming SMS. Will exit and do nothing.");
        SD.log("BroadcastReceiver: Intent action was not for an incoming SMS. Will exit and do nothing.");
        return;
      }

      // Get out the message pdrotocol data units (PDUs), convert them
      // into message objects and start the Fix service for them
      Bundle bundle = intent.getExtras();
      SmsMessage sms[] = constructSmsFromPDUs((Object[]) bundle
          .get("pdus"));
      // Filter messages before we start the service
      // (we do not send every message to the fix service
      // -> see filter method)
      SD.log("BroadcastReceiver: Extracted " + sms.length
          + " sms objects from PDU. Will start SmsTimeFixService.");
      startFixServiceForSMS(filterMessages(sms));

    } catch (Exception t) {
      Log.e(TAG,
          "BroadcastReceiver: SOMETHING WENT WRONG! Catched Exception:  "
              + t, t);
      SD.log("BroadcastReceiver: SOMETHING WENT WRONG! Catched Exception:  "
          + t);
    } finally {
      Log.d(TAG,
          "BroadcastReceiver: Work successfully done. :-) Will exit now. GOOD BYE!");
      SD.log("BroadcastReceiver: Receiver is finished now and will exit. GOOD BYE!");
    }
  }

  /**
   * Construct SMS java objects from raw data bytes
   * 
   * @param rawPduData
   * @return
   */
  private SmsMessage[] constructSmsFromPDUs(Object[] rawPduData) {
    SmsMessage smsMessages[] = new SmsMessage[rawPduData.length];
    for (int n = 0; n < rawPduData.length; n++) {
      smsMessages[n] = SmsMessage.createFromPdu((byte[]) rawPduData[n]);
      // remove debug
      // Log.i(TAG, "BroadcastReceiver: sms #" + n + " body: '"
      // + smsMessages[n].getMessageBody() + "'");
    }
    // Log.d(TAG, "BroadcastReceiver: Parsed " + rawPduData.length
    // + " SMS message objects from raw sms data PDUs.");
    return smsMessages;
  }

  /**
   * Takes a bunch of messages and filters out 'system' messages like delivery
   * reports and others like that. Also returns only one message as I realized
   * later that all messages in the array belong to the same SMS
   * (multipart-sms) and for our check it's sufficcient to look at the first
   * one (in the most cases).
   * 
   * @param msgs
   * @return
   */
  private SmsMessage[] filterMessages(SmsMessage msgs[]) {
    // Log.d(TAG, "BroadcastReceiver: filterMessages: got " + msgs.length
    // + " msgs");
    List<SmsMessage> filtered = new ArrayList<SmsMessage>();

    // ASSUMPTION: at the moment we always return just 1 msg!!
    // Ich bin mir nicht sicher, ob das in allen Handynetzen so
    // funktioniert, aber wenn man ?berlange SMS sendet, kommen mehrere
    // PDUs. Ich gehe daher mal davon aus, dass mehrere PDUs IMMER zur
    // selben SMS geh?ren. --> ANNAHME STIMMT!! Habe Sourceode von 2.2.1
    // gecheckt:
    /*
     * Broadcast Action: A new text based SMS message has been received by
     * the device. The intent will have the following extra values:</p>
     * 
     * <ul> <li><em>pdus</em> - An Object[] od byte[]s containing the PDUs
     * that make up the message.</li> </ul>
     * 
     * <p>The extra values can be extracted using {@link
     * #getMessagesFromIntent(Intent)}.</p>
     * 
     * <p>If a BroadcastReceiver encounters an error while processing this
     * intent it should set the result code appropriately.</p>
     */
    for (SmsMessage sms : msgs) {

      if (sms.isEmail()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isEmail' flag. Will not process it (because we don't know if this may brteak something).");
        continue;
      }
      if (sms.isCphsMwiMessage()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isCphsMwiMessage' flag.");
        // continue;
      }
      if (sms.isMWIClearMessage()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isMWIClearMessage' flag.");
        // continue;
      }
      if (sms.isMwiDontStore()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isMwiDontStore' flag.");
        // continue;
      }
      if (sms.isMWISetMessage()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isMWISetMessage' flag.");
        // continue;
      }
      if (sms.isStatusReportMessage()) {
        SD.log("BroadcastReceiver: filterMessages: SMS has 'isStatusReportMessage' flag. Will not process it.");
        SD.log("BroadcastReceiver: filterMessages: status field has value: "
            + sms.getStatus());
        continue;
      }

      // check body
      if (sms.getMessageBody() == null) {
        SD.log("BroadcastReceiver: filterMessages: SMS message body is null. Will ignore this sms.");
        continue;
      }
      if (sms.getMessageBody().length() == 0) {
        SD.log("BroadcastReceiver: filterMessages: SMS message body length == 0. Will ignore this sms.");
        continue;
      }
      // check timestamp (just simple check if it's not 0 or kind of..
      if (sms.getTimestampMillis() < 5000L) {
        SD.log("BroadcastReceiver: filterMessages: SMS message timestamp is invalid: "
            + sms.getTimestampMillis() + ". Will ignore this sms.");
        continue;
      }

      filtered.add(sms);
      // INFO: assumption that we always only need to
      // inspect the first pdu sms:
      if (filtered.size() >= 1) {
        SD.log("BroadcastReceiver: filterMessages: We have >=1 pdu sms in the filtered work queue.");
        break;
      }
    }
    // Log.d(TAG,
    // "BroadcastReceiver: filterMessages: will return "
    // + filtered.size() + " msgs");
    return filtered.toArray(new SmsMessage[filtered.size()]);
  }

  /**
   * Starts the worker service which wll change the timestamp in DB
   * 
   * @param msgs
   */
  private void startFixServiceForSMS(SmsMessage msgs[]) {
    // Log.v(TAG,
    // "BroadcastReceiver: Constructing intent for service start.");
    if (msgs.length == 0) {
      Log.i(TAG,
          "BroadcastReceiver: After sorting out special sms we have 0 sms messages "
              + "left to process. Will do nothing and exit. GOOD BYE!");
      SD.log("BroadcastReceiver: After sorting out special sms we have 0 sms messages "
          + "left to process. Will do nothing and exit. GOOD BYE!");
      return;
    }

    Intent svcIntent = new Intent(ctx, SmsTimeFixService.class);

    // pack the data into the intent
    String scAddress[] = new String[msgs.length];
    String body[] = new String[msgs.length];
    String originator[] = new String[msgs.length];
    long scTimestamp[] = new long[msgs.length];
    for (int i = 0; i < msgs.length; i++) {
      scAddress[i] = msgs[i].getServiceCenterAddress();
      body[i] = msgs[i].getMessageBody();
      originator[i] = msgs[i].getOriginatingAddress();
      scTimestamp[i] = msgs[i].getTimestampMillis();
    }
    svcIntent.putExtra(EXTRA_SC_ADRESSES, scAddress);
    svcIntent.putExtra(EXTRA_BODIES, body);
    svcIntent.putExtra(EXTRA_ORIGINATORS, originator);
    svcIntent.putExtra(EXTRA_SC_TIMESTAMPS, scTimestamp);

    // Start the service
    ctx.startService(svcIntent);
  }

}




Java Source Code List

at.zweng.smssenttimefix.Constants.java
at.zweng.smssenttimefix.DebugSettingsActivity.java
at.zweng.smssenttimefix.SDCardLogger.java
at.zweng.smssenttimefix.SDNotMountedException.java
at.zweng.smssenttimefix.SmsFixException.java
at.zweng.smssenttimefix.SmsNotFoundException.java
at.zweng.smssenttimefix.SmsReceiver.java
at.zweng.smssenttimefix.SmsSentTimeFixActivity.java
at.zweng.smssenttimefix.SmsTimeFixPrefs.java
at.zweng.smssenttimefix.SmsTimeFixService.java
at.zweng.smssenttimefix.Util.java