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