11

I want to add some MMS messages into my device database.

I've the following code but it doesn't work at all. No entry are added into the native app...

public static Uri insert(Context context, String[] to, String subject, Uri messageUri)
{
    try
    {
        Uri destUri = Uri.parse("content://mms/sent");

        // Get thread id
        Set<String> recipients = new HashSet<String>();
        recipients.addAll(Arrays.asList(to));
        long thread_id = getOrCreateThreadId(context, recipients);
        Log.e(">>>>>>>", "Thread ID is " + thread_id);

        // Create a dummy sms
        ContentValues dummyValues = new ContentValues();
        dummyValues.put("thread_id", thread_id);
        dummyValues.put("body", "Dummy SMS body.");
        Uri dummySms = context.getContentResolver().insert(Uri.parse("content://sms/sent"), dummyValues);

        // Create a new message entry
        ContentValues mmsValues = new ContentValues();
        mmsValues.put("thread_id", thread_id);
        mmsValues.put("date", System.currentTimeMillis()/1000);
        mmsValues.put("ct_t", "application/vnd.wap.multipart.related");
        mmsValues.put("read", "1");
        mmsValues.put("sub", subject);

        // Create part
        long dummyId = System.currentTimeMillis();
        createPart(context, dummyId, imageBytes);

        // Insert message
        Uri res = context.getContentResolver().insert(destUri, mmsValues);
        String messageId = res.getLastPathSegment().trim();
        Log.e(">>>>>>>", "Message saved as " + res);

        // Update part
        ContentValues updateValues = new ContentValues();
        updateValues.put("mid", messageId);
        Uri updateUri = Uri.parse("content://mms/" + dummyId + "/part");
        int mmsPartRows = context.getContentResolver().update(updateUri, updateValues, null, null);
        Log.e(">>>>>>>", "Part rows " + mmsPartRows);

        // Create addresses
        for (String addr : to)
        {
            ContentValues addrValues = new ContentValues();
            addrValues.put("address", addr);
            addrValues.put("charset", "106");
            addrValues.put("type", 151); // TO
            Uri addrUri = Uri.parse("content://mms/"+ messageId +"/addr");
            Uri mmsAddrUri = context.getContentResolver().insert(addrUri, addrValues);
            Log.e(">>>>>>>", "Addr uri is " + mmsAddrUri.toString());
        }

        res = Uri.parse(destUri + "/" + messageId);

        // Delete dummy sms
        context.getContentResolver().delete(dummySms, null, null);

        return res;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    return null;
}

private static Uri createPart(Context context, long id, byte[] imageBytes) throws Exception
{
    ContentValues mmsPartValue = new ContentValues();
    mmsPartValue.put("ct", "image/png");
    Uri partUri = Uri.parse("content://mms/" + id + "/part");
    Uri res = context.getContentResolver().insert(partUri, mmsPartValue);
    Log.e(">>>>>>>", "Part uri is " + res.toString());

    // Add data to part
    OutputStream os = context.getContentResolver().openOutputStream(res);
    ByteArrayInputStream is = new ByteArrayInputStream(imageBytes);
    byte[] buffer = new byte[256];
    for (int len=0; (len=is.read(buffer)) != -1;)
    {
        os.write(buffer, 0, len);
    }
    os.close();
    is.close();

    return res;
}

private static long getOrCreateThreadId(Context context, String[] numbers)
{
    HashSet<String> recipients = new HashSet<String>();
    recipients.addAll(Arrays.asList(numbers));
    return Telephony.Threads.getOrCreateThreadId(context, recipients);
}
  • context is my view context
  • to is a string array containing the addresses (eg. new String[] {"0612345678", "0623456789"})
  • subject is my MMS subject such as "Sent via MyApp"
  • messageUri is an Uri pointing to the image I want to send on my SD card.

Am I doing it wrong ?

Manitoba
  • 8,522
  • 11
  • 60
  • 122

1 Answers1

10

Finally I found how to do the job ! Here is the code I made.

Tell me if you got some troubles with this.

public static Uri insert(Context context, String[] to, String subject, byte[] imageBytes)
{
    try
    {           
        Uri destUri = Uri.parse("content://mms");

        // Get thread id
        Set<String> recipients = new HashSet<String>();
        recipients.addAll(Arrays.asList(to));
        long thread_id = getOrCreateThreadId(context, recipients);
        Log.e(">>>>>>>", "Thread ID is " + thread_id);

        // Create a dummy sms
        ContentValues dummyValues = new ContentValues();
        dummyValues.put("thread_id", thread_id);
        dummyValues.put("body", "Dummy SMS body.");
        Uri dummySms = context.getContentResolver().insert(Uri.parse("content://sms/sent"), dummyValues);

        // Create a new message entry
        long now = System.currentTimeMillis();
        ContentValues mmsValues = new ContentValues();
        mmsValues.put("thread_id", thread_id);
        mmsValues.put("date", now/1000L);
        mmsValues.put("msg_box", MESSAGE_TYPE_OUTBOX);
        //mmsValues.put("m_id", System.currentTimeMillis());
        mmsValues.put("read", 1);
        mmsValues.put("sub", subject);
        mmsValues.put("sub_cs", 106);
        mmsValues.put("ct_t", "application/vnd.wap.multipart.related");
        mmsValues.put("exp", imageBytes.length);
        mmsValues.put("m_cls", "personal");
        mmsValues.put("m_type", 128); // 132 (RETRIEVE CONF) 130 (NOTIF IND) 128 (SEND REQ)
        mmsValues.put("v", 19);
        mmsValues.put("pri", 129);
        mmsValues.put("tr_id", "T"+ Long.toHexString(now));
        mmsValues.put("resp_st", 128);

        // Insert message
        Uri res = context.getContentResolver().insert(destUri, mmsValues);
        String messageId = res.getLastPathSegment().trim();
        Log.e(">>>>>>>", "Message saved as " + res);

        // Create part
        createPart(context, messageId, imageBytes);

        // Create addresses
        for (String addr : to)
        {
            createAddr(context, messageId, addr);
        }

        //res = Uri.parse(destUri + "/" + messageId);

        // Delete dummy sms
        context.getContentResolver().delete(dummySms, null, null);

        return res;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    return null;
}

private static Uri createPart(Context context, String id, byte[] imageBytes) throws Exception
{
    ContentValues mmsPartValue = new ContentValues();
    mmsPartValue.put("mid", id);
    mmsPartValue.put("ct", "image/png");
    mmsPartValue.put("cid", "<" + System.currentTimeMillis() + ">");
    Uri partUri = Uri.parse("content://mms/" + id + "/part");
    Uri res = context.getContentResolver().insert(partUri, mmsPartValue);
    Log.e(">>>>>>>", "Part uri is " + res.toString());

    // Add data to part
    OutputStream os = context.getContentResolver().openOutputStream(res);
    ByteArrayInputStream is = new ByteArrayInputStream(imageBytes);
    byte[] buffer = new byte[256];
    for (int len=0; (len=is.read(buffer)) != -1;)
    {
        os.write(buffer, 0, len);
    }
    os.close();
    is.close();

    return res;
}

private static Uri createAddr(Context context, String id, String addr) throws Exception
{
    ContentValues addrValues = new ContentValues();
    addrValues.put("address", addr);
    addrValues.put("charset", "106");
    addrValues.put("type", 151); // TO
    Uri addrUri = Uri.parse("content://mms/"+ id +"/addr");
    Uri res = context.getContentResolver().insert(addrUri, addrValues);
    Log.e(">>>>>>>", "Addr uri is " + res.toString());

    return res;
}
Manitoba
  • 8,522
  • 11
  • 60
  • 122
  • 1
    getOrCreateThreadId(context, recipients) where is this method ? – kamal_tech_view Apr 08 '13 at 06:27
  • why you are sending Uri dummySms = context.getContentResolver().insert(Uri.parse("content://sms/sent"), dummyValues); – kamal_tech_view Apr 09 '13 at 05:12
  • Apparently, on some devices (running 2.2-), if there is not discussion with the given contact yet, you need to insert a dummy SMS into DB, then insert your MMS and finally delete the dummy sms. – Manitoba Apr 09 '13 at 07:55
  • Thanks Vodemki and have you work on send mms programatically.. if you have then I need some help from you. – kamal_tech_view Apr 09 '13 at 08:37
  • I have a semi working MMS lib that sends MMS programmatically. For the moment it works perfectly in France, but not in all countries. For example, it UK it works once on 10... I'm still working on it. Check my profile for email address – Manitoba Apr 09 '13 at 08:55
  • vodemki(.at.)gmail(.dot.)com – Manitoba Apr 09 '13 at 11:54
  • Can anybody help me about the method... getOrCreateThreadId(context, recipients) where is this method ? – Komal Sorathiya Mar 25 '14 at 09:41
  • Right here: http://my.fit.edu/~vkepuska/ece5570/adt-bundle-windows-x86_64/sdk/sources/android-14/android/provider/Telephony.java – Manitoba Mar 25 '14 at 18:23
  • @manitoba: Hi tried this solution its giving me error in KITKAT 4.4, inside createPart() method // Add data to part OutputStream os = context.getContentResolver().openOutputStream(res); its giving me exception java.io.FileNotFoundException: App op not allowed – Min2 Aug 12 '14 at 09:22
  • Does anyone know how to delete the MMS and corresponding database entries programmatically? – ssk Aug 27 '14 at 18:21
  • I've been implementing your code with success, but as I'm trying to insert some file quite big (I mean not too small), when I try to show them after by quering the database, theses image files seems to be corrupted, at least truncated, have you heard of a restriction one the size of the file you're storing? Have you ever met this behaviour? – tchoum Dec 08 '15 at 10:45
  • Hello tchoum, i've taken a look at your issue. The method takes the following parameter `byte[] imageBytes` which must be a weakness if you try to push a far too big photo (or whatever type the MMS format allows). I would suggest to improve the code to handle every kind of sizes. I've written a quick gist to show you a way to achieve that: https://gist.github.com/anonymous/10bc611f89f2544e354e – Manitoba Dec 08 '15 at 16:10