ConversationFragment.java

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