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(); + } + } + +}