ConversationFragment.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.HashMap;
  5import java.util.List;
  6import java.util.Set;
  7
  8import org.openintents.openpgp.OpenPgpError;
  9
 10import net.java.otr4j.session.SessionStatus;
 11
 12import eu.siacs.conversations.R;
 13import eu.siacs.conversations.crypto.OnPgpEngineResult;
 14import eu.siacs.conversations.crypto.PgpEngine;
 15import eu.siacs.conversations.entities.Account;
 16import eu.siacs.conversations.entities.Contact;
 17import eu.siacs.conversations.entities.Conversation;
 18import eu.siacs.conversations.entities.Message;
 19import eu.siacs.conversations.entities.MucOptions;
 20import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
 21import eu.siacs.conversations.services.XmppConnectionService;
 22import eu.siacs.conversations.utils.UIHelper;
 23import eu.siacs.conversations.xmpp.jingle.JingleConnection;
 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.SharedPreferences;
 32import android.content.IntentSender.SendIntentException;
 33import android.graphics.Bitmap;
 34import android.graphics.Typeface;
 35import android.net.Uri;
 36import android.os.Bundle;
 37import android.preference.PreferenceManager;
 38import android.text.Editable;
 39import android.text.Selection;
 40import android.util.DisplayMetrics;
 41import android.util.Log;
 42import android.view.LayoutInflater;
 43import android.view.View;
 44import android.view.View.OnClickListener;
 45import android.view.ViewGroup;
 46import android.widget.ArrayAdapter;
 47import android.widget.Button;
 48import android.widget.EditText;
 49import android.widget.LinearLayout;
 50import android.widget.ListView;
 51import android.widget.ImageButton;
 52import android.widget.ImageView;
 53import android.widget.TextView;
 54import android.widget.Toast;
 55
 56public class ConversationFragment extends Fragment {
 57
 58	protected Conversation conversation;
 59	protected ListView messagesView;
 60	protected LayoutInflater inflater;
 61	protected List<Message> messageList = new ArrayList<Message>();
 62	protected ArrayAdapter<Message> messageListAdapter;
 63	protected Contact contact;
 64	protected BitmapCache mBitmapCache = new BitmapCache();
 65
 66	protected String queuedPqpMessage = null;
 67
 68	private EditText chatMsg;
 69	private String pastedText = null;
 70
 71	protected Bitmap selfBitmap;
 72
 73	private boolean useSubject = true;
 74
 75	private IntentSender askForPassphraseIntent = null;
 76
 77	private OnClickListener sendMsgListener = new OnClickListener() {
 78
 79		@Override
 80		public void onClick(View v) {
 81			if (chatMsg.getText().length() < 1)
 82				return;
 83			Message message = new Message(conversation, chatMsg.getText()
 84					.toString(), conversation.getNextEncryption());
 85			if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
 86				sendOtrMessage(message);
 87			} else if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
 88				sendPgpMessage(message);
 89			} else {
 90				sendPlainTextMessage(message);
 91			}
 92		}
 93	};
 94	protected OnClickListener clickToDecryptListener = new OnClickListener() {
 95
 96		@Override
 97		public void onClick(View v) {
 98			if (askForPassphraseIntent != null) {
 99				try {
100					getActivity().startIntentSenderForResult(
101							askForPassphraseIntent,
102							ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
103							0, 0);
104				} catch (SendIntentException e) {
105					Log.d("xmppService", "couldnt fire intent");
106				}
107			}
108		}
109	};
110
111	private LinearLayout pgpInfo;
112	private LinearLayout mucError;
113	private TextView mucErrorText;
114	private OnClickListener clickToMuc = new OnClickListener() {
115
116		@Override
117		public void onClick(View v) {
118			Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
119			intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
120			intent.putExtra("uuid", conversation.getUuid());
121			startActivity(intent);
122		}
123	};
124	private ConversationActivity activity;
125
126	public void hidePgpPassphraseBox() {
127		pgpInfo.setVisibility(View.GONE);
128	}
129
130	public void updateChatMsgHint() {
131		if (conversation.getMode() == Conversation.MODE_MULTI) {
132			chatMsg.setHint(getString(R.string.send_message_to_conference));
133		} else {
134			switch (conversation.getNextEncryption()) {
135			case Message.ENCRYPTION_NONE:
136				chatMsg.setHint(getString(R.string.send_plain_text_message));
137				break;
138			case Message.ENCRYPTION_OTR:
139				chatMsg.setHint(getString(R.string.send_otr_message));
140				break;
141			case Message.ENCRYPTION_PGP:
142				chatMsg.setHint(getString(R.string.send_pgp_message));
143				break;
144			default:
145				break;
146			}
147		}
148	}
149
150	@Override
151	public View onCreateView(final LayoutInflater inflater,
152			ViewGroup container, Bundle savedInstanceState) {
153
154		final DisplayMetrics metrics = getResources().getDisplayMetrics();
155
156		this.inflater = inflater;
157
158		final View view = inflater.inflate(R.layout.fragment_conversation,
159				container, false);
160		chatMsg = (EditText) view.findViewById(R.id.textinput);
161
162		ImageButton sendButton = (ImageButton) view
163				.findViewById(R.id.textSendButton);
164		sendButton.setOnClickListener(this.sendMsgListener);
165
166		pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
167		pgpInfo.setOnClickListener(clickToDecryptListener);
168		mucError = (LinearLayout) view.findViewById(R.id.muc_error);
169		mucError.setOnClickListener(clickToMuc);
170		mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
171
172		messagesView = (ListView) view.findViewById(R.id.messages_view);
173
174		messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
175				.getApplicationContext(), R.layout.message_sent,
176				this.messageList) {
177
178			private static final int SENT = 0;
179			private static final int RECIEVED = 1;
180
181			@Override
182			public int getViewTypeCount() {
183				return 2;
184			}
185
186			@Override
187			public int getItemViewType(int position) {
188				if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
189					return RECIEVED;
190				} else {
191					return SENT;
192				}
193			}
194
195			private void displayStatus(ViewHolder viewHolder, Message message) {
196				String filesize = null;
197				String info = null;
198				boolean error = false;
199				if (message.getType() == Message.TYPE_IMAGE) {
200					String[] fileParams = message.getBody().split(",");
201					long size = Long.parseLong(fileParams[0]);
202					filesize = size / 1024 + " KB";
203				}
204				switch (message.getStatus()) {
205				case Message.STATUS_UNSEND:
206					info = getString(R.string.sending);
207					break;
208				case Message.STATUS_OFFERED:
209					info = getString(R.string.offering);
210					break;
211				case Message.STATUS_SEND_FAILED:
212					info = getString(R.string.send_failed);
213					error = true;
214					break;
215				case Message.STATUS_SEND_REJECTED:
216					info = getString(R.string.send_rejected);
217					error = true;
218					break;
219				default:
220					if ((message.getConversation().getMode() == Conversation.MODE_MULTI)
221							&& (message.getStatus() <= Message.STATUS_RECIEVED)) {
222						info = message.getCounterpart();
223					}
224					break;
225				}
226				if (error) {
227					viewHolder.time.setTextColor(0xFFe92727);
228				} else {
229					viewHolder.time.setTextColor(0xFF8e8e8e);
230				}
231				if (message.getEncryption() == Message.ENCRYPTION_NONE) {
232					viewHolder.indicator.setVisibility(View.GONE);
233				} else {
234					viewHolder.indicator.setVisibility(View.VISIBLE);
235				}
236
237				String formatedTime = UIHelper.readableTimeDifference(message
238						.getTimeSent());
239				if (message.getStatus() <= Message.STATUS_RECIEVED) {
240					if ((filesize != null) && (info != null)) {
241						viewHolder.time.setText(filesize + " \u00B7 " + info);
242					} else if ((filesize == null) && (info != null)) {
243						viewHolder.time.setText(formatedTime + " \u00B7 "
244								+ info);
245					} else if ((filesize != null) && (info == null)) {
246						viewHolder.time.setText(formatedTime + " \u00B7 "
247								+ filesize);
248					} else {
249						viewHolder.time.setText(formatedTime);
250					}
251				} else {
252					if ((filesize != null) && (info != null)) {
253						viewHolder.time.setText(filesize + " \u00B7 " + info);
254					} else if ((filesize == null) && (info != null)) {
255						viewHolder.time.setText(info + " \u00B7 "
256								+ formatedTime);
257					} else if ((filesize != null) && (info == null)) {
258						viewHolder.time.setText(filesize + " \u00B7 "
259								+ formatedTime);
260					} else {
261						viewHolder.time.setText(formatedTime);
262					}
263				}
264			}
265
266			private void displayInfoMessage(ViewHolder viewHolder, int r) {
267				viewHolder.download_button.setVisibility(View.GONE);
268				viewHolder.image.setVisibility(View.GONE);
269				viewHolder.messageBody.setVisibility(View.VISIBLE);
270				viewHolder.messageBody.setText(getString(r));
271				viewHolder.messageBody.setTextColor(0xff33B5E5);
272				viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
273			}
274
275			private void displayDecryptionFailed(ViewHolder viewHolder) {
276				viewHolder.download_button.setVisibility(View.GONE);
277				viewHolder.image.setVisibility(View.GONE);
278				viewHolder.messageBody.setVisibility(View.VISIBLE);
279				viewHolder.messageBody
280						.setText(getString(R.string.decryption_failed));
281				viewHolder.messageBody.setTextColor(0xFFe92727);
282				viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
283			}
284
285			private void displayTextMessage(ViewHolder viewHolder, String text) {
286				if (viewHolder.download_button != null) {
287					viewHolder.download_button.setVisibility(View.GONE);
288				}
289				viewHolder.image.setVisibility(View.GONE);
290				viewHolder.messageBody.setVisibility(View.VISIBLE);
291				if (text != null) {
292					viewHolder.messageBody.setText(text.trim());
293				} else {
294					viewHolder.messageBody.setText("");
295				}
296				viewHolder.messageBody.setTextColor(0xff333333);
297				viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
298			}
299
300			private void displayImageMessage(ViewHolder viewHolder,
301					final Message message) {
302				if (viewHolder.download_button != null) {
303					viewHolder.download_button.setVisibility(View.GONE);
304				}
305				viewHolder.messageBody.setVisibility(View.GONE);
306				viewHolder.image.setVisibility(View.VISIBLE);
307				String[] fileParams = message.getBody().split(",");
308				if (fileParams.length == 3) {
309					double target = metrics.density * 288;
310					int w = Integer.parseInt(fileParams[1]);
311					int h = Integer.parseInt(fileParams[2]);
312					int scalledW;
313					int scalledH;
314					if (w <= h) {
315						scalledW = (int) (w / ((double) h / target));
316						scalledH = (int) target;
317					} else {
318						scalledW = (int) target;
319						scalledH = (int) (h / ((double) w / target));
320					}
321					viewHolder.image
322							.setLayoutParams(new LinearLayout.LayoutParams(
323									scalledW, scalledH));
324				}
325				activity.loadBitmap(message, viewHolder.image);
326				viewHolder.image.setOnClickListener(new OnClickListener() {
327
328					@Override
329					public void onClick(View v) {
330						Uri uri = Uri
331								.parse("content://eu.siacs.conversations.images/"
332										+ message.getConversationUuid()
333										+ "/"
334										+ message.getUuid());
335						Log.d("xmppService",
336								"staring intent with uri:" + uri.toString());
337						Intent intent = new Intent(Intent.ACTION_VIEW);
338						intent.setDataAndType(uri, "image/*");
339						startActivity(intent);
340					}
341				});
342			}
343
344			@Override
345			public View getView(int position, View view, ViewGroup parent) {
346				final Message item = getItem(position);
347				int type = getItemViewType(position);
348				ViewHolder viewHolder;
349				if (view == null) {
350					viewHolder = new ViewHolder();
351					switch (type) {
352					case SENT:
353						view = (View) inflater.inflate(R.layout.message_sent,
354								null);
355						viewHolder.contact_picture = (ImageView) view
356								.findViewById(R.id.message_photo);
357						viewHolder.contact_picture.setImageBitmap(selfBitmap);
358						break;
359					case RECIEVED:
360						view = (View) inflater.inflate(
361								R.layout.message_recieved, null);
362						viewHolder.contact_picture = (ImageView) view
363								.findViewById(R.id.message_photo);
364
365						viewHolder.download_button = (Button) view
366								.findViewById(R.id.download_button);
367
368						if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
369
370							viewHolder.contact_picture
371									.setImageBitmap(mBitmapCache.get(
372											item.getConversation().getName(
373													useSubject), item
374													.getConversation()
375													.getContact(),
376											getActivity()
377													.getApplicationContext()));
378
379						}
380						break;
381					default:
382						viewHolder = null;
383						break;
384					}
385					viewHolder.indicator = (ImageView) view
386							.findViewById(R.id.security_indicator);
387					viewHolder.image = (ImageView) view
388							.findViewById(R.id.message_image);
389					viewHolder.messageBody = (TextView) view
390							.findViewById(R.id.message_body);
391					viewHolder.time = (TextView) view
392							.findViewById(R.id.message_time);
393					view.setTag(viewHolder);
394				} else {
395					viewHolder = (ViewHolder) view.getTag();
396				}
397
398				if (type == RECIEVED) {
399					if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
400						if (item.getCounterpart() != null) {
401							viewHolder.contact_picture
402									.setImageBitmap(mBitmapCache.get(item
403											.getCounterpart(), null,
404											getActivity()
405													.getApplicationContext()));
406						} else {
407							viewHolder.contact_picture
408									.setImageBitmap(mBitmapCache.get(
409											item.getConversation().getName(
410													useSubject), null,
411											getActivity()
412													.getApplicationContext()));
413						}
414					}
415				}
416
417				if (item.getType() == Message.TYPE_IMAGE) {
418					if (item.getStatus() == Message.STATUS_RECIEVING) {
419						displayInfoMessage(viewHolder, R.string.receiving_image);
420					} else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
421						viewHolder.image.setVisibility(View.GONE);
422						viewHolder.messageBody.setVisibility(View.GONE);
423						viewHolder.download_button.setVisibility(View.VISIBLE);
424						viewHolder.download_button
425								.setOnClickListener(new OnClickListener() {
426
427									@Override
428									public void onClick(View v) {
429										JingleConnection connection = item
430												.getJingleConnection();
431										if (connection != null) {
432											connection.accept();
433										} else {
434											Log.d("xmppService",
435													"attached jingle connection was null");
436										}
437									}
438								});
439					} else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
440							|| (item.getEncryption() == Message.ENCRYPTION_NONE)) {
441						displayImageMessage(viewHolder, item);
442					} else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
443						displayInfoMessage(viewHolder,
444								R.string.encrypted_message);
445					} else {
446						displayDecryptionFailed(viewHolder);
447					}
448				} else {
449					if (item.getEncryption() == Message.ENCRYPTION_PGP) {
450						displayInfoMessage(viewHolder,
451								R.string.encrypted_message);
452					} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
453						displayDecryptionFailed(viewHolder);
454					} else {
455						displayTextMessage(viewHolder, item.getBody());
456					}
457				}
458
459				displayStatus(viewHolder, item);
460
461				return view;
462			}
463		};
464		messagesView.setAdapter(messageListAdapter);
465
466		return view;
467	}
468
469	protected Bitmap findSelfPicture() {
470		SharedPreferences sharedPref = PreferenceManager
471				.getDefaultSharedPreferences(getActivity()
472						.getApplicationContext());
473		boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
474				"show_phone_selfcontact_picture", true);
475
476		return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
477				showPhoneSelfContactPicture, getActivity());
478	}
479
480	@Override
481	public void onStart() {
482		super.onStart();
483		this.activity = (ConversationActivity) getActivity();
484		SharedPreferences preferences = PreferenceManager
485				.getDefaultSharedPreferences(activity);
486		this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
487		if (activity.xmppConnectionServiceBound) {
488			this.onBackendConnected();
489		}
490	}
491
492	@Override
493	public void onStop() {
494		super.onStop();
495		this.conversation.setNextMessage(chatMsg.getText().toString());
496	}
497
498	public void onBackendConnected() {
499		this.conversation = activity.getSelectedConversation();
500		if (this.conversation == null) {
501			return;
502		}
503		if (this.pastedText == null) {
504			this.chatMsg.setText(conversation.getNextMessage());
505		} else {
506			chatMsg.setText(conversation.getNextMessage() + " " + pastedText);
507			pastedText = null;
508		}
509		int position = chatMsg.length();
510		Editable etext = chatMsg.getText();
511		Selection.setSelection(etext, position);
512		this.selfBitmap = findSelfPicture();
513		updateMessages();
514		if (activity.getSlidingPaneLayout().isSlideable()) {
515			if (!activity.shouldPaneBeOpen()) {
516				activity.getSlidingPaneLayout().closePane();
517				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
518				activity.getActionBar().setTitle(
519						conversation.getName(useSubject));
520				activity.invalidateOptionsMenu();
521
522			}
523		}
524		if (conversation.getMode() == Conversation.MODE_MULTI) {
525			activity.xmppConnectionService
526					.setOnRenameListener(new OnRenameListener() {
527
528						@Override
529						public void onRename(final boolean success) {
530							activity.xmppConnectionService
531									.updateConversation(conversation);
532							getActivity().runOnUiThread(new Runnable() {
533
534								@Override
535								public void run() {
536									if (success) {
537										Toast.makeText(
538												getActivity(),
539												getString(R.string.your_nick_has_been_changed),
540												Toast.LENGTH_SHORT).show();
541									} else {
542										Toast.makeText(
543												getActivity(),
544												getString(R.string.nick_in_use),
545												Toast.LENGTH_SHORT).show();
546									}
547								}
548							});
549						}
550					});
551		}
552	}
553
554	private void decryptMessage(final Message message) {
555		PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
556		if (engine != null) {
557			engine.decrypt(message, new OnPgpEngineResult() {
558
559				@Override
560				public void userInputRequried(PendingIntent pi) {
561					askForPassphraseIntent = pi.getIntentSender();
562					pgpInfo.setVisibility(View.VISIBLE);
563				}
564
565				@Override
566				public void success() {
567					activity.xmppConnectionService.databaseBackend
568							.updateMessage(message);
569					updateMessages();
570				}
571
572				@Override
573				public void error(OpenPgpError openPgpError) {
574					Log.d("xmppService",
575							"decryption error" + openPgpError.getMessage());
576					message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
577					// updateMessages();
578				}
579			});
580		} else {
581			pgpInfo.setVisibility(View.VISIBLE);
582		}
583	}
584
585	public void updateMessages() {
586		ConversationActivity activity = (ConversationActivity) getActivity();
587		if (this.conversation != null) {
588			for (Message message : this.conversation.getMessages()) {
589				if ((message.getEncryption() == Message.ENCRYPTION_PGP)
590						&& (message.getStatus() == Message.STATUS_RECIEVED)) {
591					decryptMessage(message);
592					break;
593				}
594			}
595			this.messageList.clear();
596			this.messageList.addAll(this.conversation.getMessages());
597			this.messageListAdapter.notifyDataSetChanged();
598			if (conversation.getMode() == Conversation.MODE_SINGLE) {
599				if (messageList.size() >= 1) {
600					makeFingerprintWarning(conversation.getLatestEncryption());
601				}
602			} else {
603				if (conversation.getMucOptions().getError() != 0) {
604					mucError.setVisibility(View.VISIBLE);
605					if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
606						mucErrorText.setText(getString(R.string.nick_in_use));
607					}
608				} else {
609					mucError.setVisibility(View.GONE);
610				}
611			}
612			getActivity().invalidateOptionsMenu();
613			updateChatMsgHint();
614			int size = this.messageList.size();
615			if (size >= 1)
616				messagesView.setSelection(size - 1);
617			if (!activity.shouldPaneBeOpen()) {
618				conversation.markRead();
619				// TODO update notifications
620				UIHelper.updateNotification(getActivity(),
621						activity.getConversationList(), null, false);
622				activity.updateConversationList();
623			}
624		}
625	}
626
627	protected void makeFingerprintWarning(int latestEncryption) {
628		final LinearLayout fingerprintWarning = (LinearLayout) getView()
629				.findViewById(R.id.new_fingerprint);
630		if (conversation.getContact() != null) {
631			Set<String> knownFingerprints = conversation.getContact()
632					.getOtrFingerprints();
633			if ((latestEncryption == Message.ENCRYPTION_OTR)
634					&& (conversation.hasValidOtrSession()
635							&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
636								.contains(conversation.getOtrFingerprint())))) {
637				fingerprintWarning.setVisibility(View.VISIBLE);
638				TextView fingerprint = (TextView) getView().findViewById(
639						R.id.otr_fingerprint);
640				fingerprint.setText(conversation.getOtrFingerprint());
641				fingerprintWarning.setOnClickListener(new OnClickListener() {
642
643					@Override
644					public void onClick(View v) {
645						AlertDialog dialog = UIHelper
646								.getVerifyFingerprintDialog(
647										(ConversationActivity) getActivity(),
648										conversation, fingerprintWarning);
649						dialog.show();
650					}
651				});
652			} else {
653				fingerprintWarning.setVisibility(View.GONE);
654			}
655		} else {
656			fingerprintWarning.setVisibility(View.GONE);
657		}
658	}
659
660	protected void sendPlainTextMessage(Message message) {
661		ConversationActivity activity = (ConversationActivity) getActivity();
662		activity.xmppConnectionService.sendMessage(message, null);
663		chatMsg.setText("");
664	}
665
666	protected void sendPgpMessage(final Message message) {
667		final ConversationActivity activity = (ConversationActivity) getActivity();
668		final XmppConnectionService xmppService = activity.xmppConnectionService;
669		final Contact contact = message.getConversation().getContact();
670		final Account account = message.getConversation().getAccount();
671		if (activity.hasPgp()) {
672			if (contact.getPgpKeyId() != 0) {
673				xmppService.getPgpEngine().hasKey(contact,
674						new OnPgpEngineResult() {
675
676							@Override
677							public void userInputRequried(PendingIntent pi) {
678								activity.runIntent(
679										pi,
680										ConversationActivity.REQUEST_SEND_MESSAGE);
681							}
682
683							@Override
684							public void success() {
685								xmppService.getPgpEngine().encrypt(account,
686										message, new OnPgpEngineResult() {
687
688											@Override
689											public void userInputRequried(
690													PendingIntent pi) {
691												activity.runIntent(
692														pi,
693														ConversationActivity.REQUEST_SEND_MESSAGE);
694											}
695
696											@Override
697											public void success() {
698												xmppService.sendMessage(
699														message, null);
700												chatMsg.setText("");
701											}
702
703											@Override
704											public void error(
705													OpenPgpError openPgpError) {
706												// TODO Auto-generated method
707												// stub
708
709											}
710										});
711							}
712
713							@Override
714							public void error(OpenPgpError openPgpError) {
715								Log.d("xmppService", "openpgp error"
716										+ openPgpError.getMessage());
717							}
718						});
719
720			} else {
721				showNoPGPKeyDialog(new DialogInterface.OnClickListener() {
722
723					@Override
724					public void onClick(DialogInterface dialog,
725							int which) {
726						conversation
727								.setNextEncryption(Message.ENCRYPTION_NONE);
728						message.setEncryption(Message.ENCRYPTION_NONE);
729						xmppService.sendMessage(message, null);
730						chatMsg.setText("");
731					}
732				});
733			}
734		}
735	}
736	
737	public void showNoPGPKeyDialog(DialogInterface.OnClickListener listener) {
738		AlertDialog.Builder builder = new AlertDialog.Builder(
739				getActivity());
740		builder.setTitle(getString(R.string.no_pgp_key));
741		builder.setIconAttribute(android.R.attr.alertDialogIcon);
742		builder.setMessage(getText(R.string.contact_has_no_pgp_key));
743		builder.setNegativeButton(getString(R.string.cancel), null);
744		builder.setPositiveButton(getString(R.string.send_unencrypted),listener);
745		builder.create().show();
746	}
747
748	protected void sendOtrMessage(final Message message) {
749		ConversationActivity activity = (ConversationActivity) getActivity();
750		final XmppConnectionService xmppService = activity.xmppConnectionService;
751		if (conversation.hasValidOtrSession()) {
752			activity.xmppConnectionService.sendMessage(message, null);
753			chatMsg.setText("");
754		} else {
755			activity.selectPresence(message.getConversation(),
756					new OnPresenceSelected() {
757
758						@Override
759						public void onPresenceSelected(boolean success,
760								String presence) {
761							if (success) {
762								xmppService.sendMessage(message, presence);
763								chatMsg.setText("");
764							}
765						}
766
767						@Override
768						public void onSendPlainTextInstead() {
769							message.setEncryption(Message.ENCRYPTION_NONE);
770							xmppService.sendMessage(message, null);
771							chatMsg.setText("");
772						}
773					}, "otr");
774		}
775	}
776
777	private static class ViewHolder {
778
779		protected Button download_button;
780		protected ImageView image;
781		protected ImageView indicator;
782		protected TextView time;
783		protected TextView messageBody;
784		protected ImageView contact_picture;
785
786	}
787
788	private class BitmapCache {
789		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
790		private Bitmap error = null;
791
792		public Bitmap get(String name, Contact contact, Context context) {
793			if (bitmaps.containsKey(name)) {
794				return bitmaps.get(name);
795			} else {
796				Bitmap bm;
797				if (contact != null) {
798					bm = UIHelper
799							.getContactPicture(contact, 48, context, false);
800				} else {
801					bm = UIHelper.getContactPicture(name, 48, context, false);
802				}
803				bitmaps.put(name, bm);
804				return bm;
805			}
806		}
807	}
808
809	public void setText(String text) {
810		this.pastedText = text;
811	}
812}