From 26979b1c626391df9ba96c0e3165c1f17036e831 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Mon, 21 Sep 2015 10:54:23 -0700 Subject: [PATCH] Log calls to conversations // FREEBIE --- .../ic_call_made_grey600_24dp.png | Bin 0 -> 284 bytes .../ic_call_missed_grey600_24dp.png | Bin 0 -> 311 bytes .../ic_call_received_grey600_24dp.png | Bin 0 -> 309 bytes .../ic_call_made_grey600_24dp.png | Bin 0 -> 227 bytes .../ic_call_missed_grey600_24dp.png | Bin 0 -> 249 bytes .../ic_call_received_grey600_24dp.png | Bin 0 -> 230 bytes .../ic_call_made_grey600_24dp.png | Bin 0 -> 308 bytes .../ic_call_missed_grey600_24dp.png | Bin 0 -> 359 bytes .../ic_call_received_grey600_24dp.png | Bin 0 -> 322 bytes .../ic_call_made_grey600_24dp.png | Bin 0 -> 386 bytes .../ic_call_missed_grey600_24dp.png | Bin 0 -> 449 bytes .../ic_call_received_grey600_24dp.png | Bin 0 -> 384 bytes res/layout/conversation_item_update.xml | 47 +++++++++++----- .../redphone/RedPhoneService.java | 22 +++----- .../redphone/ui/NotificationBarManager.java | 50 ++++++++++-------- .../securesms/ConversationAdapter.java | 6 +-- .../securesms/ConversationUpdateItem.java | 49 ++++++++++++----- .../securesms/database/MmsSmsColumns.java | 20 +++++++ .../securesms/database/SmsDatabase.java | 40 ++++++++++++++ .../database/model/DisplayRecord.java | 16 ++++++ .../database/model/MessageRecord.java | 6 +++ 21 files changed, 189 insertions(+), 67 deletions(-) create mode 100644 res/drawable-hdpi/ic_call_made_grey600_24dp.png create mode 100644 res/drawable-hdpi/ic_call_missed_grey600_24dp.png create mode 100644 res/drawable-hdpi/ic_call_received_grey600_24dp.png create mode 100644 res/drawable-mdpi/ic_call_made_grey600_24dp.png create mode 100644 res/drawable-mdpi/ic_call_missed_grey600_24dp.png create mode 100644 res/drawable-mdpi/ic_call_received_grey600_24dp.png create mode 100644 res/drawable-xhdpi/ic_call_made_grey600_24dp.png create mode 100644 res/drawable-xhdpi/ic_call_missed_grey600_24dp.png create mode 100644 res/drawable-xhdpi/ic_call_received_grey600_24dp.png create mode 100644 res/drawable-xxhdpi/ic_call_made_grey600_24dp.png create mode 100644 res/drawable-xxhdpi/ic_call_missed_grey600_24dp.png create mode 100644 res/drawable-xxhdpi/ic_call_received_grey600_24dp.png diff --git a/res/drawable-hdpi/ic_call_made_grey600_24dp.png b/res/drawable-hdpi/ic_call_made_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7d0807b0bf8f5e101856ebb441a0532551571023 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?)>`X-8t7bI9O+q6K``*XH+@C1doogvQh z!Oq$XWtO#xE%ASRctOmvHl-s=rFvLdU2U&6t0g;&xk~U~y25=(QvTO6qxkOo(U)JB z2h{97@ilwZ$qy1YH4lAxGEt#$nf{FyW92{WC5A6}ZBD;kb)`Wv8R&EdPgg&ebxsLQ E04<1b3jhEB literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/ic_call_received_grey600_24dp.png b/res/drawable-hdpi/ic_call_received_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..5c9a88d1267de47760941376195f1d2de85458e9 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZK3>dAqwX{BQ3+vmeOgEbxddW?*;UV`o`9xO=~G=WkJm z?djqeVsScIBUORdh$oo$|3-&bSq=^xFRfmZ(V(&4WewYmqQFNc3R8>)7Bfa#3Q7e` z6~5B2ZcYQ6&(jLigy25)Oo4?mk<5XoCYruccC*~XHuuurmZ|*xI$R9hzkJRf%~<*w PXbpp>tDnm{r-UW|CZ9vU literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_call_missed_grey600_24dp.png b/res/drawable-mdpi/ic_call_missed_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..609ef526176a54e7b4a4ae9b955e1e06c440a493 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWO=~G=WkKR z=;`7ZVsZNI<&(Sz6nI<$%@b#N)CR`|v2cE!z^uViJ>fxL%@cdhjT|YtDb1`C&VGqJ z(3&jAqLMO)$7RKBmy`Ra+IO7T!E0E_e?@TmcL%M?EQca)DNdX33nm`nZ;bU*{BwrQ ld~Jt~ygl#JpZ^?+KQnP2_cfXO^a{u?44$rjF6*2UngBuDPecF! literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_call_received_grey600_24dp.png b/res/drawable-mdpi/ic_call_received_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..685982d8e2043c04a67f82cfb13aaa16aeafb327 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1g=CK)Uj~LMH3o);76yi2K%s^g z3=E|P3=FRl7#OT(FffQ0%-I!a1C(G&@^*J&_}|`tWO=~G=WkJm z=jq}YVsZNJ<=wmu20Sf^`i;{Q_DS=%bxf)BaZLT$Ii>Bzt^eBn4)@*uv-C)(%NwY% zgp2R_dEg?m+WE%G*$NZ1`W+{@E1apF@I=m|n7ivvlhXDDCu|pN7kg6^xRqVS#plds Ts}t=&n;1M@{an^LB{Ts5U4BV; literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_call_made_grey600_24dp.png b/res/drawable-xhdpi/ic_call_made_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1e609bb5e6f9bb7e05f897bf8216eec516df8096 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+;1OBOz`!jG!i)^F=12eq z*Lb=(hD02Gd)<+%*+9VI;>0;YOOAhVxZ1nUHa>8-=jwAuF8py2H)j9AuhuwW+4NnP zEgm#5|7TjW)0BM`ydVB`!zxama!ws^jlV9*vJYn26u57zwQT;if4&t&6lD0p@|^E}I`6Eq^P|I~hGF3(gnr^DmfVFo6r3H^+kPE-1s z4U>+&nyPQ{>fEAd>{tCdK4&iI4S1q@z})cClhgz16Ei=3I#?-u*Yzoe&q;p|^eTg=tDnm{r-UW|gcyc( literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_call_received_grey600_24dp.png b/res/drawable-xhdpi/ic_call_received_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..91b5587a8adb5f24313e960030c30fe39da921a0 GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VX;-`;;_Kaj^+;1OBOz`!jG!i)^F=12eq zcX_%vhD02Gd)=3d$&jb*VR_2CXNp;@dz+tsWOuY#+_NJ<;K)q1pH|!(Z+@?Rp|#|; z;rkNaj05(JovPApI~$I4vWkCF4`i=+#(3_@uLIWh6Lwr^&6y|Jabh^jn z@zY4*nfHOPv;NEl;h$9*O!FC+?0L(cY`jljY5~(*hD-I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g$s z6#V7s;uw-~@9j-PzC#8)tO4bk?b;zp2~IN2(T?nS?A$4?Dt*Eq$|wHY-!Om5jb__9 zsj-qAN*xMKU}95cUGQWe`&Xb@(bP=a1w!f^AbKJ+`&OthG9kTW4^4X7R|RT*Da9i zQ(n>knC;b5i^gA;daoroj`J}Uu2GOU&c;-vqoA>zkEu9I!NQ%LwZJ5R!<|`o)A3@H z3sXFlXD$A}Ft=)p;OUj6H~sWFS)N>ZenCgw@{xs&zo3hNBa7gd{|m&+!u#G Ph6019tDnm{r-UW|oVI(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g&? zz`$tf>EalYaqsO7PrfDx0oDuW+4#~Q9eSt{cYLXIsdB~6dl|}xe!V5UU7h>4IXrL8 zbNZ_l_G7IUhf;?^6Pzf&;JK^q!#^(RHHCjf16pm>IA$#Myw6rTXB*SAjALwfEo3tr zt9&jfFJCJ=?QvtAW%~)vsDMw2S8qy282;yt^tdT=b6Tb+Q{NY!Ob?}V1}_?39^PtI zx9VZ>oWy|EwT&vzc$&GUWKC+C%-l3-$)hKYK}*#BbvD_ni>s)vwEU^SdGf%-h9Xb3 zKAtJgMny{&h`f}j-v8j}#O8YwWh|ruK7Q7pE+Py9kd=40Sun5elF{r5}E*960e2; literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_call_received_grey600_24dp.png b/res/drawable-xxhdpi/ic_call_received_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..f4be04c671a959c500991442c88f966ff99d66fe GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw6p}rHd>I(3)EF2VS{N990fib~ zFff!FFfhDIU|_JC!N4G1FlSew4N!t9$=lt9;eUJonf*W>XMsm#F#`j)FbFd;%$g$s z6#U`o;uw-~@9j-Rp+gJ;%m+fI?tj=|*ZN)|FrlGt9h(cQ!5N0~>03lQ_nlm0F+Ht6 zb*bSAg=QY36AM(Eqhtyl_KO5`8()*y@Y8J;pGgrz!U3`EJ01PcdE9zvrT$_rGlP1` z=SDkA@e+w=Osy7G0TULpwOU36G%aRXYGD;HX))7MOR0dy#SBv|_B(#R9&Ovst5v*1 zfvKHyQ9*@*P&@0QLJI|@cE&|TuM~`yb1f>)Qea%pG^yZ|f}lG0q{1QvMRn#$MUNB= z)ww1WCoPydPnh{@l^+j_tvbI@;U)!1b#|d5E&DI-+a1{?SMo literal 0 HcmV?d00001 diff --git a/res/layout/conversation_item_update.xml b/res/layout/conversation_item_update.xml index a3c927e65b..29557e17a1 100644 --- a/res/layout/conversation_item_update.xml +++ b/res/layout/conversation_item_update.xml @@ -1,21 +1,25 @@ + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/conversation_update_item" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center" + android:padding="20dp"> - + + - - + android:textColor="?attr/conversation_group_member_name" + tools:text="Sasha called you"/> + + + diff --git a/src/org/thoughtcrime/redphone/RedPhoneService.java b/src/org/thoughtcrime/redphone/RedPhoneService.java index 7a8a3cb5a4..90732766dd 100644 --- a/src/org/thoughtcrime/redphone/RedPhoneService.java +++ b/src/org/thoughtcrime/redphone/RedPhoneService.java @@ -48,6 +48,7 @@ import org.thoughtcrime.redphone.signaling.SignalingSocket; import org.thoughtcrime.redphone.ui.NotificationBarManager; import org.thoughtcrime.redphone.util.Base64; import org.thoughtcrime.redphone.util.UncaughtExceptionHandlerManager; +import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -92,15 +93,12 @@ public class RedPhoneService extends Service implements CallStateListener, CallS private int state; private byte[] zid; -// private String localNumber; private String remoteNumber; -// private String password; private CallManager currentCallManager; private LockManager lockManager; private UncaughtExceptionHandlerManager uncaughtExceptionHandlerManager; private Handler handler; -// private CallLogger.CallRecord currentCallRecord; private IncomingPstnCallListener pstnCallListener; @Override @@ -163,17 +161,9 @@ public class RedPhoneService extends Service implements CallStateListener, CallS registerReceiver(pstnCallListener, new IntentFilter("android.intent.action.PHONE_STATE")); } -// private void initializeApplicationContext() { -// ApplicationContext context = ApplicationContext.getInstance(); -// context.setContext(this); -// context.setCallStateListener(this); -// } - private void initializeResources() { this.state = RedPhone.STATE_IDLE; this.zid = getZID(); -// this.localNumber = TextSecurePreferences.getLocalNumber(this); -// this.password = TextSecurePreferences.getPushServerPassword(this); this.lockManager = new LockManager(this); } @@ -216,8 +206,8 @@ public class RedPhoneService extends Service implements CallStateListener, CallS this.currentCallManager.start(); NotificationBarManager.setCallInProgress(this); -// -// currentCallRecord = CallLogger.logOutgoingCall(this, remoteNumber); + DatabaseFactory.getSmsDatabase(this).insertOutgoingCall(remoteNumber); + } private void handleBusyCall(Intent intent) { @@ -246,14 +236,14 @@ public class RedPhoneService extends Service implements CallStateListener, CallS } private void handleMissedCall(String remoteNumber) { -// CallLogger.logMissedCall(this, remoteNumber, System.currentTimeMillis()); + DatabaseFactory.getSmsDatabase(this).insertMissedCall(remoteNumber); NotificationBarManager.notifyMissedCall(this, remoteNumber); } private void handleAnswerCall(Intent intent) { state = RedPhone.STATE_ANSWERING; incomingRinger.stop(); -// currentCallRecord = CallLogger.logIncomingCall(this, remoteNumber); + DatabaseFactory.getSmsDatabase(this).insertReceivedCall(remoteNumber); if (currentCallManager != null) { ((ResponderCallManager)this.currentCallManager).answer(true); } @@ -262,7 +252,7 @@ public class RedPhoneService extends Service implements CallStateListener, CallS private void handleDenyCall(Intent intent) { state = RedPhone.STATE_IDLE; incomingRinger.stop(); -// CallLogger.logMissedCall(this, remoteNumber, System.currentTimeMillis()); + DatabaseFactory.getSmsDatabase(this).insertMissedCall(remoteNumber); if(currentCallManager != null) { ((ResponderCallManager)this.currentCallManager).answer(false); } diff --git a/src/org/thoughtcrime/redphone/ui/NotificationBarManager.java b/src/org/thoughtcrime/redphone/ui/NotificationBarManager.java index 675f60fa6f..47c2c4d19a 100644 --- a/src/org/thoughtcrime/redphone/ui/NotificationBarManager.java +++ b/src/org/thoughtcrime/redphone/ui/NotificationBarManager.java @@ -22,9 +22,15 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.net.Uri; +import android.support.v4.app.NotificationCompat; import org.thoughtcrime.redphone.RedPhone; +import org.thoughtcrime.securesms.ConversationActivity; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.Recipients; /** * Manages the state of the RedPhone items in the Android notification bar. @@ -35,7 +41,8 @@ import org.thoughtcrime.securesms.R; public class NotificationBarManager { - private static final int RED_PHONE_NOTIFICATION = 313388; + private static final int RED_PHONE_NOTIFICATION = 313388; + private static final int MISSED_CALL_NOTIFICATION = 313389; public static void setCallEnded(Context context) { NotificationManager notificationManager = (NotificationManager)context @@ -61,26 +68,27 @@ public class NotificationBarManager { } public static void notifyMissedCall(Context context, String remoteNumber) { -// Intent intent = new Intent(DialerActivity.CALL_LOG_ACTION, null, -// context, DialerActivity.class); -// PendingIntent launchIntent = PendingIntent.getActivity(context, 0, intent, 0); -// PersonInfo remoteInfo = PersonInfo.getInstance(context, remoteNumber); + Intent intent = new Intent(context, ConversationActivity.class); + Recipients notifyRecipients = RecipientFactory.getRecipientsFromString(context, remoteNumber, false); + intent.putExtra("recipients", notifyRecipients.getIds()); + intent.putExtra("thread_id", DatabaseFactory.getThreadDatabase(context).getThreadIdFor(notifyRecipients)); + intent.setData((Uri.parse("custom://" + System.currentTimeMillis()))); -// NotificationCompat.Builder builder = new NotificationCompat.Builder(context); -// builder.setSmallIcon(R.drawable.stat_notify_missed_call); -// builder.setWhen(System.currentTimeMillis()); -// builder.setTicker(context -// .getString(R.string.NotificationBarManager_missed_redphone_call_from_s, -// remoteInfo.getName())); -// builder.setContentTitle(context.getString(R.string.NotificationBarManager_missed_redphone_call)); -// builder.setContentText(remoteInfo.getName()); -// builder.setContentIntent(launchIntent); -// builder.setDefaults(Notification.DEFAULT_VIBRATE); -// builder.setAutoCancel(true); -// -// NotificationManager manager = (NotificationManager)context -// .getSystemService(Context.NOTIFICATION_SERVICE); -// -// manager.notify(DialerActivity.MISSED_CALL, builder.build()); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + builder.setSmallIcon(R.drawable.ic_call_missed_grey600_24dp); + builder.setWhen(System.currentTimeMillis()); + builder.setTicker(String.format("Missed call from %s", notifyRecipients.toShortString())); + builder.setContentTitle("Missed Signal call"); + builder.setContentText(String.format("Missed call from %s", notifyRecipients.toShortString())); + builder.setContentIntent(pendingIntent); + builder.setDefaults(Notification.DEFAULT_VIBRATE); + builder.setAutoCancel(true); + + NotificationManager manager = (NotificationManager)context + .getSystemService(Context.NOTIFICATION_SERVICE); + + manager.notify(MISSED_CALL_NOTIFICATION, builder.build()); } } diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java index ed636731e8..370cfc723d 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -164,9 +164,9 @@ public class ConversationAdapter String type = cursor.getString(cursor.getColumnIndexOrThrow(MmsSmsDatabase.TRANSPORT)); MessageRecord messageRecord = getMessageRecord(id, cursor, type); - if (messageRecord.isGroupAction()) return MESSAGE_TYPE_UPDATE; - else if (messageRecord.isOutgoing()) return MESSAGE_TYPE_OUTGOING; - else return MESSAGE_TYPE_INCOMING; + if (messageRecord.isGroupAction() || messageRecord.isCallLog()) return MESSAGE_TYPE_UPDATE; + else if (messageRecord.isOutgoing()) return MESSAGE_TYPE_OUTGOING; + else return MESSAGE_TYPE_INCOMING; } private MessageRecord getMessageRecord(long messageId, Cursor cursor, String type) { diff --git a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java index a8322aa188..b41d36b5c8 100644 --- a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java +++ b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java @@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.Util; @@ -26,8 +27,10 @@ public class ConversationUpdateItem extends LinearLayout private ImageView icon; private TextView body; + private TextView date; private Recipient sender; private MessageRecord messageRecord; + private Locale locale; public ConversationUpdateItem(Context context) { super(context); @@ -43,6 +46,7 @@ public class ConversationUpdateItem extends LinearLayout this.icon = (ImageView)findViewById(R.id.conversation_update_icon); this.body = (TextView)findViewById(R.id.conversation_update_body); + this.date = (TextView)findViewById(R.id.conversation_update_date); setOnClickListener(this); } @@ -54,28 +58,45 @@ public class ConversationUpdateItem extends LinearLayout @NonNull Set batchSelected, boolean groupThread, boolean pushDestination) { - bind(messageRecord); + bind(messageRecord, locale); } - private void bind(@NonNull MessageRecord messageRecord) { + private void bind(@NonNull MessageRecord messageRecord, @NonNull Locale locale) { this.messageRecord = messageRecord; this.sender = messageRecord.getIndividualRecipient(); + this.locale = locale; this.sender.addListener(this); - if (messageRecord.isGroupAction()) { - icon.setImageDrawable(getContext().getResources().getDrawable(R.drawable.ic_group_grey600_24dp)); + if (messageRecord.isGroupAction()) setGroupRecord(messageRecord); + else if (messageRecord.isCallLog()) setCallRecord(messageRecord); + else throw new AssertionError("Neither group no log."); + } - if (messageRecord.isGroupQuit() && messageRecord.isOutgoing()) { - body.setText(R.string.MessageRecord_left_group); - } else if (messageRecord.isGroupQuit()) { - body.setText(getContext().getString(R.string.ConversationItem_group_action_left, sender.toShortString())); - } else { - GroupUtil.GroupDescription description = GroupUtil.getDescription(getContext(), messageRecord.getBody().getBody()); - description.addListener(this); - body.setText(description.toString()); - } + private void setCallRecord(MessageRecord messageRecord) { + if (messageRecord.isIncomingCall()) icon.setImageResource(R.drawable.ic_call_received_grey600_24dp); + else if (messageRecord.isOutgoingCall()) icon.setImageResource(R.drawable.ic_call_made_grey600_24dp); + else icon.setImageResource(R.drawable.ic_call_missed_grey600_24dp); + + body.setText(messageRecord.getDisplayBody()); + date.setText(DateUtils.getExtendedRelativeTimeSpanString(getContext(), locale, messageRecord.getDateReceived())); + date.setVisibility(View.VISIBLE); + } + + private void setGroupRecord(MessageRecord messageRecord) { + icon.setImageResource(R.drawable.ic_group_grey600_24dp); + + if (messageRecord.isGroupQuit() && messageRecord.isOutgoing()) { + body.setText(R.string.MessageRecord_left_group); + } else if (messageRecord.isGroupQuit()) { + body.setText(getContext().getString(R.string.ConversationItem_group_action_left, sender.toShortString())); + } else { + GroupUtil.GroupDescription description = GroupUtil.getDescription(getContext(), messageRecord.getBody().getBody()); + description.addListener(this); + body.setText(description.toString()); } + + date.setVisibility(View.GONE); } @Override @@ -88,7 +109,7 @@ public class ConversationUpdateItem extends LinearLayout Util.runOnMain(new Runnable() { @Override public void run() { - bind(messageRecord); + bind(messageRecord, locale); } }); } diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 9eaceb0bac..fcb24c6660 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -19,6 +19,10 @@ public interface MmsSmsColumns { // Base Types protected static final long BASE_TYPE_MASK = 0x1F; + protected static final long INCOMING_CALL_TYPE = 1; + protected static final long OUTGOING_CALL_TYPE = 2; + protected static final long MISSED_CALL_TYPE = 3; + protected static final long BASE_INBOX_TYPE = 20; protected static final long BASE_OUTBOX_TYPE = 21; protected static final long BASE_SENDING_TYPE = 22; @@ -150,6 +154,22 @@ public interface MmsSmsColumns { return (type & KEY_EXCHANGE_IDENTITY_UPDATE_BIT) != 0; } + public static boolean isCallLog(long type) { + return type == INCOMING_CALL_TYPE || type == OUTGOING_CALL_TYPE || type == MISSED_CALL_TYPE; + } + + public static boolean isIncomingCall(long type) { + return type == INCOMING_CALL_TYPE; + } + + public static boolean isOutgoingCall(long type) { + return type == OUTGOING_CALL_TYPE; + } + + public static boolean isMissedCall(long type) { + return type == MISSED_CALL_TYPE; + } + public static boolean isGroupUpdate(long type) { return (type & GROUP_UPDATE_BIT) != 0; } diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index a5d4175859..784d09655f 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -22,6 +22,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteStatement; +import android.support.annotation.NonNull; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.util.Log; @@ -343,6 +344,45 @@ public class SmsDatabase extends MessagingDatabase { return new Pair<>(newMessageId, record.getThreadId()); } + public @NonNull Pair insertReceivedCall(@NonNull String number) { + return insertCallLog(number, Types.INCOMING_CALL_TYPE, false); + } + + public @NonNull Pair insertOutgoingCall(@NonNull String number) { + return insertCallLog(number, Types.OUTGOING_CALL_TYPE, false); + } + + public @NonNull Pair insertMissedCall(@NonNull String number) { + return insertCallLog(number, Types.MISSED_CALL_TYPE, true); + } + + private @NonNull Pair insertCallLog(@NonNull String number, long type, boolean unread) { + Recipients recipients = RecipientFactory.getRecipientsFromString(context, number, true); + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); + + ContentValues values = new ContentValues(6); + values.put(ADDRESS, number); + values.put(ADDRESS_DEVICE_ID, 1); + values.put(DATE_RECEIVED, System.currentTimeMillis()); + values.put(DATE_SENT, System.currentTimeMillis()); + values.put(READ, unread ? 0 : 1); + values.put(TYPE, type); + values.put(THREAD_ID, threadId); + + SQLiteDatabase db = databaseHelper.getWritableDatabase(); + long messageId = db.insert(TABLE_NAME, null, values); + + DatabaseFactory.getThreadDatabase(context).update(threadId); + notifyConversationListeners(threadId); + jobManager.add(new TrimThreadJob(context, threadId)); + + if (unread) { + DatabaseFactory.getThreadDatabase(context).setUnread(threadId); + } + + return new Pair<>(messageId, threadId); + } + protected Pair insertMessageInbox(IncomingTextMessage message, long type) { if (message.isPreKeyBundle()) { type |= Types.KEY_EXCHANGE_BIT | Types.KEY_EXCHANGE_BUNDLE_BIT; diff --git a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java index 3c0bc3ed44..67c13ff8a4 100644 --- a/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -95,6 +95,22 @@ public abstract class DisplayRecord { return isGroupUpdate() || isGroupQuit(); } + public boolean isCallLog() { + return SmsDatabase.Types.isCallLog(type); + } + + public boolean isIncomingCall() { + return SmsDatabase.Types.isIncomingCall(type); + } + + public boolean isOutgoingCall() { + return SmsDatabase.Types.isOutgoingCall(type); + } + + public boolean isMissedCall() { + return SmsDatabase.Types.isMissedCall(type); + } + public static class Body { private final String body; private final boolean plaintext; diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java index c58a7ab870..e1f9afa7d2 100644 --- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -115,6 +115,12 @@ public abstract class MessageRecord extends DisplayRecord { return emphasisAdded(context.getString(R.string.MessageRecord_left_group)); } else if (isGroupQuit()) { return emphasisAdded(context.getString(R.string.ConversationItem_group_action_left, getIndividualRecipient().toShortString())); + } else if (isIncomingCall()) { + return emphasisAdded(String.format("%s called you", getIndividualRecipient().toShortString())); + } else if (isOutgoingCall()) { + return emphasisAdded(String.format("Called %s", getIndividualRecipient().toShortString())); + } else if (isMissedCall()) { + return emphasisAdded(String.format("Missed call from %s", getIndividualRecipient().toShortString())); } else if (getBody().getBody().length() > MAX_DISPLAY_LENGTH) { return new SpannableString(getBody().getBody().substring(0, MAX_DISPLAY_LENGTH)); }