Android Open Source - android-sms-relay Relay Service






From Project

Back to project page android-sms-relay.

License

The source code is released under:

GNU General Public License

If you think the Android project android-sms-relay 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 com.nyaruka.androidrelay;
//from  ww w. j  av  a  2s .co  m
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;

import com.commonsware.cwac.wakeful.WakefulIntentService;
import com.nyaruka.androidrelay.data.TextMessage;
import com.nyaruka.androidrelay.data.TextMessageHelper;

public class RelayService extends Service implements SMSModem.SmsModemListener {

  public static final String TAG = AndroidRelay.TAG;
  
  public static RelayService s_this = null;
  public static RelayService get(){ return s_this; }
  
  // what was the last alert type we sent
  public static long s_lastAlert;
  
  // constants for s_lastAlert
  public static final int ALERT_POWER_ON = 0;
  public static final int ALERT_50_PERCENT = 1;
  public static final int ALERT_25_PERCENT = 2;
  public static final int ALERT_5_PERCENT = 3;
  
  // APN related
  public static final Uri APN_TABLE_URI =  Uri.parse("content://telephony/carriers");
  public static final Uri PREFERRED_APN_URI = Uri.parse("content://telephony/carriers/preferapn");
  
  public static boolean doReset = false;
  public static boolean doSendLog = false;

  public int createAPN(String name, String apnAddr) {
    int id = -1;

    TelephonyManager tele = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    String mcc = tele.getSimOperator().substring(0, 3);
    String mnc = tele.getSimOperator().substring(3);
    
    ContentResolver resolver = this.getContentResolver();
    ContentValues values = new ContentValues();
    values.put("name", name);
    values.put("apn", apnAddr);

    values.put("mcc", mcc);
    values.put("mnc", mnc);
    values.put("numeric", tele.getSimOperator());
    
    Cursor cursor = null;
    
    try {
      Uri newAPN = resolver.insert(APN_TABLE_URI, values);
      if(newAPN != null) {
        cursor = resolver.query(newAPN, null, null, null, null);
        Log.d(TAG, "New APN added! Yeee.");

        // Obtain the apn id
                int idindex = cursor.getColumnIndex("_id");
                cursor.moveToFirst();
                id = cursor.getShort(idindex);
      }
    }catch (SQLException e) {
      Log.d(TAG, e.getMessage());
    }finally {
      if (cursor != null)
        cursor.close();
    }
    
    return id;
  }
  
  public int getDefaultAPN() {
    int id = -1;
    ContentResolver resolver = this.getContentResolver();
    Cursor cursor = resolver.query(PREFERRED_APN_URI, new String[] { "_id", "name" }, null, null, null);
    
    if (cursor != null) {
      try {
        if (cursor.moveToFirst()) {
          id = cursor.getInt(cursor.getColumnIndex("_id"));
        }
      } catch (SQLException e) {
        Log.d(TAG, e.getMessage());
      } finally {
      cursor.close();
      }
    }
    return id;
  }
  
  public boolean setDefaultAPN(int id) {
    boolean res = false;
        ContentResolver resolver = this.getContentResolver();
        ContentValues values = new ContentValues();

        values.put("apn_id", id); 

        try {
            resolver.update(PREFERRED_APN_URI, values, null, null);
            Cursor cursor = resolver.query(PREFERRED_APN_URI, new String[]{"name","apn"}, "_id="+id, null, null);
            if(cursor != null) {
                res = true;
                cursor.close();
            }
        }
        catch (SQLException e) {
            Log.d(TAG, e.getMessage());
        }
        return res;
  }

  public void deleteAPN(int id) {
    ContentResolver resolver = this.getContentResolver();
        
        try {
          resolver.delete(APN_TABLE_URI, "_id=?", new String[] { Integer.toString(id)});
        } catch(SQLException e) {
          
        }
  }
  
  public void deleteUnfavoriteAPNs() {
    ContentResolver resolver = this.getContentResolver();
    
    try {
          resolver.delete(APN_TABLE_URI, "apn LIKE ?", new String[]{"relay.nyaruka.com"});
    } catch(SQLException e) {
      
    }
  }
  
  public void tickleDefaultAPN() {
    int id_default = this.getDefaultAPN();
    int id_fakeAPN = this.createAPN("SMS Relay", "relay.nyaruka.com");

    Log.d(TAG, "Tickling the Default APN" + id_default +" by fake APN " + id_fakeAPN);

    // make the fake APN the default for
    this.setDefaultAPN(id_fakeAPN);

    // 30 seconds before
    try{
      Thread.sleep(30000);
    } catch (Throwable tt){}

    // switching back to the real working APN
    this.setDefaultAPN(id_default);
    
    //and delete the fake APN not in use anymore
    //this.deleteAPN(id_fakeAPN);
    this.deleteUnfavoriteAPNs();
  }
  
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }
  
  @Override
  public void onCreate(){
    s_this = this;
    modem = new SMSModem(getApplicationContext(), this);
    Log.d(TAG, "RelayService Created.");
    promoteErroredMessages();
    kickService();
  }
    
  public TextMessageHelper getHelper(){
    return AndroidRelay.getHelper(getApplicationContext());
  }

  public void checkPowerStatus(){
    Context c = getApplicationContext();
    Intent intent = this.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
    
    // get whether we are plugged in
    boolean hasPower = plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB;
    
    // get our battery level as percentage
    int level = intent.getIntExtra("level", 0);

    // no power
    if (!hasPower){
      // less than 5% and haven't already reported it
      if (level <= 5 && s_lastAlert != ALERT_5_PERCENT){
        if (sendAlert(c, "Relayer has no power and battery level at " + level + "%", "")){
          s_lastAlert = ALERT_5_PERCENT;
        }
      } 
      // less than 25% and haven't already reported it
      else if (level <= 25 && level > 5 && s_lastAlert != ALERT_25_PERCENT){
        if (sendAlert(c, "Relayer has no power and battery level at " + level + "%", "")){
          s_lastAlert = ALERT_25_PERCENT;
        }
      } 
      // less than 50% and haven't already reported it
      else if (level <= 50 && level > 25 && s_lastAlert != ALERT_50_PERCENT){
        if (sendAlert(c, "Relayer has no power and battery level at " + level + "%", "")){
          s_lastAlert = ALERT_50_PERCENT;
        }
      }
    } 
    // is having power a new condition, IE, did we scream about it?
    else if (s_lastAlert != ALERT_POWER_ON){
      if (sendAlert(c, "Relayer regained power, battery level at " + level + "%", "")){
        s_lastAlert = ALERT_POWER_ON;
      }
    }
  }

  /**
   * Sends an alert to our server with the passed in subject.  The body will contain
   * configuration attributes and debugging information.
   * 
   * TODO: Would be nice to echo these out to SMS if the client is configured 
   *       with an alert phone number.
   *       
   * @param subject The subject of the alert to send to the server
   */
  public static boolean sendAlert(Context context, String subject, String body){
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    String hostname = prefs.getString("router_hostname", null);
    
    Log.d(TAG, "__SENDING ALERT: " + subject);
    
    if (hostname != null && subject != null){
      // send the alert off
      HttpClient client = new DefaultHttpClient();
      client.getParams().setParameter("http.connection-manager.timeout", new Integer(60000));
      client.getParams().setParameter("http.connection.timeout", new Integer(60000));
      client.getParams().setParameter("http.socket.timeout", new Integer(60000));
      
      StringBuilder conf = new StringBuilder();
      conf.append("SMS Relay Version: " + AndroidRelay.getVersionNumber(context));
      conf.append("\n");
      conf.append("\nHostname: " + prefs.getString("router_hostname", null));
      String backend = prefs.getString("router_backend", null);
      conf.append("\nBackend:" + backend);
      conf.append("\nPassword:" + prefs.getString("router_password", null));
      conf.append("\n");
      conf.append("\nProcess Incoming:" + prefs.getBoolean("process_incoming", false));
      conf.append("\nProcess Outgoing:" + prefs.getBoolean("process_outgoing", false));
      conf.append("\nInterval:" + prefs.getString("update_interval", "null"));
      
      TextMessageHelper helper = AndroidRelay.getHelper(context);
      int total = helper.getAllMessages().size();
      int unsynced = helper.withStatus(context, TextMessage.INCOMING, TextMessage.RECEIVED).size();

      conf.append("\n");
      conf.append("\nTotal Messages:" + total);
      conf.append("\nUnsynced:" + unsynced);
      List<TextMessage> erroredOut = helper.withStatus(context, TextMessage.OUTGOING, TextMessage.ERRORED);
      conf.append("\n\nErrored Out: " + erroredOut.size());
      for (TextMessage msg : erroredOut){
        conf.append("\n" + msg.number + ": " + msg.text);
      }
      List<TextMessage> erroredIn = helper.withStatus(context, TextMessage.INCOMING, TextMessage.ERRORED);
      conf.append("\n\nErrored In: " + erroredIn.size());
      for (TextMessage msg : erroredIn){
        conf.append("\n" + msg.number + ": " + msg.text);
      }
      conf.append("\n\nLog:\n\n");
      
      // prepend our configuration to our body
      body = conf.toString() + body;
      try{
        HttpPost post = new HttpPost("http://" + hostname + "/router/alert");
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("password", "" + prefs.getString("router_password", null)));
        nameValuePairs.add(new BasicNameValuePair("subject", "[" + backend + "] " + subject));
        nameValuePairs.add(new BasicNameValuePair("body", body));
        post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
        
        Log.e(MainActivity.TAG, "Sending log to: " + post.getURI().toURL().toString());
      
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        client.execute(post, responseHandler);
        return true;
      } catch (Throwable t){
        Log.e(MainActivity.TAG, "Sending of alert failed", t);
        return false;
      }
    }
    
    return false;
  }
  
  /**
   * Toggles our connection from WIFI and vice versa.  If it does not and we are on WIFI, then 
   * we try to switch to the mobile network.
   */
  public void toggleConnection(){
        WifiManager wifi = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
      
    // well that didn't work, let's flip our connection status, that might just help.. we sleep a bit so things can connect
    boolean newWifiState = !wifi.isWifiEnabled();
    Log.d(TAG, "Toggling Connection: Connection test failed, flipping WIFI state to: " + newWifiState);
    wifi.setWifiEnabled(newWifiState);
    
    // sleep 30 seconds to give the network a chance to connect
    try{
      Thread.sleep(30000);
    } catch (Throwable tt){}
  }
  
  /***
   * This should be run only when our service starts, and takes care of resending any messages
   * that were queued but which we never got a reply for.  This could result in double sends
   * but that's better than leaving a message on the floor.
   */
  public void promoteErroredMessages(){
    TextMessageHelper helper = getHelper();
      
    List<TextMessage> msgs = helper.withStatus(this.getApplicationContext(), TextMessage.OUTGOING, TextMessage.QUEUED);
    for(TextMessage msg : msgs){
      msg.status = TextMessage.ERRORED;
      helper.updateMessage(msg);
      MainActivity.updateMessage(msg);      
    }
  }

  /***
   * Goes through all our activations, retriggering syncs for all those that need to be sent.
   */
  public void requeueErroredIncoming(){
    TextMessageHelper helper = getHelper();
    List<TextMessage> msgs = helper.withStatus(this.getApplicationContext(), TextMessage.INCOMING, TextMessage.ERRORED);
      
    int count = 0;
    for(TextMessage msg : msgs){
      msg.status = TextMessage.RECEIVED;
      helper.updateMessage(msg);
      
      MainActivity.updateMessage(msg);
      
      count++;
      if (count >= 5){
        Log.d(TAG, "Reprocessed five messages, skipping rest.");
        break;
      }
    }  
  }
  
  /**
   * Trims all but the latest 100 messages in our table.
   */
  public void trimMessages(){
    TextMessageHelper helper = getHelper();
    helper.trimMessages();
  }
  
  /***
   * Goes through all the messages which have errors and resends them.  Note that we only try to send
   * five at a time, so it could take a bit to clear out the backlog.
   */
  public void resendErroredSMS(){
    TextMessageHelper helper = getHelper();
    List<TextMessage> msgs = helper.erroredOutgoing(getApplicationContext());

    int count = 0;
    for(TextMessage msg : msgs){
      try{
        Log.d(TAG, "Sending [" + msg.id + "] - " + msg.number + " - "+ msg.text);
        modem.sendSms(msg.number, msg.text, "" + msg.id);
        msg.status = TextMessage.QUEUED;
      } catch (Throwable t){
        msg.status = TextMessage.ERRORED;
        Log.d(TAG, "Errored [" + msg.id + "] - " + msg.number + " - "+ msg.text, t);
      }
      helper.updateMessage(msg);
      MainActivity.updateMessage(msg);
      
      count++;
      if (count >= 5){
        Log.d(TAG, "Resent five messages, skipping rest.");
        break;
      }
    }
  }
  
  /**
   * Sends all our pending outgoing messages to our server.
   */
  public void sendPendingMessagesToServer() throws IOException {
    List<TextMessage> msgs = null;
    
    // first send any that haven't yet been tried
    TextMessageHelper helper = getHelper();
    msgs = helper.withStatus(this.getApplicationContext(), TextMessage.INCOMING, TextMessage.RECEIVED);
    for(TextMessage msg : msgs){
      sendMessageToServer(msg);
    }
    
    // then those that had an error when we tried to contact the server
    helper = getHelper();
    msgs = helper.withStatus(this.getApplicationContext(), TextMessage.INCOMING, TextMessage.ERRORED);
    for(TextMessage msg : msgs){
      sendMessageToServer(msg);
    }
  }
  
  public void markDeliveriesOnServer() throws IOException {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    String deliveryURL = prefs.getString("delivery_url", null);
      
    if (deliveryURL != null && deliveryURL.length() > 0){
      TextMessageHelper helper = getHelper();
      List<TextMessage> msgs = helper.withStatus(this.getApplicationContext(), TextMessage.OUTGOING, TextMessage.SENT);
      for(TextMessage msg : msgs){
        markMessageDelivered(msg);
      }
    }
  }
  
  public String fetchURL(String url) throws ClientProtocolException, IOException{
    HttpClient client = new DefaultHttpClient();
    client.getParams().setParameter("http.connection-manager.timeout", new Integer(25000));
    client.getParams().setParameter("http.connection.timeout", new Integer(25000));
    client.getParams().setParameter("http.socket.timeout", new Integer(25000));
    
    HttpGet httpget = new HttpGet(url);
    ResponseHandler<String> responseHandler = new BasicResponseHandler();
    String content = client.execute(httpget, responseHandler);
    
    return content;
  }
  
  /**
   * Sends a message to our server.
   * @param msg
   */
  public void sendMessageToServer(TextMessage msg) throws IOException {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    String receiveURL = prefs.getString("receive_url", null);
        boolean process_outgoing = prefs.getBoolean("process_outgoing", false);

    TextMessageHelper helper = getHelper();
    
    Log.d(TAG, "Receive URL: " + receiveURL);
    
    // no delivery url means we don't do anything
    if (receiveURL == null || receiveURL.length() == 0){
      return;
    }
    
    String url = receiveURL + "&sender=" + URLEncoder.encode(msg.number) + "&message=" + URLEncoder.encode(msg.text);      
    Log.d(TAG, "Sending: "+ url);
    
    try {
      String content = fetchURL(url);
      
      if (content.trim().length() > 0){
        JSONObject json = new JSONObject(content);
        
        // if we are supposed to process outgoing messages, then read any responses
        if (process_outgoing){
          JSONArray responses = json.getJSONArray("responses");
          for (int i=0; i<responses.length(); i++) {
            JSONObject response = responses.getJSONObject(i);
            String number = "+" + response.getString("contact");
            String message = response.getString("text");          
            long serverId = response.getLong("id");

            if ("O".equals(response.getString("direction"))  && "Q".equals(response.getString("status"))) {          
              // if this message doesn't already exist
              TextMessage existing = helper.withServerId(this.getApplicationContext(), serverId);
              if (existing == null){
                Log.d(TAG, "Got reply: " + serverId + ": " + message);
                TextMessage toSend = new TextMessage(number, message, serverId);
                helper.createMessage(toSend);
                sendMessage(toSend);
              }
            }
          }
        }
      }
      msg.status = TextMessage.HANDLED;
      msg.error = null;
      Log.d(TAG, "Msg '" + msg.text + "' handed to server.");
    } catch (HttpResponseException e){
      Log.d(TAG, "HTTP ERROR Got Error: "+ e.getMessage(), e);
      msg.error = e.getClass().getSimpleName() + ": " + e.getMessage();
      msg.status = TextMessage.ERRORED;      
    } catch (IOException e){
      msg.error = e.getClass().getSimpleName() + ": " + e.getMessage();
      msg.status = TextMessage.ERRORED;
      throw e;
    } catch (Throwable t) {
      Log.d(TAG, "THROWABLE Got Error: "+ t.getMessage(), t);
      msg.error = t.getClass().getSimpleName() + ": " + t.getMessage();
      msg.status = TextMessage.ERRORED;
    } finally {     
      helper.updateMessage(msg);
      MainActivity.updateMessage(msg);
    }
  }
  
  public void markMessageDelivered(TextMessage msg) throws IOException {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    String deliveryURL = prefs.getString("delivery_url", null);
    TextMessageHelper helper = getHelper();    
    
    Log.d(TAG, "Delivery URL: " + deliveryURL);
    
    // no delivery url means we don't do anything
    if (deliveryURL == null || deliveryURL.length() == 0){
      return;
    }
    
    if (msg.serverId <= 0){
      msg.status = TextMessage.DONE;
      msg.error = "Ignored due to 0 id";
    } else {
      String url = deliveryURL + "&message_id=" + msg.serverId;
      Log.d(TAG, "Sending: "+ url);
    
      try {
        fetchURL(url);
        msg.status = TextMessage.DONE;
        msg.error = null;
        Log.d(TAG, "Msg " + msg.serverId + " marked as delivered.");
      } catch (IOException e){
        msg.status = TextMessage.SENT;
        msg.error = e.getClass().getSimpleName() + ": " + e.getMessage();
        throw e;
      } catch (Throwable t) {
        Log.d(TAG, "Got Error: "+ t.getMessage(), t);
        msg.status = TextMessage.SENT;
        msg.error = t.getClass().getSimpleName() + ": " + t.getMessage();
      } finally {
        helper.updateMessage(msg);
        MainActivity.updateMessage(msg);
      }
    }
  }
  
  /**
   * Sends a message to our server.
   * @param msg
   */
  public void checkOutbox() throws IOException {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    String updateInterval = prefs.getString("update_interval", "30000");
    long interval = Long.parseLong(updateInterval);

    String outboxURL = prefs.getString("outbox_url", null);
    TextMessageHelper helper = getHelper();    
    
    // no delivery url means we don't do anything
    if (outboxURL == null || outboxURL.length() == 0){
      return;
    }
    
    // if our update interval is set to 0, then that means we shouldn't be checking, so skip
    if (interval == 0){
      return;
    }
    
    Log.d(TAG, "Outbox URL: " + outboxURL);
    
    try {
      String content = fetchURL(outboxURL);
      
      if (content.trim().length() > 0){
        JSONObject json = new JSONObject(content);
        JSONArray responses = json.getJSONArray("outbox");
        for (int i=0; i<responses.length(); i++) {
          JSONObject response = responses.getJSONObject(i);    
          if ("O".equals(response.getString("direction")) && "Q".equals(response.getString("status"))) {
            String number = "+" + response.getString("contact");
            String message = response.getString("text");
            long serverId = response.getLong("id");
            
            // if this message doesn't already exist
            TextMessage existing = helper.withServerId(this.getApplicationContext(), serverId);
            if (existing == null){
              Log.d(TAG, "New outgoing msg: " + serverId + ": " + message);
              TextMessage toSend = new TextMessage(number, message, serverId);
              helper.createMessage(toSend);
              sendMessage(toSend);
            } else {
              if (existing.status == TextMessage.DONE){
                existing.status = TextMessage.SENT;
                helper.updateMessage(existing);
              }
              Log.d(TAG, "Ignoring message: " + serverId + " already queued.");
            }
          }
        }
      }
      Log.d(TAG, "Outbox fetched from server");
    } catch (HttpResponseException e){
      Log.d(TAG, "Got Error: "+ e.getMessage(), e);
    } catch (IOException e){
      throw e;
    } catch (Throwable t) {
      Log.d(TAG, "Got Error: "+ t.getMessage(), t);
    }        
  }

  // triggers our background service to go do things
  public void kickService(){
    WakefulIntentService.sendWakefulWork(this, CheckService.class);
  }

  public void sendMessage(TextMessage msg){
    Log.d(TAG, "=== SMS OUT: " + msg.number + ": " + msg.text);    
    try {
      modem.sendSms(msg.number, msg.text, "" + msg.id);
    } catch (Exception e){
      msg.status = TextMessage.ERRORED;
    }
    MainActivity.updateMessage(msg);
  }

  public void onNewSMS(String number, String message) {
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    boolean process_messages = prefs.getBoolean("process_incoming", false);

    TextMessageHelper helper = getHelper();
    String keyword = prefs.getString("relay_password", "nyaruka").toLowerCase();

    // if we aren't supposed to process messages, ignore this message
    if (!process_messages){
      return;
    }
    
    // if someone sends 'keyword log' then send a log to the server
    if (message.equalsIgnoreCase(keyword + " log")){
      RelayService.doSendLog = true;
            
      int unsynced = helper.withStatus(getApplicationContext(), TextMessage.INCOMING, TextMessage.RECEIVED).size();
      int erroredOut = helper.withStatus(getApplicationContext(), TextMessage.OUTGOING, TextMessage.ERRORED).size();
      int erroredIn = helper.withStatus(getApplicationContext(), TextMessage.INCOMING, TextMessage.ERRORED).size();
      
      modem.sendSms(number, "Log being sent. " + unsynced + " unsynced.  " + erroredOut + " out errors.  " + erroredIn + " in errors.", "-1");
            return;
    }

    if(message.equalsIgnoreCase(keyword + " reset")){
      // change the label to true
      doReset = true;
      Log.d(TAG, "The reset process is set to " + Boolean.toString(doReset));
      
      // start the check service for reset changes to take effect
      kickService();
    
      modem.sendSms(number, "Reset process has been started. ", "-1");      
      return;
    }

    if(message.equalsIgnoreCase(keyword + " clear")){
      Log.d(TAG, "Clearing all messages");
      AndroidRelay.clearMessages(RelayService.this);
            Toast.makeText(RelayService.this, "Messages cleared", Toast.LENGTH_LONG).show();
            
            modem.sendSms(number, "All messages have been removed.", "-1");      
      return;
    }
    
    {
      SharedPreferences.Editor editor = prefs.edit();

      // process message with 'keyword data and change the network connection to specified mode
      if(message.equalsIgnoreCase(keyword + " data")) {
        Log.d(TAG, "Switching to data connection");

        editor.putString("pref_net", "1");
        editor.commit();

        modem.sendSms(number, "Your preferred network is now set to 'MOBILE DATA'", "-1");      
        return;
      }
    
      // process message with 'keyword wifi and change the network connection to specified mode
      if(message.equalsIgnoreCase(keyword + " wifi")) {
        Log.d(TAG, "Switching to wifi connection");
      
        editor.putString("pref_net", "0");
        editor.commit();

        modem.sendSms(number, "Your preferred network is now set to 'WIFI'", "-1");
        return;
      }
    }


    TextMessage msg = null;

    msg = new TextMessage();
    msg.number = number;
    msg.text = message;
    msg.created = new Date();
    msg.direction = TextMessage.INCOMING;
    msg.status = TextMessage.RECEIVED;
    helper.createMessage(msg);
  
    Log.d(TAG, "=== SMS IN:" + msg.number + ": " + msg.text);
    MainActivity.updateMessage(msg);
    
    kickService();
  }  
  
  public void onSMSSendError(String token, String errorDetails) {
    TextMessage msg = null;
    TextMessageHelper helper = getHelper();    
    
    msg = helper.withId(Long.parseLong(token));
    
    if (msg != null){
      msg.status = TextMessage.ERRORED;
      msg.error = "SMS send error";
      helper.updateMessage(msg);
    
      Log.d(TAG, "=== SMS ERROR:" + token + " Details: " + errorDetails);
      MainActivity.updateMessage(msg);
    }
  }

  public void onSMSSent(String token) {
    TextMessage msg = null;
    TextMessageHelper helper = getHelper();    
    
    msg = helper.withId(Long.parseLong(token));
    
    if (msg != null){
      msg.status = TextMessage.SENT;
      msg.error = "";
      helper.updateMessage(msg);
    
      Log.d(TAG, "=== SMS SENT: " + token);
      MainActivity.updateMessage(msg);
      kickService();
    }
  }
  
  public SMSModem modem;
}




Java Source Code List

com.commonsware.cwac.wakeful.AlarmReceiver.java
com.commonsware.cwac.wakeful.WakefulIntentService.java
com.nyaruka.android.actionbarcompat.ActionBarActivity.java
com.nyaruka.android.actionbarcompat.ActionBarHelperBase.java
com.nyaruka.android.actionbarcompat.ActionBarHelperHoneycomb.java
com.nyaruka.android.actionbarcompat.ActionBarHelperICS.java
com.nyaruka.android.actionbarcompat.ActionBarHelper.java
com.nyaruka.android.actionbarcompat.SimpleMenuItem.java
com.nyaruka.android.actionbarcompat.SimpleMenu.java
com.nyaruka.androidrelay.AlarmListener.java
com.nyaruka.androidrelay.AndroidRelay.java
com.nyaruka.androidrelay.BootStrapper.java
com.nyaruka.androidrelay.CheckService.java
com.nyaruka.androidrelay.MainActivity.java
com.nyaruka.androidrelay.MessageListFragment.java
com.nyaruka.androidrelay.RebootService.java
com.nyaruka.androidrelay.RelayService.java
com.nyaruka.androidrelay.SMSModem.java
com.nyaruka.androidrelay.SettingsActivity.java
com.nyaruka.androidrelay.data.TextMessageHelper.java
com.nyaruka.androidrelay.data.TextMessage.java
com.nyaruka.log.LogCollector.java