package com.commonsensenet.realfarm.sync;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;
import com.buzzbox.mob.android.scheduler.Task;
import com.buzzbox.mob.android.scheduler.TaskResult;
import com.commonsensenet.realfarm.dataaccess.RealFarmProvider;
import com.commonsensenet.realfarm.model.Action;
import com.commonsensenet.realfarm.model.Model;
import com.commonsensenet.realfarm.model.Plot;
import com.commonsensenet.realfarm.model.User;
import com.commonsensenet.realfarm.utils.ApplicationTracker;
import com.commonsensenet.realfarm.utils.ApplicationTracker.EventType;
/**
* Recurring Task that implements your business logic. The BuzzBox SDK Scheduler
* will take care of running the doWork method according to the scheduling.
*
*/
public class UpstreamTask implements Task {
/** Identifies when an SMS has been delivered. */
private static final String DELIVERED = "SMS_DELIVERED";
/** Receiver used to detect if an SMS was delivered correctly. */
private static BroadcastReceiver sDeliveredBroadcastReceiver;
/** Identifies when an SMS has been sent. */
private static final String SENT = "SMS_SENT";
/** Phone number of the server. */
public static final String SERVER_PHONE_NUMBER = "9742016861";
/** Receiver used to detect if an SMS was sent correctly. */
private static BroadcastReceiver sSendBroadcastReceiver;
/** List of Actions obtained from the Database. */
private List<Action> mActionList;
/** Access to the underlying database. */
private RealFarmProvider mDataProvider;
/** List of messages to send to the server. */
private List<Model> mMessageList;
/** List of Plots obtained from the Database. */
private List<Plot> mPlotList;
/** List of Users obtained from the Database. */
private List<User> mUserList;
/** Time in hours when a resend will be attempted. */
public static final int RESEND_TIME_IN_HOURS = 6;
public TaskResult doWork(ContextWrapper ctx) {
TaskResult res = new TaskResult();
// adds the Broadcast receivers if needed.
registerReceivers(ctx.getApplicationContext());
// gets the database provider.
mDataProvider = RealFarmProvider.getInstance(ctx);
// Sends first the long time waiting messages.
mActionList = mDataProvider.getActionsBySendStatus(Model.STATUS_SENT);
mPlotList = mDataProvider.getPlotsBySendStatus(Model.STATUS_SENT);
mUserList = mDataProvider.getUsersBySendStatus(Model.STATUS_SENT);
// initializes the list used to send the messages.
mMessageList = new ArrayList<Model>();
// gets the current date and subtracts RESEND_TIME_IN_HOURS hours.
Calendar now = GregorianCalendar.getInstance();
now.add(Calendar.HOUR, -RESEND_TIME_IN_HOURS);
Date date;
// checks all the actions that are older.
for (int x = 0; x < mActionList.size(); x++) {
// gets the current date of the action.
date = new Date(mActionList.get(x).getTimestamp());
// adds the action to the list to send.
if (date.before(now.getTime())) {
// tracks the re-sending
ApplicationTracker.getInstance().logSyncEvent(EventType.SYNC,
"RESEND", mActionList.get(x).toString());
mMessageList.add(mActionList.get(x));
}
}
// checks all the plots that are older.
for (int x = 0; x < mPlotList.size(); x++) {
// gets the current date of the action.
date = new Date(mPlotList.get(x).getTimestamp());
// adds the action to the list to send.
if (date.before(now.getTime())) {
// tracks the re-sending
ApplicationTracker.getInstance().logSyncEvent(EventType.SYNC,
"RESEND", mPlotList.get(x).toString());
mMessageList.add(mPlotList.get(x));
}
}
// checks all the users that are older.
for (int x = 0; x < mUserList.size(); x++) {
// gets the current date of the action.
date = new Date(mUserList.get(x).getTimestamp());
// adds the action to the list to send.
if (date.before(now.getTime())) {
// tracks the re-sending
ApplicationTracker.getInstance().logSyncEvent(EventType.SYNC,
"RESEND", mUserList.get(x).toString());
mMessageList.add(mUserList.get(x));
}
}
// gets all the data from the server that has not being sent.
mActionList = mDataProvider.getActionsBySendStatus(Model.STATUS_UNSENT);
mPlotList = mDataProvider.getPlotsBySendStatus(Model.STATUS_UNSENT);
mUserList = mDataProvider.getUsersBySendStatus(Model.STATUS_UNSENT);
// adds all the elements into the message list.
mMessageList.addAll(mUserList);
mMessageList.addAll(mPlotList);
mMessageList.addAll(mActionList);
// sends all the messages to the server via SMS.
for (int i = 0; i < mMessageList.size(); i++) {
// sends the message.
sendMessage(ctx, mMessageList.get(i));
}
// sets the flag for the sent actions.
for (int x = 0; x < mActionList.size(); x++) {
mDataProvider.setActionStatus(mActionList.get(x).getId(),
Model.STATUS_SENT);
}
// sets the flag for the sent plots.
for (int x = 0; x < mPlotList.size(); x++) {
mDataProvider.setPlotStatus(mPlotList.get(x).getId(),
Model.STATUS_SENT);
}
// sets the flag for the sent users.
for (int x = 0; x < mUserList.size(); x++) {
mDataProvider.setUserStatus(mUserList.get(x).getId(),
Model.STATUS_SENT);
}
return res;
}
public String getId() {
return "reminder";
}
public String getTitle() {
return "Reminder";
}
public void registerReceivers(Context context) {
if (sSendBroadcastReceiver == null) {
sSendBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
// gets the extras from the Bundle.
Bundle extras = arg1.getExtras();
long id = -1;
int type = -1;
// obtains the values from the bundle.
if (extras != null) {
id = extras.getLong("id");
type = extras.getInt("type");
}
String resultMessage;
switch (getResultCode()) {
case Activity.RESULT_OK:
resultMessage = "SMS sent";
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
resultMessage = "Generic Failure";
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
resultMessage = "No Service";
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
resultMessage = "Null PDU";
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
resultMessage = "Radio Off";
break;
default:
resultMessage = "Error";
break;
}
// tracks the send notification.
ApplicationTracker.getInstance().logSyncEvent(
EventType.SYNC, "SEND-" + resultMessage,
"type:" + type + ", id:" + id);
}
};
// registers the send receiver.
context.registerReceiver(sSendBroadcastReceiver, new IntentFilter(
SENT));
}
if (sDeliveredBroadcastReceiver == null) {
sDeliveredBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context arg0, Intent arg1) {
// gets the extras from the Bundle.
Bundle extras = arg1.getExtras();
long id = -1;
int type = -1;
// obtains the values from the bundle.
if (extras != null) {
id = extras.getLong("id");
type = extras.getInt("type");
}
// checks the obtained code.
switch (getResultCode()) {
case Activity.RESULT_OK:
// marks the message as delivered.
updateStatus(type, id, Model.STATUS_CONFIRMED);
break;
case Activity.RESULT_CANCELED:
break;
}
// tracks the sync activity.
ApplicationTracker.getInstance().logSyncEvent(
EventType.SYNC, "DELIVERY",
"type:" + type + ", id:" + id);
}
};
// registers the delivered receiver.
context.registerReceiver(sDeliveredBroadcastReceiver,
new IntentFilter(DELIVERED));
}
}
protected void sendMessage(ContextWrapper context, Model message) {
Intent sentIntent = new Intent(SENT);
sentIntent.putExtra("type", message.getModelTypeId());
sentIntent.putExtra("id", message.getId());
PendingIntent sentPI = PendingIntent.getBroadcast(
context.getApplicationContext(), 0, sentIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Intent deliveredIntent = new Intent(DELIVERED);
deliveredIntent.putExtra("type", message.getModelTypeId());
deliveredIntent.putExtra("id", message.getId());
PendingIntent deliveredPI = PendingIntent.getBroadcast(
context.getApplicationContext(), 0, deliveredIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
// gets the data to send.
String sms = message.toSmsString();
// tracks that the data that has been sent to the Server.
ApplicationTracker.getInstance().logSyncEvent(EventType.SYNC,
"UPSTREAM", sms);
// gets the manager in charge of sending SMS.
SmsManager sm = SmsManager.getDefault();
// sends the messages from the phone number
sm.sendTextMessage(SERVER_PHONE_NUMBER, null, sms, sentPI, deliveredPI);
}
/**
* Updates the status of the entry in the database that matches the given
* type and id with the new status.
*
* @param type
* type of the Model to update.
* @param id
* id of the Model to update.
* @param status
* new status. It can be 0 (unsent), 1(sent) or 2(confirmed).
*/
private void updateStatus(int type, long id, int status) {
switch (type) {
case 1000: // Action
// changes the status of the action
mDataProvider.setActionStatus(id, status);
break;
case 1001: // Plot
// changes the status of the plot
mDataProvider.setPlotStatus(id, status);
break;
case 1002: // User
// changes the status of the user.
mDataProvider.setUserStatus(id, status);
break;
}
}
}