diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 96900c5..d05117e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/java/eu/droogers/smsmatrix/DatabaseContract.java b/app/src/main/java/eu/droogers/smsmatrix/DatabaseContract.java
new file mode 100644
index 0000000..5f4fcfb
--- /dev/null
+++ b/app/src/main/java/eu/droogers/smsmatrix/DatabaseContract.java
@@ -0,0 +1,75 @@
+package eu.droogers.smsmatrix;
+
+import android.provider.BaseColumns;
+
+public class DatabaseContract {
+
+ private DatabaseContract () {}
+
+ public static final class SmsEntry implements BaseColumns {
+ public static final String TABLE_NAME = "sms";
+ public static final String COLUMN_TYPE = "type";
+ //matrix -> cell=1 ; cell -> matrix = 2
+ public static final String COLUMN_SOURCE_EPOCH = "source_epoch";
+ //epoch in ms from sending party
+ public static final String COLUMN_RECIEVED_EPOCH = "received_epoch";
+ //epoch in ms when the device on onRecieve
+ public static final String COLUMN_NUMBER = "number";
+ //Who the message is from
+ public static final String COLUMN_MESSAGE = "message";
+ //Body of the message
+ public static final String COLUMN_BRIDGED = "bridged";
+ //Was it sent successfully?
+ public static final String COLUMN_LOCK = "lock";
+ //Are we doing something with this message?
+ public static final String COLUMN_ERROR = "error";
+ //Was there an error doing something?
+
+ public static final String SQL_CREATE_TABLE =
+ "CREATE TABLE " + TABLE_NAME + " (" +
+ _ID + " INTEGER PRIMARY KEY, " +
+ COLUMN_TYPE + " INTEGER NOT NULL, " +
+ COLUMN_SOURCE_EPOCH + " INTEGER, " +
+ COLUMN_RECIEVED_EPOCH + " INTEGER NOT NULL, " +
+ COLUMN_NUMBER + " TEXT NOT NULL, " +
+ COLUMN_MESSAGE + " TEXT NOT NULL, " +
+ COLUMN_BRIDGED + " INTEGER NOT NULL, " +
+ COLUMN_LOCK + " INTEGER NOT NULL, " +
+ COLUMN_ERROR + " INTEGER NOT NULL )";
+
+ }
+
+ public static final class MmsEntry implements BaseColumns {
+ public static final String TABLE_NAME = "mms";
+ public static final String COLUMN_TYPE = "type";
+ //matrix -> cell=1 ; cell -> matrix = 2
+ public static final String COLUMN_SOURCE_EPOCH = "source_epoch";
+ //epoch in ms from sending party
+ public static final String COLUMN_RECIEVED_EPOCH = "received_epoch";
+ //epoch in ms when the device on onRecieve
+ public static final String COLUMN_NUMBER = "number";
+ //Who the message is from
+ public static final String COLUMN_MMS_ID = "mms_id";
+ //ID of mmssms.db - addr
+ public static final String COLUMN_BRIDGED = "bridged";
+ //Was it sent successfully?
+ public static final String COLUMN_LOCK = "lock";
+ //Are we doing something with this message?
+ public static final String COLUMN_ERROR = "error";
+ //Was there an error doing something?
+
+
+ public static final String SQL_CREATE_TABLE =
+ "CREATE TABLE " + TABLE_NAME + " (" +
+ _ID + " INTEGER PRIMARY KEY, " +
+ COLUMN_TYPE + " INTEGER NOT NULL, " +
+ COLUMN_SOURCE_EPOCH + " INTEGER, " +
+ COLUMN_RECIEVED_EPOCH + " INTEGER NOT NULL, " +
+ COLUMN_NUMBER + " TEXT NOT NULL, " +
+ COLUMN_MMS_ID + " INTEGER UNIQUE NOT NULL, " +
+ COLUMN_BRIDGED + " INTEGER NOT NULL, " +
+ COLUMN_LOCK + " INTEGER, " +
+ COLUMN_ERROR + " INTEGER )";
+ }
+
+}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/MMSMonitor.java b/app/src/main/java/eu/droogers/smsmatrix/MMSMonitor.java
deleted file mode 100644
index 76c9764..0000000
--- a/app/src/main/java/eu/droogers/smsmatrix/MMSMonitor.java
+++ /dev/null
@@ -1,302 +0,0 @@
-package eu.droogers.smsmatrix;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Telephony;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-public class MMSMonitor {
- private MatrixService mainActivity;
- private ContentResolver contentResolver = null;
- private Context mainContext;
- private Handler mmshandler = null;
- private ContentObserver mmsObserver = null;
- public boolean monitorStatus = false;
- private int mmsCount = 0;
- private static final String TAG = "MMSMonitor";
-
- public MMSMonitor(final MatrixService mainActivity, final Context mainContext) {
- this.mainActivity = mainActivity;
- contentResolver = mainActivity.getContentResolver();
- this.mainContext = mainContext;
- mmshandler = new MMSHandler();
- mmsObserver = new MMSObserver(mmshandler);
- Log.i(TAG, "***** Start MMS Monitor *****");
- }
-
-
- public void startMMSMonitoring() {
- try {
- monitorStatus = false;
- if (!monitorStatus) {
- contentResolver.registerContentObserver(
- Uri.parse("content://mms"),
- true,
- mmsObserver
- );
-
- // Save the count of MMS messages on start-up.
- Uri uriMMSURI = Uri.parse("content://mms-sms");
- Cursor mmsCur = mainActivity.getContentResolver().query(
- uriMMSURI,
- null,
- Telephony.Mms.MESSAGE_BOX + " = " + Telephony.Mms.MESSAGE_BOX_INBOX,
- null,
- Telephony.Mms._ID
- );
- if (mmsCur != null && mmsCur.getCount() > 0) {
- mmsCount = mmsCur.getCount();
- Log.d(TAG, "Init MMSCount = " + mmsCount);
- }
- }
- } catch (Exception e) {
- Log.e(TAG, e.getMessage());
- }
- }
-
-
- public void stopMMSMonitoring() {
- try {
- monitorStatus = false;
- if (!monitorStatus){
- contentResolver.unregisterContentObserver(mmsObserver);
- }
- } catch (Exception e) {
- Log.e(TAG, e.getMessage());
- }
- }
-
-
- class MMSHandler extends Handler {
- public void handleMessage(final Message msg) {
- //Log.i(TAG, "Handler");
- }
- }
-
-
- class MMSObserver extends ContentObserver {
- private Handler mms_handle = null;
- public MMSObserver(final Handler mmshandle) {
- super(mmshandle);
- mms_handle = mmshandle;
- }
-
- public void onChange(final boolean bSelfChange) {
- super.onChange(bSelfChange);
- Log.i(TAG, "Onchange");
-
- try {
- monitorStatus = true;
-
- // Send message to Activity.
- Message msg = new Message();
- mms_handle.sendMessage(msg);
-
- // Get the MMS count.
- Uri uriMMSURI = Uri.parse("content://mms/");
- Cursor mmsCur = mainActivity.getContentResolver().query(
- uriMMSURI,
- null,
- Telephony.Mms.MESSAGE_BOX + " = " + Telephony.Mms.MESSAGE_BOX_INBOX,
- null,
- Telephony.Mms._ID
- );
-
- int currMMSCount = 0;
- if (mmsCur != null && mmsCur.getCount() > 0) {
- currMMSCount = mmsCur.getCount();
- }
-
- // Proceed if there is a new message.
- if (currMMSCount > mmsCount) {
- mmsCount = currMMSCount;
- mmsCur.moveToLast();
-
- // Get the message id and subject.
- String subject = mmsCur.getString(mmsCur.getColumnIndex(Telephony.Mms.SUBJECT));
- int id = Integer.parseInt(mmsCur.getString(mmsCur.getColumnIndex(Telephony.Mms._ID)));
- Log.d(TAG, "_id = " + id);
- Log.d(TAG, "Subject = " + subject);
-
- byte[] mediaData = null;
- String message = "";
- String address = "";
- String fileName = "";
- String fileType = "";
- String messageType = "";
-
- // Get parts.
- Uri uriMMSPart = Uri.parse("content://mms/part");
- Cursor curPart = mainActivity.getContentResolver().query(
- uriMMSPart,
- null,
- Telephony.Mms.Part.MSG_ID + " = " + id,
- null,
- Telephony.Mms.Part._ID
- );
- Log.d(TAG, "Parts records length = " + curPart.getCount());
- curPart.moveToLast();
- do {
- String contentType = curPart.getString(curPart.getColumnIndex(Telephony.Mms.Part.CONTENT_TYPE));
- String partId = curPart.getString(curPart.getColumnIndex(Telephony.Mms.Part._ID));
- fileName = curPart.getString(curPart.getColumnIndex(Telephony.Mms.Part.NAME));
- Log.d(TAG, "partId = " + partId);
- Log.d(TAG, "Part mime type = " + contentType);
-
- if (contentType.equalsIgnoreCase("text/plain"))
- {
- // Get the message.
-
- Log.i(TAG,"==== Get the message start ====");
- messageType = Matrix.MESSAGE_TYPE_TEXT;
- byte[] messageData = readMMSPart(partId);
- if (messageData != null && messageData.length > 0) {
- message = new String(messageData);
- }
-
- if (message.isEmpty()) {
- Cursor curPart1 = mainActivity.getContentResolver().query(
- uriMMSPart,
- null,
- Telephony.Mms.Part.MSG_ID + " = " + id + " and "+ Telephony.Mms.Part._ID + " = " + partId,
- null,
- Telephony.Mms.Part._ID
- );
- for (int i = 0; i < curPart1.getColumnCount(); i++)
- {
- Log.d(TAG,"Column Name : " + curPart1.getColumnName(i));
- }
- curPart1.moveToLast();
- message = curPart1.getString(13);
- }
- Log.d(TAG,"Txt Message = " + message);
- } else if (isImageType(contentType) || isVideoType(contentType)) {
- // Get the media.
-
- if (isImageType(contentType)) {
- messageType = Matrix.MESSAGE_TYPE_IMAGE;
- } else if (isVideoType(contentType)) {
- messageType = Matrix.MESSAGE_TYPE_VIDEO;
- }
- Log.i(TAG, "==== Get the media start ====");
- fileType = contentType;
- mediaData = readMMSPart(partId);
- Log.i(TAG, "Media data length == " + mediaData.length);
- }
- } while (curPart.moveToPrevious());
-
-
-
- // Get the sender's address.
- Uri uriMMSAddr = Uri.parse("content://mms/" + id + "/addr");
- Cursor addrCur = mainActivity.getContentResolver().query(
- uriMMSAddr,
- null,
- Telephony.Mms.Addr.TYPE + " = 137", // PduHeaders.FROM
- null,
- Telephony.Mms.Addr._ID
- );
- if (addrCur != null) {
- addrCur.moveToLast();
- do{
- Log.d(TAG, "addrCur records length = " + addrCur.getCount());
- if (addrCur.getCount() > 0) {
- address = addrCur.getString(addrCur.getColumnIndex(Telephony.Mms.Addr.ADDRESS));
- }
- Log.d(TAG, "address = " + address);
-
- if (!message.isEmpty()) {
- Utilities.sendMatrix(mainActivity, message, address, messageType);
- }
- if (mediaData != null) {
- Utilities.sendMatrix(
- mainActivity,
- mediaData,
- address,
- messageType,
- fileName,
- fileType
- );
- }
- } while (addrCur.moveToPrevious());
- }
- }
-
- } catch (Exception e) {
- Log.e(TAG, e.getMessage());
- }
- }
- }
-
-
- private byte[] readMMSPart(String partId) {
- byte[] partData = null;
- Uri partURI = Uri.parse("content://mms/part/" + partId);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- InputStream is = null;
-
- try {
-
- Log.i(TAG,"Entered into readMMSPart try.");
- ContentResolver mContentResolver = mainActivity.getContentResolver();
- is = mContentResolver.openInputStream(partURI);
-
- byte[] buffer = new byte[256];
- int len = is.read(buffer);
- while (len >= 0) {
- baos.write(buffer, 0, len);
- len = is.read(buffer);
- }
- partData = baos.toByteArray();
- //Log.i(TAG, "Text Msg :: " + new String(partData));
-
- } catch (IOException e) {
- Log.e(TAG, "Exception == Failed to load part data");
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- Log.e(TAG, "Exception :: Failed to close stream");
- }
- }
- }
- return partData;
- }
-
-
- private boolean isImageType(String mime) {
- boolean result = false;
- if (mime.equalsIgnoreCase("image/jpg")
- || mime.equalsIgnoreCase("image/jpeg")
- || mime.equalsIgnoreCase("image/png")
- || mime.equalsIgnoreCase("image/gif")
- || mime.equalsIgnoreCase("image/bmp")) {
- result = true;
- }
- return result;
- }
-
-
- private boolean isVideoType(String mime) {
- boolean result = false;
- if (mime.equalsIgnoreCase("video/3gpp")
- || mime.equalsIgnoreCase("video/3gpp2")
- || mime.equalsIgnoreCase("video/avi")
- || mime.equalsIgnoreCase("video/mp4")
- || mime.equalsIgnoreCase("video/mpeg")
- || mime.equalsIgnoreCase("video/webm")) {
- result = true;
- }
- return result;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/eu/droogers/smsmatrix/MainActivity.java b/app/src/main/java/eu/droogers/smsmatrix/MainActivity.java
index 8c2334e..0c922ee 100644
--- a/app/src/main/java/eu/droogers/smsmatrix/MainActivity.java
+++ b/app/src/main/java/eu/droogers/smsmatrix/MainActivity.java
@@ -19,6 +19,7 @@ import static android.Manifest.permission.READ_CONTACTS;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_SMS;
+import static android.Manifest.permission.RECEIVE_MMS;
import static android.Manifest.permission.RECEIVE_SMS;
import static android.Manifest.permission.SEND_SMS;
import static android.content.ContentValues.TAG;
@@ -34,7 +35,7 @@ public class MainActivity extends Activity {
private EditText syncDelay;
private EditText syncTimeout;
private static final String[] PERMISSIONS_REQUIRED = new String[]{
- READ_SMS, SEND_SMS, RECEIVE_SMS, READ_PHONE_STATE, READ_CONTACTS, READ_EXTERNAL_STORAGE
+ READ_SMS, SEND_SMS, RECEIVE_SMS, READ_PHONE_STATE, READ_CONTACTS, READ_EXTERNAL_STORAGE, RECEIVE_MMS
};
private static final int PERMISSION_REQUEST_CODE = 200;
@@ -79,7 +80,12 @@ public class MainActivity extends Activity {
editor.apply();
Log.e(TAG, "onClick: " + botUsername.getText().toString() );
- startService();
+ Intent matrixService = new Intent(getApplicationContext(), eu.droogers.smsmatrix.MatrixService.class);
+ startService(matrixService);
+
+ Intent mmsIntent = new Intent(getApplicationContext(), eu.droogers.smsmatrix.MmsService.class);
+ mmsIntent.putExtra("startButton", true);
+ startService(mmsIntent);
}
}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/MatrixService.java b/app/src/main/java/eu/droogers/smsmatrix/MatrixService.java
index 9fbd89a..da7ae3e 100644
--- a/app/src/main/java/eu/droogers/smsmatrix/MatrixService.java
+++ b/app/src/main/java/eu/droogers/smsmatrix/MatrixService.java
@@ -23,7 +23,6 @@ public class MatrixService extends Service {
private String hsUrl;
private String syncDelay;
private String syncTimeout;
- private MMSMonitor mms;
@Override
public void onCreate() {
@@ -67,10 +66,7 @@ public class MatrixService extends Service {
}
}
- if (this.mms == null) {
- this.mms = new MMSMonitor(this , getApplicationContext());
- this.mms.startMMSMonitoring();
- }
+
return START_NOT_STICKY;
@@ -79,8 +75,6 @@ public class MatrixService extends Service {
@Override
public void onDestroy() {
mx.destroy();
- this.mms.stopMMSMonitoring();
- this.mms = null;
super.onDestroy();
}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/MmsService.java b/app/src/main/java/eu/droogers/smsmatrix/MmsService.java
new file mode 100644
index 0000000..e77b21d
--- /dev/null
+++ b/app/src/main/java/eu/droogers/smsmatrix/MmsService.java
@@ -0,0 +1,303 @@
+package eu.droogers.smsmatrix;
+
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class MmsService extends Service {
+ private static final String TAG = "MmsService";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.i(TAG, "onStartCommand: MmsService");
+ Boolean firstStart = intent.getBooleanExtra("startButton", false);
+ Boolean newMms = intent.getBooleanExtra("onRecieveMms", false);
+
+ if (firstStart) {
+ Log.i(TAG, "App starting");
+ firstBoot();
+ } else if (newMms) {
+ Log.i(TAG, "New MMS from BroadcastListener.");
+ checkForNewMms();
+ checkUnreadMms();
+ } else {
+ Log.e(TAG, "Something started MmsService?");
+ //we shouldn't get here
+ }
+ return START_NOT_STICKY;
+ }
+
+ private void firstBoot() {
+ SqlOpenHelper mSqlOpenHelper = new SqlOpenHelper(getApplicationContext());
+ long mmsCount = dbManager.countMmses(mSqlOpenHelper);
+ if (mmsCount == 0) {
+ Log.i(TAG, "Importing latest MMS to our DB as starting point");
+ importLatestMms(mSqlOpenHelper);
+ }
+ mSqlOpenHelper.close();
+ }
+
+ private void checkForNewMms() {
+ //can we lock here?
+ SqlOpenHelper mSqlOpenHelper = new SqlOpenHelper(this);
+ long lastBridgedMms = dbManager.lastMmsId(mSqlOpenHelper);
+ long latestMms = getLatestMms(mSqlOpenHelper);
+ Log.i(TAG, "Last MMS ID in our database: " + lastBridgedMms + " Latest MMS ID: " + latestMms);
+ if (lastBridgedMms > 0 && latestMms > lastBridgedMms) {
+ Log.i(TAG, "there is a new MMS to send to Matrix!");
+ findNewMms(lastBridgedMms);
+ } else {
+ Log.i(TAG, "Looks like our databases are in sync.");
+ }
+ mSqlOpenHelper.close();
+ }
+
+ private void findNewMms(long lastBridgedMms) {
+ Uri mmsInboxDatabase = Uri.parse("content://mms/inbox");
+ String selectionPart = "_id > " + lastBridgedMms;
+ Cursor mmsInboxDatabaseCursor = getContentResolver().query(
+ mmsInboxDatabase,
+ null,
+ selectionPart,
+ null,
+ "_id ASC");
+ while (mmsInboxDatabaseCursor.moveToNext()) {
+ long mid = mmsInboxDatabaseCursor.getInt(mmsInboxDatabaseCursor.getColumnIndex("_id"));
+ Log.i(TAG, "mid to look in part for: " + mid );
+ writeToDatabase(mid);
+ }
+ }
+
+ private void writeToDatabase(long mid) {
+ SqlOpenHelper mSqlOpenHelper = new SqlOpenHelper(this);
+ //Get Phone number
+ String sourceNumber = getMmsSourceNumber(mid);
+ Log.i(TAG, "Picture from: " + sourceNumber);
+ dbManager.importNewMms(mSqlOpenHelper,dbManager.TYPE_INCOMING,dbManager.EPOCH_NO,dbManager.EPOCH_NO, sourceNumber, mid,dbManager.BRIDGED_NO,dbManager.LOCK_NO,dbManager.ERROR_NO);
+ }
+
+ private String getMmsSourceNumber(long mid) {
+ String sourceNumber = null;
+
+ Uri mmsAddrDatabase = Uri.parse("content://mms/" + mid + "/addr/");
+ String selectionPart = "type=137";
+ //137 = source
+ //107 = dest
+ String[] selectAddress = new String[] { "address" };
+ Cursor mmsAddrDatabaseCursor = getContentResolver().query(
+ mmsAddrDatabase,
+ selectAddress,
+ selectionPart,
+ null,
+ null);
+ try {
+ mmsAddrDatabaseCursor.moveToFirst();
+ sourceNumber = mmsAddrDatabaseCursor.getString(mmsAddrDatabaseCursor.getColumnIndex("address"));
+ //remove the +1 because I dont need them
+ //sourceNumber = sourceNumber.replace("+1", "");
+ } catch (Exception e) {
+ Log.e(TAG, "Error finding phone number of MID");
+ sourceNumber = "0";
+ } finally {
+ mmsAddrDatabaseCursor.close();
+ }
+
+ return sourceNumber;
+ }
+
+ private long getLatestMms(SqlOpenHelper mSqlOpenHelper) {
+ int mmsId = 0;
+ Uri mmsInboxDatabase = Uri.parse("content://mms/inbox");
+ Cursor mmsInboxDatabaseCursor = getContentResolver().query(
+ mmsInboxDatabase,
+ null,
+ null,
+ null,
+ "_id DESC");
+
+ try {
+ mmsInboxDatabaseCursor.moveToFirst();
+ mmsId = mmsInboxDatabaseCursor.getInt(mmsInboxDatabaseCursor.getColumnIndex("_id"));
+ } catch (Exception e) {
+ Log.e(TAG, "ERROR gettings Latest MMS: " + e );
+ mmsId = 0;
+ } finally {
+ mmsInboxDatabaseCursor.close();
+ }
+
+ return mmsId;
+ }
+
+
+ private long importLatestMms(SqlOpenHelper mSqlOpenHelper) {
+ long mmsId = getLatestMms(mSqlOpenHelper);
+ Log.i(TAG, "Latest MMS message: " + mmsId);
+ long now = System.currentTimeMillis();
+ dbManager.importNewMms(mSqlOpenHelper, dbManager.TYPE_RESYNC, now, now, "0000000000", mmsId, dbManager.BRIDGED_INIT, dbManager.LOCK_NO, dbManager.ERROR_NO );
+ return mmsId;
+ }
+
+
+
+ private void checkUnreadMms() {
+ SqlOpenHelper mSqlOpenHelper = new SqlOpenHelper(getApplicationContext());
+ SQLiteDatabase appDb = mSqlOpenHelper.getReadableDatabase();
+ String unreadMmsSelection = "bridged=0 AND lock=0";
+ Cursor unreadMmsQueryCursor = appDb.query(DatabaseContract.MmsEntry.TABLE_NAME, null, unreadMmsSelection, null, null, null, null);
+ Log.i(TAG, "mmsQueryCursor cursor " + DatabaseUtils.dumpCursorToString(unreadMmsQueryCursor) );
+
+ while (unreadMmsQueryCursor.moveToNext()) {
+ int id = unreadMmsQueryCursor.getInt(unreadMmsQueryCursor.getColumnIndex("_id"));
+ int mid = unreadMmsQueryCursor.getInt(unreadMmsQueryCursor.getColumnIndex("mms_id"));
+ String number = unreadMmsQueryCursor.getString(unreadMmsQueryCursor.getColumnIndex("number"));
+
+ //
+ String selectionPart = "mid=" + String.valueOf(mid) + " AND NOT ct=\'application/smil\'";
+ Uri uri = Uri.parse("content://mms/part");
+ Cursor mmsPartCursor = getContentResolver().query(uri, null, selectionPart, null, null );
+
+ //The part table will have 2+ entries with the same mid.
+ //The first is information about the rest - application/smil - I ignore this
+ //The second++ is each picture set to us
+ //The Last (if provided) is the text message along with all the pictures - text/plain
+ //So an MMS with 2 pictures with text will have 4 parts. information, picture, picture, text.
+ while (mmsPartCursor.moveToNext()) {
+ String type = mmsPartCursor.getString(mmsPartCursor.getColumnIndex("ct"));
+
+ if (type.equals("text/plain")){
+ String text = mmsPartCursor.getString(mmsPartCursor.getColumnIndex("text"));
+ Log.i(TAG, "MMS message with text: " + text );
+ Utilities.sendMatrix(getApplicationContext(), text, number, Matrix.MESSAGE_TYPE_TEXT);
+ } else {
+ String name = mmsPartCursor.getString(mmsPartCursor.getColumnIndex("name"));
+ Log.i(TAG, "MMS message picture: " + name );
+ byte[] mediaData = null;
+ String fileName = "";
+
+ fileName = mmsPartCursor.getString(mmsPartCursor.getColumnIndex("name"));
+ Log.e(TAG, "mmsPartCursor - fileName " + fileName);
+
+ mediaData = readMMSPart(mmsPartCursor.getString(mmsPartCursor.getColumnIndex("_id")));
+ Log.e(TAG, "mmsPartCursor - mediaData " + mediaData);
+
+ String contentType = mmsPartCursor.getString(mmsPartCursor.getColumnIndex("ct"));
+ Log.e(TAG, "mmsPartCursor - contentType " + contentType);
+
+ if (isImageType(contentType)) {
+ Utilities.sendMatrix(
+ getApplicationContext(),
+ mediaData,
+ number,
+ Matrix.MESSAGE_TYPE_IMAGE,
+ fileName,
+ contentType
+ );
+ } else if (isVideoType(contentType)) {
+ Utilities.sendMatrix(
+ getApplicationContext(),
+ mediaData,
+ number,
+ Matrix.MESSAGE_TYPE_VIDEO,
+ fileName,
+ contentType
+ );
+ }
+ dbManager.markMmsRead(mSqlOpenHelper, id);
+
+ }
+ }
+ mmsPartCursor.close();
+ }
+ unreadMmsQueryCursor.close();
+ appDb.close();
+ mSqlOpenHelper.close();
+
+ }
+
+ private byte[] readMMSPart(String partId) {
+ byte[] partData = null;
+ Uri partURI = Uri.parse("content://mms/part/" + partId);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ InputStream is = null;
+
+ try {
+
+ Log.i(TAG,"Entered into readMMSPart try.");
+ ContentResolver mContentResolver = getContentResolver();
+ is = mContentResolver.openInputStream(partURI);
+
+ byte[] buffer = new byte[256];
+ int len = is.read(buffer);
+ while (len >= 0) {
+ baos.write(buffer, 0, len);
+ len = is.read(buffer);
+ }
+ partData = baos.toByteArray();
+
+ } catch (IOException e) {
+ Log.e(TAG, "Exception == Failed to load part data");
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Exception :: Failed to close stream");
+ }
+ }
+ }
+ return partData;
+ }
+
+ private boolean isImageType(String mime) {
+ boolean result = false;
+ if (mime.equalsIgnoreCase("image/jpg")
+ || mime.equalsIgnoreCase("image/jpeg")
+ || mime.equalsIgnoreCase("image/png")
+ || mime.equalsIgnoreCase("image/gif")
+ || mime.equalsIgnoreCase("image/bmp")) {
+ result = true;
+ }
+ return result;
+ }
+
+ private boolean isVideoType(String mime) {
+ boolean result = false;
+ if (mime.equalsIgnoreCase("video/3gpp")
+ || mime.equalsIgnoreCase("video/3gpp2")
+ || mime.equalsIgnoreCase("video/avi")
+ || mime.equalsIgnoreCase("video/mp4")
+ || mime.equalsIgnoreCase("video/mpeg")
+ || mime.equalsIgnoreCase("video/webm")) {
+ result = true;
+ }
+ return result;
+ }
+
+
+
+ @Override
+ public void onDestroy() {
+ Log.i(TAG, "onDestroy: MmsService");
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/ReceiverListener.java b/app/src/main/java/eu/droogers/smsmatrix/ReceiverListener.java
index cf1e6c0..a01ed24 100644
--- a/app/src/main/java/eu/droogers/smsmatrix/ReceiverListener.java
+++ b/app/src/main/java/eu/droogers/smsmatrix/ReceiverListener.java
@@ -9,6 +9,8 @@ import android.telephony.TelephonyManager;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
/**
* Created by gerben on 6-10-17.
@@ -16,6 +18,8 @@ import java.util.Map;
public class ReceiverListener extends BroadcastReceiver {
private static final String TAG = "ReceiverListener";
+ private static final String ACTION_MMS_RECEIVED = "android.provider.Telephony.WAP_PUSH_RECEIVED";
+ private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";
@Override
public void onReceive(Context context, Intent intent) {
@@ -23,6 +27,8 @@ public class ReceiverListener extends BroadcastReceiver {
handleIncomingSMS(context, intent);
} else if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
handleIncomingCall(context, intent);
+ } else if (intent.getAction().equals(ACTION_MMS_RECEIVED) && intent.getType().equals(MMS_DATA_TYPE)) {
+ handleIncomingMMS(context, intent);
}
}
@@ -81,4 +87,41 @@ public class ReceiverListener extends BroadcastReceiver {
}
Utilities.sendMatrix(context, body, cal_from, Matrix.MESSAGE_TYPE_NOTICE);
}
+
+ private void handleIncomingMMS(final Context context, Intent intent) {
+ //I don't know how to download MMSC from cell provider. so we will do something with mmssms.sb
+ try {
+ Bundle bundle = intent.getExtras();
+ if (bundle != null) {
+ byte[] buffer = bundle.getByteArray("data");
+ String bufferString = new String(buffer);
+ Log.i(TAG, "bufferString: " + bufferString);
+
+ //Get Phone Number (between + and /TYPE
+ int mmsIndex = bufferString.indexOf("/TYPE");
+ int mmsIndexPlus = bufferString.indexOf("+");
+ String number = bufferString.substring(mmsIndexPlus, mmsIndex);
+ //Got phone number, Remove +1
+ //number = number.replace("+1", "");
+ Log.i(TAG, "Phone Number: " + number);
+
+ new Timer().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ Log.i(TAG, "Checking if MMS is downloaded.");
+ // this code will be executed after 15 seconds
+ Intent intnet = new Intent(context, eu.droogers.smsmatrix.MmsService.class);
+ intnet.putExtra("onRecieveMms", true);
+ context.startService(intnet);
+ }
+ }, 15000);
+
+ }
+
+ } catch (Exception e ) {
+ Log.e(TAG, "received mms failed " + e);
+ }
+
+ }
+
}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/SqlOpenHelper.java b/app/src/main/java/eu/droogers/smsmatrix/SqlOpenHelper.java
new file mode 100644
index 0000000..f64b569
--- /dev/null
+++ b/app/src/main/java/eu/droogers/smsmatrix/SqlOpenHelper.java
@@ -0,0 +1,26 @@
+package eu.droogers.smsmatrix;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+public class SqlOpenHelper extends SQLiteOpenHelper {
+ public static final String DATABASE_NAME = "SmsMatrix.db";
+ public static final int DATABASE_VERSION = 1;
+
+
+ public SqlOpenHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(DatabaseContract.SmsEntry.SQL_CREATE_TABLE);
+ db.execSQL(DatabaseContract.MmsEntry.SQL_CREATE_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+
+ }
+}
diff --git a/app/src/main/java/eu/droogers/smsmatrix/dbManager.java b/app/src/main/java/eu/droogers/smsmatrix/dbManager.java
new file mode 100644
index 0000000..5c4063f
--- /dev/null
+++ b/app/src/main/java/eu/droogers/smsmatrix/dbManager.java
@@ -0,0 +1,169 @@
+package eu.droogers.smsmatrix;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+public class dbManager {
+ private static dbManager ourInsance = null;
+ private static final String TAG = "dbManager";
+ public static final int TYPE_INCOMING = 1;
+ public static final int TYPE_OUTGOING = 2;
+ public static final int TYPE_RESYNC = 3;
+ public static final int BRIDGED_NO = 0;
+ public static final int BRIDGED_YES = 1;
+ public static final int BRIDGED_INIT = 2;
+ public static final int LOCK_NO = 0;
+ public static final int LOCK_YES = 1;
+ public static final int ERROR_NO = 0;
+ public static final int EPOCH_NO = 0;
+
+
+ private static final String[] ALLColumns = new String[] { "*" };
+
+
+ public static dbManager getInstance() {
+ if(ourInsance == null) {
+ ourInsance = new dbManager();
+ }
+ return ourInsance;
+ }
+
+ public static long dumpSmses(SqlOpenHelper dbHelper) {
+ Log.i(TAG, "dumpSmses");
+
+ SQLiteDatabase db = dbHelper.getReadableDatabase();
+ Cursor smsQueryCursor = db.query(DatabaseContract.SmsEntry.TABLE_NAME, ALLColumns, null, null, null, null, null);
+ long smsCount=smsQueryCursor.getCount();
+ Log.i(TAG, "Heres what's in the cursor " + DatabaseUtils.dumpCursorToString(smsQueryCursor) );
+ smsQueryCursor.close();
+ db.close();
+
+ Log.i(TAG, "dumpSmses is done");
+ return smsCount;
+ }
+
+ public static long dumpMmses(SqlOpenHelper dbHelper) {
+ Log.i(TAG, "dumpMmses");
+
+ SQLiteDatabase db = dbHelper.getReadableDatabase();
+ Cursor mmsQueryCursor = db.query(DatabaseContract.MmsEntry.TABLE_NAME, ALLColumns, null, null, null, null, null);
+ Log.i(TAG, "Heres what's in the cursor " + DatabaseUtils.dumpCursorToString(mmsQueryCursor) );
+ long mmsCount = mmsQueryCursor.getCount();
+ mmsQueryCursor.close();
+ db.close();
+
+ Log.i(TAG, "dumpMmses is done");
+ return mmsCount;
+ }
+
+ public static long countMmses(SqlOpenHelper dbHelper) {
+ Log.i(TAG, "countMmses");
+
+ SQLiteDatabase db = dbHelper.getReadableDatabase();
+ Cursor mmsQueryCursor = db.query(DatabaseContract.MmsEntry.TABLE_NAME, ALLColumns, null, null, null, null, null);
+ long mmsCount = mmsQueryCursor.getCount();
+ mmsQueryCursor.close();
+ db.close();
+
+ Log.i(TAG, "countMmses is done");
+ return mmsCount;
+ }
+
+ public static long importNewSms(SqlOpenHelper dbHelper, int type, long sourceEpoch, long recievedEpoch, String number, String message, int bridged, int lock, int error) {
+ Log.i(TAG, "importNewSms");
+ long smsImportRowId = -1;
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(DatabaseContract.SmsEntry.COLUMN_TYPE, type);
+ values.put(DatabaseContract.SmsEntry.COLUMN_SOURCE_EPOCH, sourceEpoch);
+ values.put(DatabaseContract.SmsEntry.COLUMN_RECIEVED_EPOCH, recievedEpoch);
+ values.put(DatabaseContract.SmsEntry.COLUMN_NUMBER, number);
+ values.put(DatabaseContract.SmsEntry.COLUMN_MESSAGE, message);
+ values.put(DatabaseContract.SmsEntry.COLUMN_BRIDGED, bridged);
+ values.put(DatabaseContract.SmsEntry.COLUMN_LOCK, lock);
+ values.put(DatabaseContract.SmsEntry.COLUMN_ERROR, error);
+ try {
+ smsImportRowId = db.insert(DatabaseContract.SmsEntry.TABLE_NAME, null, values);
+ Log.i(TAG, "importNewSms " + smsImportRowId );
+ } catch (Exception e) {
+ Log.e(TAG, "importNewSms failed " + e );
+ smsImportRowId = -1;
+ } finally {
+ db.close();
+ return smsImportRowId;
+ }
+ }
+
+ public static void updateLongSmsBody (SqlOpenHelper dbHelper, long id, String body ){
+ Log.i(TAG, "updateLongSmsBody");
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(DatabaseContract.SmsEntry.COLUMN_MESSAGE, body);
+ try {
+ Log.i(TAG, " try updateLongSmsBody _id=" + id );
+ db.update(DatabaseContract.SmsEntry.TABLE_NAME, values, "_id=" + id, null );
+ } catch (Exception e) {
+ Log.e(TAG, "updateLongSmsBody failed " + e );
+ } finally {
+ db.close();
+ }
+ }
+
+ public static long importNewMms(SqlOpenHelper dbHelper, int type, long sourceEpoch, long recievedEpoch, String number, long mmsId, int bridged, int lock, int error) {
+ Log.i(TAG, "importNewMms");
+ long mmsImportRowId = -1;
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(DatabaseContract.MmsEntry.COLUMN_TYPE, type);
+ values.put(DatabaseContract.MmsEntry.COLUMN_SOURCE_EPOCH, sourceEpoch);
+ values.put(DatabaseContract.MmsEntry.COLUMN_RECIEVED_EPOCH, recievedEpoch);
+ values.put(DatabaseContract.MmsEntry.COLUMN_NUMBER, number);
+ values.put(DatabaseContract.MmsEntry.COLUMN_MMS_ID, mmsId);
+ values.put(DatabaseContract.MmsEntry.COLUMN_BRIDGED, bridged);
+ values.put(DatabaseContract.MmsEntry.COLUMN_LOCK, lock);
+ values.put(DatabaseContract.MmsEntry.COLUMN_ERROR, error);
+ try {
+ mmsImportRowId = db.insert(DatabaseContract.MmsEntry.TABLE_NAME, null, values);
+ Log.i(TAG, "importNewMms " + mmsImportRowId );
+ } catch (Exception e) {
+ Log.e(TAG, "importNewMms failed " + e );
+ mmsImportRowId = -1;
+ } finally {
+ db.close();
+ return mmsImportRowId;
+ }
+ }
+
+ public static long lastMmsId(SqlOpenHelper dbHelper) {
+ Log.i(TAG, "lastMmsId");
+ int mmsId = 0;
+ SQLiteDatabase db = dbHelper.getReadableDatabase();
+ Cursor mmsQueryCursor = db.query(DatabaseContract.MmsEntry.TABLE_NAME, ALLColumns, null, null, null, null, "mms_id DESC");
+ mmsQueryCursor.moveToFirst();
+ mmsId = mmsQueryCursor.getInt(mmsQueryCursor.getColumnIndex("mms_id"));
+ mmsQueryCursor.close();
+ db.close();
+ Log.i(TAG, "lastMmsId is done");
+ return mmsId;
+ }
+
+
+ public static void markMmsRead (SqlOpenHelper dbHelper, long id ){
+ Log.i(TAG, "markMmsRead");
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(DatabaseContract.MmsEntry.COLUMN_BRIDGED, 1);
+ try {
+ Log.i(TAG, " try updateLongSmsBody _id=" + id );
+ db.update(DatabaseContract.MmsEntry.TABLE_NAME, values, "_id=" + id, null );
+ } catch (Exception e) {
+ Log.e(TAG, "updateLongSmsBody failed " + e );
+ } finally {
+ db.close();
+ }
+ }
+
+}