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		if (size >= 1 && this.messagesView.getLastVisiblePosition() != size - 1) {
526			messagesView.setSelection(size - 1);
527		}
528		mEditMessage.setText("");
529		updateChatMsgHint();
530	}
531
532	public void updateSendButton() {
533		Conversation c = this.conversation;
534		if (activity.useSendButtonToIndicateStatus() && c != null
535				&& c.getAccount().getStatus() == Account.STATUS_ONLINE) {
536			if (c.getMode() == Conversation.MODE_SINGLE) {
537				switch (c.getContact().getMostAvailableStatus()) {
538				case Presences.CHAT:
539					this.mSendButton
540							.setImageResource(R.drawable.ic_action_send_now_online);
541					break;
542				case Presences.ONLINE:
543					this.mSendButton
544							.setImageResource(R.drawable.ic_action_send_now_online);
545					break;
546				case Presences.AWAY:
547					this.mSendButton
548							.setImageResource(R.drawable.ic_action_send_now_away);
549					break;
550				case Presences.XA:
551					this.mSendButton
552							.setImageResource(R.drawable.ic_action_send_now_away);
553					break;
554				case Presences.DND:
555					this.mSendButton
556							.setImageResource(R.drawable.ic_action_send_now_dnd);
557					break;
558				default:
559					this.mSendButton
560							.setImageResource(R.drawable.ic_action_send_now_offline);
561					break;
562				}
563			} else if (c.getMode() == Conversation.MODE_MULTI) {
564				if (c.getMucOptions().online()) {
565					this.mSendButton
566							.setImageResource(R.drawable.ic_action_send_now_online);
567				} else {
568					this.mSendButton
569							.setImageResource(R.drawable.ic_action_send_now_offline);
570				}
571			} else {
572				this.mSendButton
573						.setImageResource(R.drawable.ic_action_send_now_offline);
574			}
575		} else {
576			this.mSendButton
577					.setImageResource(R.drawable.ic_action_send_now_offline);
578		}
579	}
580
581	protected void updateStatusMessages() {
582		if (conversation.getMode() == Conversation.MODE_SINGLE) {
583			for (int i = this.messageList.size() - 1; i >= 0; --i) {
584				if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) {
585					return;
586				} else {
587					if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
588						this.messageList.add(i + 1,
589								Message.createStatusMessage(conversation));
590						return;
591					}
592				}
593			}
594		}
595	}
596
597	protected void makeFingerprintWarning(int latestEncryption) {
598		Set<String> knownFingerprints = conversation.getContact()
599				.getOtrFingerprints();
600		if ((latestEncryption == Message.ENCRYPTION_OTR)
601				&& (conversation.hasValidOtrSession()
602						&& (!conversation.isMuted())
603						&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
604							.contains(conversation.getOtrFingerprint())))) {
605			showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
606					new OnClickListener() {
607
608						@Override
609						public void onClick(View v) {
610							if (conversation.getOtrFingerprint() != null) {
611								AlertDialog dialog = UIHelper
612										.getVerifyFingerprintDialog(
613												(ConversationActivity) getActivity(),
614												conversation, snackbar);
615								dialog.show();
616							}
617						}
618					});
619		}
620	}
621
622	protected void showSnackbar(int message, int action,
623			OnClickListener clickListener) {
624		snackbar.setVisibility(View.VISIBLE);
625		snackbar.setOnClickListener(null);
626		snackbarMessage.setText(message);
627		snackbarMessage.setOnClickListener(null);
628		snackbarAction.setText(action);
629		snackbarAction.setOnClickListener(clickListener);
630	}
631
632	protected void hideSnackbar() {
633		snackbar.setVisibility(View.GONE);
634	}
635
636	protected void sendPlainTextMessage(Message message) {
637		ConversationActivity activity = (ConversationActivity) getActivity();
638		activity.xmppConnectionService.sendMessage(message);
639		messageSent();
640	}
641
642	protected void sendPgpMessage(final Message message) {
643		final ConversationActivity activity = (ConversationActivity) getActivity();
644		final XmppConnectionService xmppService = activity.xmppConnectionService;
645		final Contact contact = message.getConversation().getContact();
646		if (activity.hasPgp()) {
647			if (conversation.getMode() == Conversation.MODE_SINGLE) {
648				if (contact.getPgpKeyId() != 0) {
649					xmppService.getPgpEngine().hasKey(contact,
650							new UiCallback<Contact>() {
651
652								@Override
653								public void userInputRequried(PendingIntent pi,
654										Contact contact) {
655									activity.runIntent(
656											pi,
657											ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
658								}
659
660								@Override
661								public void success(Contact contact) {
662									messageSent();
663									activity.encryptTextMessage(message);
664								}
665
666								@Override
667								public void error(int error, Contact contact) {
668
669								}
670							});
671
672				} else {
673					showNoPGPKeyDialog(false,
674							new DialogInterface.OnClickListener() {
675
676								@Override
677								public void onClick(DialogInterface dialog,
678										int which) {
679									conversation
680											.setNextEncryption(Message.ENCRYPTION_NONE);
681									xmppService.databaseBackend
682											.updateConversation(conversation);
683									message.setEncryption(Message.ENCRYPTION_NONE);
684									xmppService.sendMessage(message);
685									messageSent();
686								}
687							});
688				}
689			} else {
690				if (conversation.getMucOptions().pgpKeysInUse()) {
691					if (!conversation.getMucOptions().everybodyHasKeys()) {
692						Toast warning = Toast
693								.makeText(getActivity(),
694										R.string.missing_public_keys,
695										Toast.LENGTH_LONG);
696						warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
697						warning.show();
698					}
699					activity.encryptTextMessage(message);
700					messageSent();
701				} else {
702					showNoPGPKeyDialog(true,
703							new DialogInterface.OnClickListener() {
704
705								@Override
706								public void onClick(DialogInterface dialog,
707										int which) {
708									conversation
709											.setNextEncryption(Message.ENCRYPTION_NONE);
710									message.setEncryption(Message.ENCRYPTION_NONE);
711									xmppService.databaseBackend
712											.updateConversation(conversation);
713									xmppService.sendMessage(message);
714									messageSent();
715								}
716							});
717				}
718			}
719		} else {
720			activity.showInstallPgpDialog();
721		}
722	}
723
724	public void showNoPGPKeyDialog(boolean plural,
725			DialogInterface.OnClickListener listener) {
726		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
727		builder.setIconAttribute(android.R.attr.alertDialogIcon);
728		if (plural) {
729			builder.setTitle(getString(R.string.no_pgp_keys));
730			builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));
731		} else {
732			builder.setTitle(getString(R.string.no_pgp_key));
733			builder.setMessage(getText(R.string.contact_has_no_pgp_key));
734		}
735		builder.setNegativeButton(getString(R.string.cancel), null);
736		builder.setPositiveButton(getString(R.string.send_unencrypted),
737				listener);
738		builder.create().show();
739	}
740
741	protected void sendOtrMessage(final Message message) {
742		final ConversationActivity activity = (ConversationActivity) getActivity();
743		final XmppConnectionService xmppService = activity.xmppConnectionService;
744		if (conversation.hasValidOtrSession()) {
745			activity.xmppConnectionService.sendMessage(message);
746			messageSent();
747		} else {
748			activity.selectPresence(message.getConversation(),
749					new OnPresenceSelected() {
750
751						@Override
752						public void onPresenceSelected() {
753							message.setPresence(conversation.getNextPresence());
754							xmppService.sendMessage(message);
755							messageSent();
756						}
757					});
758		}
759	}
760
761	public void setText(String text) {
762		this.pastedText = text;
763	}
764
765	public void clearInputField() {
766		this.mEditMessage.setText("");
767	}
768}