From 5cb02445e828d84e8416a771f784a73eb1353c29 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sun, 6 Jan 2013 21:38:36 -0800 Subject: [PATCH] Add support for "delivery notifications." Currently SMS-only. --- res/drawable-hdpi/ic_sms_mms_delivered.png | Bin 0 -> 927 bytes res/drawable-mdpi/ic_sms_mms_delivered.png | Bin 0 -> 692 bytes res/drawable-xhdpi/ic_sms_mms_delivered.png | Bin 0 -> 1168 bytes res/layout/conversation_item_received.xml | 10 +++- res/layout/conversation_item_sent.xml | 7 +++ res/xml/preferences.xml | 32 ++++++------ .../ApplicationPreferencesActivity.java | 3 ++ .../securesms/ConversationAdapter.java | 3 +- .../securesms/ConversationItem.java | 3 ++ .../securesms/database/MmsSmsDatabase.java | 7 +-- .../securesms/database/SmsDatabase.java | 17 +++++++ .../database/model/MediaMmsMessageRecord.java | 3 +- .../database/model/MessageRecord.java | 18 ++++++- .../model/NotificationMmsMessageRecord.java | 4 +- .../database/model/SmsMessageRecord.java | 21 ++++++-- .../securesms/service/SendReceiveService.java | 7 ++- .../securesms/service/SmsListener.java | 46 ++++++++++-------- .../securesms/service/SmsReceiver.java | 16 ++++++ .../securesms/service/SmsSender.java | 38 ++++++++++++--- 19 files changed, 174 insertions(+), 61 deletions(-) create mode 100644 res/drawable-hdpi/ic_sms_mms_delivered.png create mode 100644 res/drawable-mdpi/ic_sms_mms_delivered.png create mode 100644 res/drawable-xhdpi/ic_sms_mms_delivered.png diff --git a/res/drawable-hdpi/ic_sms_mms_delivered.png b/res/drawable-hdpi/ic_sms_mms_delivered.png new file mode 100644 index 0000000000000000000000000000000000000000..0802373ec3cb9e90a4518a41c931437c93761294 GIT binary patch literal 927 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*FB&(dWK3`~nXT^vI^jxU|+oh=e5(7ONCZDDpbu8$i} z{D_b&m-^}^zR#eEv6oxCOMAQ8e+Lm0De<4YiypW+ewR|}5Kuknz*hL!?W5xX^%)*& z=ikkHt#tMA*%Y~pA|~I@y?s@@%5UyF!D|xRkDrcal$pTT$E4q=@rPf5fm!8VJ|mOu zZk{_#>zJ57$%k?U1RV%st&lG`Z2g`u%=yCQz--H+%*v*KW0`=&t?z z#^%TAw=aJ^^Leq3@h{hn^_q4S!XH>HxR3CvZn}1!Q>&!{=pf_4V&7|EBM|Bl6HnpxWrD14j*;AA@|5a?62-ZY<{#A01ur z_U(sh2d~9mu3ek!s#2iI$z{hn=kq~EAG`VYd0lwdu`aOeY?8INf2wAdH&;3H2!(p$mZ5vKL|13LCx@X46jO9P-)m_xSNUN0#MocHTM7!^PsAjP0=x92~oK zKki;%e^>q5EpM-BD|o|u9L_V}HSaWt)cW`%a-qTJ0-wGPgIOncSoyW8>M8aOx;6P)QU+ARByUZemCg;TuUp~;} zaWhbxgK6rEIMdEmt=ALTc0?qXX{%&ickJGJEzthbLFw~}rJOtkC$j6eK8*O~;<9z# z*Z=%!{{?MSIri3uHhsy~67|eX@8!5OePbFs_bd$^-n0A7-``#BJ|QVYwc@~}{nr_v zm-03mKG=HQb?w3BbKSRci0yTmlE9+zBJ$FSZC{nXXnCkgeLc{ax-UNT2kTNZ*QFBS zk<)lqx4MPkKtqjer zj4X8x%&iOz(tdT`N70a*pOTqYiCcsCa>Hbx21$?&!TD(=<%vb942~)JNvR5+xryni ZL8*x;m4zo$ZGegxJYD@<);T3K0RU$)d-MPR literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_sms_mms_delivered.png b/res/drawable-mdpi/ic_sms_mms_delivered.png new file mode 100644 index 0000000000000000000000000000000000000000..44b91453d677e8dfb1393db9cf184382a76ccbc1 GIT binary patch literal 692 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zK-vS0-A-oPfdtD69Mgd`SU*F|v9*U87#MeWx;TbdoNm2jn;{Y?!usI-xxRW0w@Z;f zx;3{5ev;x=3}gw^3F_E3t*Li!$D-b;Q(G6gMtLi8G`R`{`jmwpIi#m)GQ*Fhe$ttD zn?Jakd8>%aedjGcKePDU+zo!V8S5)^rry*2uJ`SMiQHAQb$KsMrQRG+@mth4C1_2% zRoTB{)2h6Uw{q}nH*X0$x5WVZB6((`w}eUW5W0WK|`SNq+=WM_CCCM6EZGCc; zS?EFLgIP9@|NB2-6kujPu-!quK+0jOR}e>H2^aqYfk{^cZ!07}P<_DiVaFMHroJ_& z8m)v_XG}?#u5>-IpK(`%(FVpH>@9KKUe!)NX7DH%n-zK2Ih{x@)MEU`Xza-S#EYkt z@&3s>1_tVa(_SmBKOx2cL%@PfW9im&YntS=g!t|n9J|0>!}(^Czdb`f!}iAMjgLc$ z=XF@w6}ZTJXgqTMX_1?qnXRAP?>lq;|65gMX#ZR4L!-xRhTDzLRc|eJk~_VN;Rjd6 z{9DsZyt4P|X5X8d{_of4Tg!Hq@BeZ4{k=ddh8iUov+rVV9W@Vh3|OYj`675CMUCBO z(Z9M)@BgiQ*{N&(t$zw%zw3_!$CFGJhRq54#(jXJ;Ckmgr-<60>W?)T-yZvL>T9v= z&bhM8C1u3{AqAap`*v{d;S|ZecQ=D6>$V!V)`4RxfzAH5(NgEXKk43n_M>yMpx2a+ z)|`1+fquc+9wJWe=cd${8jH>C(9YVhzy4V0BZaMUAH)jUqO{}Y`M2L;H#4)mwRA#^ zYSGVm*DKwMC4TVyc=1s0*dz9N{2||7YE6{3ZMYP*U;WAVhG^eq4vc&K99a+4E|r+S z_k+jB7jr$uo+a)mw*R29ICy>#hx>|e^Oka`{Ng>JV=!|e-@R$2-Ch!h6W$k>AOF7P zX?IuUp%2H^A4QyH6kV$?=z6-BB}rjfl}ldnqAZsAx8k<7`%7l{CvCOn(Vx#`lYHZ8 z<+ImL98t@qH}OqrluKxrhrd|J-G)=9Qs?O!>| z0oUiTjL|DYH-|pvy7~I>wNU4$ObLtf-pMZTomcxHJfW-9>2K>1GqvA;xCJgoHJYtq zW?isVtxIXkHO39%H(35WnUE~oeW`DYnCOaj{y%Rf=szo1d-Af(hn64auT?)FK#IZ0z|c_Fz(Uv9FvQT%%Fx`($Wqt9+{(Zp z?N{f06b-rgDVb@NxHX6`H%ta-L1;Fyx1l&avFo0y&&l$w}QS$Hzl Q2B?U^)78&qol`;+098Hppa1{> literal 0 HcmV?d00001 diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml index 39e3b0705..cbb0d39e5 100644 --- a/res/layout/conversation_item_received.xml +++ b/res/layout/conversation_item_received.xml @@ -96,6 +96,13 @@ android:orientation="horizontal" android:gravity="left"> + + - + android:paddingTop="1dip"/> + + - + + + + + + + = SmsDatabase.Status.STATUS_FAILED) { + return MessageRecord.DELIVERY_STATUS_FAILED; + } else if (status >= SmsDatabase.Status.STATUS_PENDING) { + return MessageRecord.DELIVERY_STATUS_PENDING; + } else { + return MessageRecord.DELIVERY_STATUS_RECEIVED; + } + } } diff --git a/src/org/thoughtcrime/securesms/service/SendReceiveService.java b/src/org/thoughtcrime/securesms/service/SendReceiveService.java index 6a0c912ba..50c0b6e1d 100644 --- a/src/org/thoughtcrime/securesms/service/SendReceiveService.java +++ b/src/org/thoughtcrime/securesms/service/SendReceiveService.java @@ -47,6 +47,7 @@ public class SendReceiveService extends Service { public static final String SEND_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SEND_SMS_ACTION"; public static final String SENT_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SENT_SMS_ACTION"; + public static final String DELIVERED_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DELIVERED_SMS_ACTION"; public static final String RECEIVE_SMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_SMS_ACTION"; public static final String SEND_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SEND_MMS_ACTION"; public static final String SEND_MMS_CONNECTIVITY_ACTION = "org.thoughtcrime.securesms.SendReceiveService.SEND_MMS_CONNECTIVITY_ACTION"; @@ -93,6 +94,8 @@ public class SendReceiveService extends Service { scheduleIntent(RECEIVE_SMS, intent); else if (intent.getAction().equals(SENT_SMS_ACTION)) scheduleIntent(RECEIVE_SMS, intent); + else if (intent.getAction().equals(DELIVERED_SMS_ACTION)) + scheduleIntent(RECEIVE_SMS, intent); else if (intent.getAction().equals(SEND_MMS_ACTION) || intent.getAction().equals(SEND_MMS_CONNECTIVITY_ACTION)) scheduleSecretRequiredIntent(SEND_MMS, intent); else if (intent.getAction().equals(RECEIVE_MMS_ACTION)) @@ -191,8 +194,8 @@ public class SendReceiveService extends Service { public void run() { switch (what) { - case RECEIVE_SMS: smsReceiver.process(masterSecret, intent); return; - case SEND_SMS: smsSender.process(masterSecret, intent); return; + case RECEIVE_SMS: smsReceiver.process(masterSecret, intent); return; + case SEND_SMS: smsSender.process(masterSecret, intent); return; case RECEIVE_MMS: mmsReceiver.process(masterSecret, intent); return; case SEND_MMS: mmsSender.process(masterSecret, intent); return; case DOWNLOAD_MMS: mmsDownloader.process(masterSecret, intent); return; diff --git a/src/org/thoughtcrime/securesms/service/SmsListener.java b/src/org/thoughtcrime/securesms/service/SmsListener.java index 62f7f58a4..002f404ca 100644 --- a/src/org/thoughtcrime/securesms/service/SmsListener.java +++ b/src/org/thoughtcrime/securesms/service/SmsListener.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,14 +10,12 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.service; -import org.thoughtcrime.securesms.protocol.WirePrefix; - import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -26,6 +24,8 @@ import android.preference.PreferenceManager; import android.telephony.SmsMessage; import android.util.Log; +import org.thoughtcrime.securesms.protocol.WirePrefix; + public class SmsListener extends BroadcastReceiver { private static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; @@ -40,58 +40,58 @@ public class SmsListener extends BroadcastReceiver { if (messageBody.startsWith("Sparebank1://otp?")) { return true; } - + // Sprint Visual Voicemail - return - message.getOriginatingAddress().length() < 7 && - (messageBody.startsWith("//ANDROID:") || messageBody.startsWith("//Android:") || + return + message.getOriginatingAddress().length() < 7 && + (messageBody.startsWith("//ANDROID:") || messageBody.startsWith("//Android:") || messageBody.startsWith("//android:") || messageBody.startsWith("//BREW:")); } - + private SmsMessage getSmsMessageFromIntent(Intent intent) { Bundle bundle = intent.getExtras(); Object[] pdus = (Object[])bundle.get("pdus"); if (pdus == null || pdus.length == 0) return null; - + return SmsMessage.createFromPdu((byte[])pdus[0]); } - + private String getSmsMessageBodyFromIntent(Intent intent) { Bundle bundle = intent.getExtras(); Object[] pdus = (Object[])bundle.get("pdus"); StringBuilder bodyBuilder = new StringBuilder(); - + if (pdus == null) return null; - + for (int i=0;i constructDeliveredIntents(long messageId, long type, ArrayList messages) { + if (!PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(ApplicationPreferencesActivity.SMS_DELIVERY_REPORT_PREF, false)) + { + return null; + } + + ArrayList deliveredIntents = new ArrayList(messages.size()); + + for (int i=0;i messages = SmsManager.getDefault().divideMessage(text); - ArrayList sentIntents = constructSentIntents(messageId, type, messages); + ArrayList messages = SmsManager.getDefault().divideMessage(text); + ArrayList sentIntents = constructSentIntents(messageId, type, messages); + ArrayList deliveredIntents = constructDeliveredIntents(messageId, type, messages); + // XXX moxie@thoughtcrime.org 1/7/11 -- There's apparently a bug where for some unknown recipients // and messages, this will throw an NPE. I have no idea why, so I'm just catching it and marking // the message as a failure. That way at least it doesn't repeatedly crash every time you start // the app. try { - SmsManager.getDefault().sendMultipartTextMessage(recipient, null, messages, sentIntents, null); + SmsManager.getDefault().sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents); } catch (NullPointerException npe) { Log.w("SmsSender", npe); DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId); @@ -142,15 +165,18 @@ public class SmsSender { return; } - ArrayList messages = multipartMessageHandler.divideMessage(recipient, text, prefix); - ArrayList sentIntents = constructSentIntents(messageId, type, messages); + ArrayList messages = multipartMessageHandler.divideMessage(recipient, text, prefix); + ArrayList sentIntents = constructSentIntents(messageId, type, messages); + ArrayList deliveredIntents = constructDeliveredIntents(messageId, type, messages); + for (int i=0;i