/*
* RapidPro Android Channel - Relay SMS messages where MNO connections aren't practical.
* Copyright (C) 2014 Nyaruka, UNICEF
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.rapidpro.androidchannel;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.preference.PreferenceManager;
import io.rapidpro.androidchannel.data.DBCommandHelper;
import io.rapidpro.androidchannel.payload.MOTextMessage;
import java.util.Date;
/**
* Observers the Incoming SMS to relay them to the server as they are received
*/
public class IncomingSMSObserver extends ContentObserver{
// the time of the last SMS we've seen
private long m_lastSMS = System.currentTimeMillis();
public IncomingSMSObserver(){
super(null);
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(RapidPro.get().getApplicationContext());
// If we are paused or unclaimed, just update our last SMS seen so we don't process these later
if (RapidPro.get().isPaused() || !RapidPro.get().isClaimed()){
m_lastSMS = System.currentTimeMillis();
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(RapidPro.get().getApplicationContext()).edit();
editor.putLong(SettingsActivity.LAST_SMS_RECEIVED, m_lastSMS);
editor.commit();
return;
}
Uri inboxUri = Uri.parse("content://sms/inbox");
// get any new SMS in the inbox
Cursor cursor = RapidPro.get().getContentResolver().query(inboxUri, null, null, null, "date DESC");
// whether we need to sync
boolean doSync = false;
long newLastSMS = m_lastSMS;
// when did we last receive a message?
m_lastSMS = prefs.getLong(SettingsActivity.LAST_SMS_RECEIVED, m_lastSMS);
boolean deleteSMSAllowed = prefs.getBoolean(SettingsActivity.SMS_AUTO_DELETE, false);
// While there are records to look at
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndex("_id"));
long time = cursor.getLong(cursor.getColumnIndex("date"));
// update our most recent message if needbe
if (time > newLastSMS){
newLastSMS = time;
}
// if we have seen this message, break out
if (time <= m_lastSMS){
break;
}
String address = cursor.getString(cursor.getColumnIndex("address"));
String message = cursor.getString(cursor.getColumnIndex("body"));
RapidPro.LOG.d("SMS[" + id + "] Arrived: " + time + " From: " + address + " message body: " + message + " (last seen " + m_lastSMS + ")");
DBCommandHelper.queueCommand(RapidPro.get(), new MOTextMessage(address, message, new Date(time)));
doSync = true;
if (deleteSMSAllowed) {
RapidPro.LOG.d("DELETE SMS: at " + id + " message: " + message);
RapidPro.get().getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);
}
}
// trigger a sync if we need it
if (doSync){
m_lastSMS = newLastSMS;
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(RapidPro.get().getApplicationContext()).edit();
editor.putLong(SettingsActivity.LAST_SMS_RECEIVED, m_lastSMS);
editor.commit();
RapidPro.get().refreshHome();
RapidPro.broadcastUpdatedCounts(RapidPro.get().getApplicationContext());
RapidPro.get().sync(true);
}
}
}