1package eu.siacs.conversations.ui;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Set;
6import java.util.concurrent.ConcurrentLinkedQueue;
7
8import net.java.otr4j.session.SessionStatus;
9import eu.siacs.conversations.R;
10import eu.siacs.conversations.crypto.PgpEngine;
11import eu.siacs.conversations.entities.Account;
12import eu.siacs.conversations.entities.Contact;
13import eu.siacs.conversations.entities.Conversation;
14import eu.siacs.conversations.entities.Message;
15import eu.siacs.conversations.entities.MucOptions;
16import eu.siacs.conversations.entities.Presences;
17import eu.siacs.conversations.services.XmppConnectionService;
18import eu.siacs.conversations.ui.EditMessage.OnEnterPressed;
19import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
20import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
21import eu.siacs.conversations.ui.adapter.MessageAdapter;
22import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
23import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
24import eu.siacs.conversations.utils.UIHelper;
25import android.app.AlertDialog;
26import android.app.Fragment;
27import android.app.PendingIntent;
28import android.content.Context;
29import android.content.DialogInterface;
30import android.content.Intent;
31import android.content.IntentSender;
32import android.content.IntentSender.SendIntentException;
33import android.os.Bundle;
34import android.text.Editable;
35import android.text.Selection;
36import android.view.Gravity;
37import android.view.KeyEvent;
38import android.view.LayoutInflater;
39import android.view.View;
40import android.view.View.OnClickListener;
41import android.view.ViewGroup;
42import android.view.inputmethod.EditorInfo;
43import android.view.inputmethod.InputMethodManager;
44import android.widget.AbsListView.OnScrollListener;
45import android.widget.TextView.OnEditorActionListener;
46import android.widget.AbsListView;
47
48import android.widget.ListView;
49import android.widget.ImageButton;
50import android.widget.RelativeLayout;
51import android.widget.TextView;
52import android.widget.Toast;
53
54public class ConversationFragment extends Fragment {
55
56 protected Conversation conversation;
57 protected ListView messagesView;
58 protected LayoutInflater inflater;
59 protected List<Message> messageList = new ArrayList<Message>();
60 protected MessageAdapter messageListAdapter;
61 protected Contact contact;
62
63 protected String queuedPqpMessage = null;
64
65 private EditMessage mEditMessage;
66 private ImageButton mSendButton;
67 private String pastedText = null;
68 private RelativeLayout snackbar;
69 private TextView snackbarMessage;
70 private TextView snackbarAction;
71
72 private boolean messagesLoaded = false;
73
74 private IntentSender askForPassphraseIntent = null;
75
76
77 private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<Message>();
78 private boolean mDecryptJobRunning = false;
79
80 private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
81
82 @Override
83 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
84 if (actionId == EditorInfo.IME_ACTION_SEND) {
85 InputMethodManager imm = (InputMethodManager) v.getContext()
86 .getSystemService(Context.INPUT_METHOD_SERVICE);
87 imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
88 sendMessage();
89 return true;
90 } else {
91 return false;
92 }
93 }
94 };
95
96 private OnClickListener mSendButtonListener = new OnClickListener() {
97
98 @Override
99 public void onClick(View v) {
100 sendMessage();
101 }
102 };
103 protected OnClickListener clickToDecryptListener = new OnClickListener() {
104
105 @Override
106 public void onClick(View v) {
107 if (activity.hasPgp() && askForPassphraseIntent != null) {
108 try {
109 getActivity().startIntentSenderForResult(
110 askForPassphraseIntent,
111 ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
112 0, 0);
113 } catch (SendIntentException e) {
114 //
115 }
116 }
117 }
118 };
119
120 private OnClickListener clickToMuc = new OnClickListener() {
121
122 @Override
123 public void onClick(View v) {
124 Intent intent = new Intent(getActivity(),
125 ConferenceDetailsActivity.class);
126 intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
127 intent.putExtra("uuid", conversation.getUuid());
128 startActivity(intent);
129 }
130 };
131
132 private OnClickListener leaveMuc = new OnClickListener() {
133
134 @Override
135 public void onClick(View v) {
136 activity.endConversation(conversation);
137 }
138 };
139
140 private OnClickListener joinMuc = new OnClickListener() {
141
142 @Override
143 public void onClick(View v) {
144 activity.xmppConnectionService.joinMuc(conversation);
145 }
146 };
147
148 private OnClickListener enterPassword = new OnClickListener() {
149
150 @Override
151 public void onClick(View v) {
152 MucOptions muc = conversation.getMucOptions();
153 String password = muc.getPassword();
154 if (password == null) {
155 password = "";
156 }
157 activity.quickPasswordEdit(password, new OnValueEdited() {
158
159 @Override
160 public void onValueEdited(String value) {
161 activity.xmppConnectionService.providePasswordForMuc(
162 conversation, value);
163 }
164 });
165 }
166 };
167
168 private OnScrollListener mOnScrollListener = new OnScrollListener() {
169
170 @Override
171 public void onScrollStateChanged(AbsListView view, int scrollState) {
172 // TODO Auto-generated method stub
173
174 }
175
176 @Override
177 public void onScroll(AbsListView view, int firstVisibleItem,
178 int visibleItemCount, int totalItemCount) {
179 if (firstVisibleItem == 0 && messagesLoaded) {
180 long timestamp = messageList.get(0).getTimeSent();
181 messagesLoaded = false;
182 int size = activity.xmppConnectionService.loadMoreMessages(
183 conversation, timestamp);
184 messageList.clear();
185 messageList.addAll(conversation.getMessages());
186 updateStatusMessages();
187 messageListAdapter.notifyDataSetChanged();
188 if (size != 0) {
189 messagesLoaded = true;
190 }
191 messagesView.setSelectionFromTop(size + 1, 0);
192 }
193 }
194 };
195
196 private ConversationActivity activity;
197
198 private void sendMessage() {
199 if (this.conversation == null) {
200 return;
201 }
202 if (mEditMessage.getText().length() < 1) {
203 if (this.conversation.getMode() == Conversation.MODE_MULTI) {
204 conversation.setNextPresence(null);
205 updateChatMsgHint();
206 }
207 return;
208 }
209 Message message = new Message(conversation, mEditMessage.getText()
210 .toString(), conversation.getNextEncryption(activity
211 .forceEncryption()));
212 if (conversation.getMode() == Conversation.MODE_MULTI) {
213 if (conversation.getNextPresence() != null) {
214 message.setPresence(conversation.getNextPresence());
215 message.setType(Message.TYPE_PRIVATE);
216 conversation.setNextPresence(null);
217 }
218 }
219 if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_OTR) {
220 sendOtrMessage(message);
221 } else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_PGP) {
222 sendPgpMessage(message);
223 } else {
224 sendPlainTextMessage(message);
225 }
226 }
227
228 public void updateChatMsgHint() {
229 if (conversation.getMode() == Conversation.MODE_MULTI
230 && conversation.getNextPresence() != null) {
231 this.mEditMessage.setHint(getString(
232 R.string.send_private_message_to,
233 conversation.getNextPresence()));
234 } else {
235 switch (conversation.getNextEncryption(activity.forceEncryption())) {
236 case Message.ENCRYPTION_NONE:
237 mEditMessage
238 .setHint(getString(R.string.send_plain_text_message));
239 break;
240 case Message.ENCRYPTION_OTR:
241 mEditMessage.setHint(getString(R.string.send_otr_message));
242 break;
243 case Message.ENCRYPTION_PGP:
244 mEditMessage.setHint(getString(R.string.send_pgp_message));
245 break;
246 default:
247 break;
248 }
249 }
250 }
251
252 @Override
253 public View onCreateView(final LayoutInflater inflater,
254 ViewGroup container, Bundle savedInstanceState) {
255 final View view = inflater.inflate(R.layout.fragment_conversation,
256 container, false);
257 mEditMessage = (EditMessage) view.findViewById(R.id.textinput);
258 mEditMessage.setOnClickListener(new OnClickListener() {
259
260 @Override
261 public void onClick(View v) {
262 activity.hideConversationsOverview();
263 }
264 });
265 mEditMessage.setOnEditorActionListener(mEditorActionListener);
266 mEditMessage.setOnEnterPressedListener(new OnEnterPressed() {
267
268 @Override
269 public void onEnterPressed() {
270 sendMessage();
271 }
272 });
273
274 mSendButton = (ImageButton) view.findViewById(R.id.textSendButton);
275 mSendButton.setOnClickListener(this.mSendButtonListener);
276
277 snackbar = (RelativeLayout) view.findViewById(R.id.snackbar);
278 snackbarMessage = (TextView) view.findViewById(R.id.snackbar_message);
279 snackbarAction = (TextView) view.findViewById(R.id.snackbar_action);
280
281 messagesView = (ListView) view.findViewById(R.id.messages_view);
282 messagesView.setOnScrollListener(mOnScrollListener);
283 messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
284 messageListAdapter = new MessageAdapter(
285 (ConversationActivity) getActivity(), this.messageList);
286 messageListAdapter
287 .setOnContactPictureClicked(new OnContactPictureClicked() {
288
289 @Override
290 public void onContactPictureClicked(Message message) {
291 if (message.getStatus() <= Message.STATUS_RECEIVED) {
292 if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
293 if (message.getPresence() != null) {
294 highlightInConference(message.getPresence());
295 } else {
296 highlightInConference(message
297 .getCounterpart());
298 }
299 } else {
300 Contact contact = message.getConversation()
301 .getContact();
302 if (contact.showInRoster()) {
303 activity.switchToContactDetails(contact);
304 } else {
305 activity.showAddToRosterDialog(message
306 .getConversation());
307 }
308 }
309 }
310 }
311 });
312 messageListAdapter
313 .setOnContactPictureLongClicked(new OnContactPictureLongClicked() {
314
315 @Override
316 public void onContactPictureLongClicked(Message message) {
317 if (message.getStatus() <= Message.STATUS_RECEIVED) {
318 if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
319 if (message.getPresence() != null) {
320 privateMessageWith(message.getPresence());
321 } else {
322 privateMessageWith(message.getCounterpart());
323 }
324 }
325 }
326 }
327 });
328 messagesView.setAdapter(messageListAdapter);
329
330 return view;
331 }
332
333 protected void privateMessageWith(String counterpart) {
334 this.mEditMessage.setText("");
335 this.conversation.setNextPresence(counterpart);
336 updateChatMsgHint();
337 }
338
339 protected void highlightInConference(String nick) {
340 String oldString = mEditMessage.getText().toString().trim();
341 if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) {
342 mEditMessage.getText().insert(0, nick + ": ");
343 } else {
344 if (mEditMessage.getText().charAt(
345 mEditMessage.getSelectionStart() - 1) != ' ') {
346 nick = " " + nick;
347 }
348 mEditMessage.getText().insert(mEditMessage.getSelectionStart(),
349 nick + " ");
350 }
351 }
352
353 @Override
354 public void onStart() {
355 super.onStart();
356 this.activity = (ConversationActivity) getActivity();
357 if (activity.xmppConnectionServiceBound) {
358 this.onBackendConnected();
359 }
360 }
361
362 @Override
363 public void onStop() {
364 mDecryptJobRunning = false;
365 super.onStop();
366 if (this.conversation != null) {
367 this.conversation.setNextMessage(mEditMessage.getText().toString());
368 }
369 }
370
371 public void onBackendConnected() {
372 this.activity = (ConversationActivity) getActivity();
373 this.conversation = activity.getSelectedConversation();
374 if (this.conversation == null) {
375 return;
376 }
377 String oldString = conversation.getNextMessage().trim();
378 if (this.pastedText == null) {
379 this.mEditMessage.setText(oldString);
380 } else {
381
382 if (oldString.isEmpty()) {
383 mEditMessage.setText(pastedText);
384 } else {
385 mEditMessage.setText(oldString + " " + pastedText);
386 }
387 pastedText = null;
388 }
389 int position = mEditMessage.length();
390 Editable etext = mEditMessage.getText();
391 Selection.setSelection(etext, position);
392 if (activity.isConversationsOverviewHideable()) {
393 if (!activity.shouldPaneBeOpen()) {
394 activity.hideConversationsOverview();
395 activity.openConversation(conversation);
396 }
397 }
398 if (this.conversation.getMode() == Conversation.MODE_MULTI) {
399 conversation.setNextPresence(null);
400 }
401 updateMessages();
402 }
403
404 public void updateMessages() {
405 if (getView() == null) {
406 return;
407 }
408 hideSnackbar();
409 final ConversationActivity activity = (ConversationActivity) getActivity();
410 if (this.conversation != null) {
411 final Contact contact = this.conversation.getContact();
412 if (this.conversation.isMuted()) {
413 showSnackbar(R.string.notifications_disabled, R.string.enable,
414 new OnClickListener() {
415
416 @Override
417 public void onClick(View v) {
418 conversation.setMutedTill(0);
419 activity.xmppConnectionService.databaseBackend
420 .updateConversation(conversation);
421 updateMessages();
422 }
423 });
424 } else if (!contact.showInRoster()
425 && contact
426 .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
427 showSnackbar(R.string.contact_added_you, R.string.add_back,
428 new OnClickListener() {
429
430 @Override
431 public void onClick(View v) {
432 activity.xmppConnectionService
433 .createContact(contact);
434 activity.switchToContactDetails(contact);
435 }
436 });
437 }
438 for (Message message : this.conversation.getMessages()) {
439 if ((message.getEncryption() == Message.ENCRYPTION_PGP)
440 && ((message.getStatus() == Message.STATUS_RECEIVED) || (message
441 .getStatus() == Message.STATUS_SEND))) {
442 if (!mEncryptedMessages.contains(message)) {
443 mEncryptedMessages.add(message);
444 }
445 }
446 }
447 decryptNext();
448 this.messageList.clear();
449 if (this.conversation.getMessages().size() == 0) {
450 messagesLoaded = false;
451 } else {
452 this.messageList.addAll(this.conversation.getMessages());
453 messagesLoaded = true;
454 updateStatusMessages();
455 }
456 this.messageListAdapter.notifyDataSetChanged();
457 if (conversation.getMode() == Conversation.MODE_SINGLE) {
458 if (messageList.size() >= 1) {
459 makeFingerprintWarning(conversation.getLatestEncryption());
460 }
461 } else {
462 if (!conversation.getMucOptions().online()
463 && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
464 int error = conversation.getMucOptions().getError();
465 switch (error) {
466 case MucOptions.ERROR_NICK_IN_USE:
467 showSnackbar(R.string.nick_in_use, R.string.edit,
468 clickToMuc);
469 break;
470 case MucOptions.ERROR_ROOM_NOT_FOUND:
471 showSnackbar(R.string.conference_not_found,
472 R.string.leave, leaveMuc);
473 break;
474 case MucOptions.ERROR_PASSWORD_REQUIRED:
475 showSnackbar(R.string.conference_requires_password,
476 R.string.enter_password, enterPassword);
477 break;
478 case MucOptions.ERROR_BANNED:
479 showSnackbar(R.string.conference_banned,
480 R.string.leave, leaveMuc);
481 break;
482 case MucOptions.ERROR_MEMBERS_ONLY:
483 showSnackbar(R.string.conference_members_only,
484 R.string.leave, leaveMuc);
485 break;
486 case MucOptions.KICKED_FROM_ROOM:
487 showSnackbar(R.string.conference_kicked, R.string.join,
488 joinMuc);
489 break;
490 default:
491 break;
492 }
493 }
494 }
495 getActivity().invalidateOptionsMenu();
496 updateChatMsgHint();
497 if (!activity.shouldPaneBeOpen()) {
498 activity.xmppConnectionService.markRead(conversation, true);
499 activity.updateConversationList();
500 }
501 this.updateSendButton();
502 }
503 }
504
505 private void decryptNext() {
506 Message next = this.mEncryptedMessages.peek();
507 PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
508
509 if (next!=null && engine != null && !mDecryptJobRunning) {
510 mDecryptJobRunning = true;
511 engine.decrypt(next, new UiCallback<Message>() {
512
513 @Override
514 public void userInputRequried(PendingIntent pi, Message message) {
515 mDecryptJobRunning = false;
516 askForPassphraseIntent = pi.getIntentSender();
517 showSnackbar(R.string.openpgp_messages_found,
518 R.string.decrypt, clickToDecryptListener);
519 }
520
521 @Override
522 public void success(Message message) {
523 mDecryptJobRunning = false;
524 mEncryptedMessages.remove();
525 activity.xmppConnectionService.updateMessage(message);
526 }
527
528 @Override
529 public void error(int error, Message message) {
530 message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
531 mDecryptJobRunning = false;
532 mEncryptedMessages.remove();
533 activity.xmppConnectionService.updateConversationUi();
534 }
535 });
536 }
537 }
538
539 private void messageSent() {
540 int size = this.messageList.size();
541 messagesView.setSelection(size - 1);
542 mEditMessage.setText("");
543 updateChatMsgHint();
544 }
545
546 public void updateSendButton() {
547 Conversation c = this.conversation;
548 if (activity.useSendButtonToIndicateStatus() && c != null
549 && c.getAccount().getStatus() == Account.STATUS_ONLINE) {
550 if (c.getMode() == Conversation.MODE_SINGLE) {
551 switch (c.getContact().getMostAvailableStatus()) {
552 case Presences.CHAT:
553 this.mSendButton
554 .setImageResource(R.drawable.ic_action_send_now_online);
555 break;
556 case Presences.ONLINE:
557 this.mSendButton
558 .setImageResource(R.drawable.ic_action_send_now_online);
559 break;
560 case Presences.AWAY:
561 this.mSendButton
562 .setImageResource(R.drawable.ic_action_send_now_away);
563 break;
564 case Presences.XA:
565 this.mSendButton
566 .setImageResource(R.drawable.ic_action_send_now_away);
567 break;
568 case Presences.DND:
569 this.mSendButton
570 .setImageResource(R.drawable.ic_action_send_now_dnd);
571 break;
572 default:
573 this.mSendButton
574 .setImageResource(R.drawable.ic_action_send_now_offline);
575 break;
576 }
577 } else if (c.getMode() == Conversation.MODE_MULTI) {
578 if (c.getMucOptions().online()) {
579 this.mSendButton
580 .setImageResource(R.drawable.ic_action_send_now_online);
581 } else {
582 this.mSendButton
583 .setImageResource(R.drawable.ic_action_send_now_offline);
584 }
585 } else {
586 this.mSendButton
587 .setImageResource(R.drawable.ic_action_send_now_offline);
588 }
589 } else {
590 this.mSendButton
591 .setImageResource(R.drawable.ic_action_send_now_offline);
592 }
593 }
594
595 protected void updateStatusMessages() {
596 if (conversation.getMode() == Conversation.MODE_SINGLE) {
597 for (int i = this.messageList.size() - 1; i >= 0; --i) {
598 if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) {
599 return;
600 } else {
601 if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
602 this.messageList.add(i + 1,
603 Message.createStatusMessage(conversation));
604 return;
605 }
606 }
607 }
608 }
609 }
610
611 protected void makeFingerprintWarning(int latestEncryption) {
612 Set<String> knownFingerprints = conversation.getContact()
613 .getOtrFingerprints();
614 if ((latestEncryption == Message.ENCRYPTION_OTR)
615 && (conversation.hasValidOtrSession()
616 && (!conversation.isMuted())
617 && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
618 .contains(conversation.getOtrFingerprint())))) {
619 showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
620 new OnClickListener() {
621
622 @Override
623 public void onClick(View v) {
624 if (conversation.getOtrFingerprint() != null) {
625 AlertDialog dialog = UIHelper
626 .getVerifyFingerprintDialog(
627 (ConversationActivity) getActivity(),
628 conversation, snackbar);
629 dialog.show();
630 }
631 }
632 });
633 }
634 }
635
636 protected void showSnackbar(int message, int action,
637 OnClickListener clickListener) {
638 snackbar.setVisibility(View.VISIBLE);
639 snackbar.setOnClickListener(null);
640 snackbarMessage.setText(message);
641 snackbarMessage.setOnClickListener(null);
642 snackbarAction.setText(action);
643 snackbarAction.setOnClickListener(clickListener);
644 }
645
646 protected void hideSnackbar() {
647 snackbar.setVisibility(View.GONE);
648 }
649
650 protected void sendPlainTextMessage(Message message) {
651 ConversationActivity activity = (ConversationActivity) getActivity();
652 activity.xmppConnectionService.sendMessage(message);
653 messageSent();
654 }
655
656 protected void sendPgpMessage(final Message message) {
657 final ConversationActivity activity = (ConversationActivity) getActivity();
658 final XmppConnectionService xmppService = activity.xmppConnectionService;
659 final Contact contact = message.getConversation().getContact();
660 if (activity.hasPgp()) {
661 if (conversation.getMode() == Conversation.MODE_SINGLE) {
662 if (contact.getPgpKeyId() != 0) {
663 xmppService.getPgpEngine().hasKey(contact,
664 new UiCallback<Contact>() {
665
666 @Override
667 public void userInputRequried(PendingIntent pi,
668 Contact contact) {
669 activity.runIntent(
670 pi,
671 ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
672 }
673
674 @Override
675 public void success(Contact contact) {
676 messageSent();
677 activity.encryptTextMessage(message);
678 }
679
680 @Override
681 public void error(int error, Contact contact) {
682
683 }
684 });
685
686 } else {
687 showNoPGPKeyDialog(false,
688 new DialogInterface.OnClickListener() {
689
690 @Override
691 public void onClick(DialogInterface dialog,
692 int which) {
693 conversation
694 .setNextEncryption(Message.ENCRYPTION_NONE);
695 xmppService.databaseBackend
696 .updateConversation(conversation);
697 message.setEncryption(Message.ENCRYPTION_NONE);
698 xmppService.sendMessage(message);
699 messageSent();
700 }
701 });
702 }
703 } else {
704 if (conversation.getMucOptions().pgpKeysInUse()) {
705 if (!conversation.getMucOptions().everybodyHasKeys()) {
706 Toast warning = Toast
707 .makeText(getActivity(),
708 R.string.missing_public_keys,
709 Toast.LENGTH_LONG);
710 warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
711 warning.show();
712 }
713 activity.encryptTextMessage(message);
714 messageSent();
715 } else {
716 showNoPGPKeyDialog(true,
717 new DialogInterface.OnClickListener() {
718
719 @Override
720 public void onClick(DialogInterface dialog,
721 int which) {
722 conversation
723 .setNextEncryption(Message.ENCRYPTION_NONE);
724 message.setEncryption(Message.ENCRYPTION_NONE);
725 xmppService.databaseBackend
726 .updateConversation(conversation);
727 xmppService.sendMessage(message);
728 messageSent();
729 }
730 });
731 }
732 }
733 } else {
734 activity.showInstallPgpDialog();
735 }
736 }
737
738 public void showNoPGPKeyDialog(boolean plural,
739 DialogInterface.OnClickListener listener) {
740 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
741 builder.setIconAttribute(android.R.attr.alertDialogIcon);
742 if (plural) {
743 builder.setTitle(getString(R.string.no_pgp_keys));
744 builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));
745 } else {
746 builder.setTitle(getString(R.string.no_pgp_key));
747 builder.setMessage(getText(R.string.contact_has_no_pgp_key));
748 }
749 builder.setNegativeButton(getString(R.string.cancel), null);
750 builder.setPositiveButton(getString(R.string.send_unencrypted),
751 listener);
752 builder.create().show();
753 }
754
755 protected void sendOtrMessage(final Message message) {
756 final ConversationActivity activity = (ConversationActivity) getActivity();
757 final XmppConnectionService xmppService = activity.xmppConnectionService;
758 if (conversation.hasValidOtrSession()) {
759 activity.xmppConnectionService.sendMessage(message);
760 messageSent();
761 } else {
762 activity.selectPresence(message.getConversation(),
763 new OnPresenceSelected() {
764
765 @Override
766 public void onPresenceSelected() {
767 message.setPresence(conversation.getNextPresence());
768 xmppService.sendMessage(message);
769 messageSent();
770 }
771 });
772 }
773 }
774
775 public void setText(String text) {
776 this.pastedText = text;
777 }
778
779 public void clearInputField() {
780 this.mEditMessage.setText("");
781 }
782}