From f0b2cc559026871c1b4d8e008666afb590553004 Mon Sep 17 00:00:00 2001 From: Christoph Haefner Date: Tue, 19 May 2015 10:24:08 +0200 Subject: [PATCH] Added WearReplyReceiver --- AndroidManifest.xml | 8 ++ res/drawable-hdpi/ic_reply.png | Bin 0 -> 462 bytes res/drawable-mdpi/ic_reply.png | Bin 0 -> 343 bytes res/drawable-xhdpi/ic_reply.png | Bin 0 -> 561 bytes res/drawable-xxhdpi/ic_reply.png | Bin 0 -> 775 bytes res/values/strings.xml | 8 ++ .../notifications/MessageNotifier.java | 20 +++- .../notifications/NotificationState.java | 21 ++++- .../notifications/WearReplyReceiver.java | 86 ++++++++++++++++++ 9 files changed, 137 insertions(+), 6 deletions(-) create mode 100644 res/drawable-hdpi/ic_reply.png create mode 100644 res/drawable-mdpi/ic_reply.png create mode 100644 res/drawable-xhdpi/ic_reply.png create mode 100644 res/drawable-xxhdpi/ic_reply.png create mode 100644 src/org/thoughtcrime/securesms/notifications/WearReplyReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3e9bb545e..71e173e18 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -316,6 +316,14 @@ + + + + + + diff --git a/res/drawable-hdpi/ic_reply.png b/res/drawable-hdpi/ic_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..b3bae928957e22b4127367b9b0be667752df35de GIT binary patch literal 462 zcmV;<0WtoGP)fGKoCV)%fA$m6hH%M zfC5YdDIjhj|8~kS1=t19fE#cFE&vLk0CGpd5+8}p<1Vu+%}67J#KJwyYhjZ_ZW{wI z00S@p0|*kJ>$>-70U*A>;SeRjn&RmIYm27>Xo#l)Xo;r)Xo_D9pe=q8KnUVz1B4=e z7C=bi#kL;Br?~!OaNauS?rZ?3^yXW*z}(>1C15U)v=M+3AXhrT$~i9pKLBYdMXXS; zIsAm@rZIoeWK$rX0w9!?gj5OQK#71NM2;xrloV2g_@WImfxsI{CKUAzYxaYNkoKt| z{t15@lS){ZJ)0Agig-yRq&30?>H?SUR*qa+P`eN-op7IWBt%AUqhyHY)nM~72Z)7z z{;PiAdpzSCUek7?gu+h#5&JNS#!+g;%XZoagmf6JZ~Dz#<@I~OBSfM4TSar&Q8#lM z5L@;Q2kEp+Vz#J%ulJFtqXvkwhz-C148Q;;+phov0FBs}aEBSND*ylh07*qoM6N<$ Ef?-s=5C8xG literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_reply.png b/res/drawable-mdpi/ic_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..ce00dbc4b436cb7b84cfea033ad660f96bb306b9 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GKRsO>Ln>}1B}lL?PFT_O|NsBbO$JM!8BEN!oG^>?NLEQX zgQ>3iO~xzR=BTh=I8?Mq)9+9Xz?hgCKopV_qG57TJY(G)P zFtz5NOh#31XE=q(=M%&bP0l+XkK#q@oT literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_reply.png b/res/drawable-xhdpi/ic_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..31df111267643cb59e5a7649734e4225182af620 GIT binary patch literal 561 zcmV-10?z%3P)^q;yebT8?t2+HZJ9ca+3d1lA z!!QiPFr=90d4r|lx0ETu!^=BVwK@UX!ix&f7+y?(*6<<%G>2ywpglaRfE>cJ3CJZp zi-4TMM;DM=_^1MM3?EHEuHmBy$T@tlfZW3)E@Ai+)cDJ1U-a4JoEy{$NYL{=)EVj% zgp5fAKzIy&gnCFcYEecDB6@KF6drqC!)Xo*IE0P}mudJPCX#Sw6`(ZyB`Bd&dmtjf zD|FIsjkmxxwePaIcmz;=V>ft& zYwlEShPWhL^e(oKE5sAL_Yu-2+is9?B%COCOV=n=3gD6eZSG?P7dsCSm>6{n&@Msj zL`bUy(IYYKw}Tj({!!8}48t%C!!TCLw*UhG4C~4cD99Zp00000NkvXXu0mjf+?nRC literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_reply.png b/res/drawable-xxhdpi/ic_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..119006014d5e9c4b06670e88ed1f18633475172a GIT binary patch literal 775 zcmV+i1Ni)jP)X1-Jn> zKm+Cu+))F$hujHwTtHGlQb1Aw1)u_O0WQFN->?}nVF-$|(!Sd7d1iKW@Ql5BpZ$$i zX&L|k0000000000004l891e%qUPz)`_?K4JwcJy;r10(X&C05#M%58M0>XwbFQE4D zr3FL?Usgbr@FfLA3SUk@wD6?_L=0a>K-BOh1Vj$MxPa*47ZpJG1qBd(K>>tcP=JN+ zp5m!5(KnCTE5E|tn94( zNP@msDPUp4&aIU@zn1DTZQ$@9b7SRt?w-*S{$IF&a})7%F#;-G?QBiLR$f5mOHH4+ zPp9k+E#Z$^LG>nKkP;AVleJGhA^QZ~H82KmWM5LFV+bnT6F%mg6PSdLn3zq#2bm!# zO-_Ak9TD)qLw#Z+R-Sh`hN5hfaKN5$CbtR-CSjf9UA64X&|nfaGIPMpb3*^rrYIeK z@!x-wu5YcJD9#1#l+9y83H@_-rB)Z0@ZN`x%yqf2x?D-_gq4OPtBXH$@w!}OuFs2x zp>Bp7mzon&Yt31o)l1&o?`FE`dkH%c3Ar1^T3Wz^oAxdIASB^yrms7Z7m#jxpIV-Z zgzM(_BgkX%9(^u52`@o{aZGsowEEd3iOpgJs7dhE(KF^IulF{s{jYNTepm3um3qRM zVdy3Wzs-4us4Lw1R3zN~=Q9uf^Av}-I)NcTLBjBlUg10LNl!&cJQFT0;ZeZ56nsC& zDLI*k@&Y~Keo48R^LS$0h%xddzFy^Yb2U9cc%KkUKr{)m2eYC`kUkj~L4y3z#M&h+ z;%sQNiCLB!|8?Transport icon + + Reply + + Yes + No + OK + Thanks + diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index ef3cf8cae..ef82154ce 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -36,6 +36,7 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.Action; import android.support.v4.app.NotificationCompat.BigTextStyle; import android.support.v4.app.NotificationCompat.InboxStyle; +import android.support.v4.app.RemoteInput; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -86,6 +87,8 @@ public class MessageNotifier { private volatile static long visibleThread = -1; + public static final String EXTRA_VOICE_REPLY = "extra_voice_reply"; + public static void setVisibleThread(long threadId) { visibleThread = threadId; } @@ -222,9 +225,22 @@ public class MessageNotifier { Action markAsReadAction = new Action(R.drawable.check, context.getString(R.string.MessageNotifier_mark_read), notificationState.getMarkAsReadIntent(context, masterSecret)); + + Action replyAction = new Action(R.drawable.ic_reply_white_36dp, + context.getString(R.string.MessageNotifier_reply), + notifications.get(0).getReplyIntent(context)); + + Action wearableReplyAction = new Action.Builder(R.drawable.ic_reply, + context.getString(R.string.wear_reply_label), + notificationState.getReplyIntent(context, masterSecret, recipient.getRecipientId())) + .addRemoteInput(new RemoteInput.Builder(EXTRA_VOICE_REPLY).setLabel(context.getString(R.string.wear_reply_label)).build()) + .build(); + builder.addAction(markAsReadAction); - builder.addAction(new Action(R.drawable.ic_reply_white_36dp, context.getString(R.string.MessageNotifier_reply), notifications.get(0).getReplyIntent(context))); - builder.extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction)); + builder.addAction(replyAction); + + builder.extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction) + .addAction(wearableReplyAction)); } SpannableStringBuilder content = new SpannableStringBuilder(); diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationState.java b/src/org/thoughtcrime/securesms/notifications/NotificationState.java index 3fc3bc15d..52ac5563b 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationState.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationState.java @@ -4,11 +4,11 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Bundle; import android.support.annotation.Nullable; import android.util.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase; import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.VibrateState; import org.thoughtcrime.securesms.recipients.Recipients; @@ -71,6 +71,19 @@ public class NotificationState { } public PendingIntent getMarkAsReadIntent(Context context, MasterSecret masterSecret) { + Bundle extras = new Bundle(); + extras.putParcelable("master_secret", masterSecret); + return craftIntent(context, MarkReadReceiver.CLEAR_ACTION, extras); + } + + public PendingIntent getReplyIntent(Context context, MasterSecret masterSecret, long recipientId) { + Bundle extras = new Bundle(); + extras.putParcelable("master_secret", masterSecret); + extras.putLong("recipient_id", recipientId); + return craftIntent(context, WearReplyReceiver.REPLY_ACTION, extras); + } + + private PendingIntent craftIntent(Context context, String intentAction, Bundle extras) { long[] threadArray = new long[threads.size()]; int index = 0; @@ -79,16 +92,16 @@ public class NotificationState { threadArray[index++] = thread; } - Intent intent = new Intent(MarkReadReceiver.CLEAR_ACTION); + Intent intent = new Intent(intentAction); intent.putExtra("thread_ids", threadArray); - intent.putExtra("master_secret", masterSecret); + intent.putExtras(extras); intent.setPackage(context.getPackageName()); // XXX : This is an Android bug. If we don't pull off the extra // once before handing off the PendingIntent, the array will be // truncated to one element when the PendingIntent fires. Thanks guys! Log.w("NotificationState", "Pending array off intent length: " + - intent.getLongArrayExtra("thread_ids").length); + intent.getLongArrayExtra("thread_ids").length); return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } diff --git a/src/org/thoughtcrime/securesms/notifications/WearReplyReceiver.java b/src/org/thoughtcrime/securesms/notifications/WearReplyReceiver.java new file mode 100644 index 000000000..6929c81f1 --- /dev/null +++ b/src/org/thoughtcrime/securesms/notifications/WearReplyReceiver.java @@ -0,0 +1,86 @@ +/** + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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.notifications; + +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.v4.app.RemoteInput; +import android.util.Log; + +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.RecipientProvider; +import org.thoughtcrime.securesms.recipients.Recipients; +import org.thoughtcrime.securesms.sms.MessageSender; +import org.thoughtcrime.securesms.sms.OutgoingTextMessage; + +/** + * Get the response text from the Wearable Device and sends an message as a reply + * + * @author Alix Ducros (Ported to TextSecure-Codebase by Christoph Haefner) + */ +public class WearReplyReceiver extends BroadcastReceiver { + + public static final String TAG = WearReplyReceiver.class.getSimpleName(); + public static final String REPLY_ACTION = "org.thoughtcrime.securesms.notifications.WEAR_REPLY"; + + @Override + public void onReceive(final Context context, Intent intent) { + if (!intent.getAction().equals(REPLY_ACTION)) + return; + + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput == null) + return; + + final long[] threadIds = intent.getLongArrayExtra("thread_ids"); + final MasterSecret masterSecret = intent.getParcelableExtra("master_secret"); + final long recipientId = intent.getLongExtra("recipient_id", -1); + final CharSequence responseText = remoteInput.getCharSequence(MessageNotifier.EXTRA_VOICE_REPLY); + + final Recipients recipients = RecipientFactory.getRecipientsForIds(context, new long[]{recipientId}, false); + + if (threadIds != null && masterSecret != null) { + + ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)) + .cancel(MessageNotifier.NOTIFICATION_ID); + + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + for (long threadId : threadIds) { + Log.w(TAG, "Marking as read: " + threadId); + DatabaseFactory.getThreadDatabase(context).setRead(threadId); + } + + OutgoingTextMessage reply = new OutgoingTextMessage(recipients, responseText.toString()); + MessageSender.send(context, masterSecret, reply, threadIds[0], false); + + MessageNotifier.updateNotification(context, masterSecret); + return null; + } + }.execute(); + } + } +}