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		if (this.conversation!=null) {
496			this.conversation.setNextMessage(chatMsg.getText().toString());
497		}
498	}
499
500	public void onBackendConnected() {
501		this.conversation = activity.getSelectedConversation();
502		if (this.conversation == null) {
503			return;
504		}
505		if (this.pastedText == null) {
506			this.chatMsg.setText(conversation.getNextMessage());
507		} else {
508			chatMsg.setText(conversation.getNextMessage() + " " + pastedText);
509			pastedText = null;
510		}
511		int position = chatMsg.length();
512		Editable etext = chatMsg.getText();
513		Selection.setSelection(etext, position);
514		this.selfBitmap = findSelfPicture();
515		updateMessages();
516		if (activity.getSlidingPaneLayout().isSlideable()) {
517			if (!activity.shouldPaneBeOpen()) {
518				activity.getSlidingPaneLayout().closePane();
519				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
520				activity.getActionBar().setTitle(
521						conversation.getName(useSubject));
522				activity.invalidateOptionsMenu();
523
524			}
525		}
526		if (conversation.getMode() == Conversation.MODE_MULTI) {
527			activity.xmppConnectionService
528					.setOnRenameListener(new OnRenameListener() {
529
530						@Override
531						public void onRename(final boolean success) {
532							activity.xmppConnectionService
533									.updateConversation(conversation);
534							getActivity().runOnUiThread(new Runnable() {
535
536								@Override
537								public void run() {
538									if (success) {
539										Toast.makeText(
540												getActivity(),
541												getString(R.string.your_nick_has_been_changed),
542												Toast.LENGTH_SHORT).show();
543									} else {
544										Toast.makeText(
545												getActivity(),
546												getString(R.string.nick_in_use),
547												Toast.LENGTH_SHORT).show();
548									}
549								}
550							});
551						}
552					});
553		}
554	}
555
556	private void decryptMessage(final Message message) {
557		PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
558		if (engine != null) {
559			engine.decrypt(message, new OnPgpEngineResult() {
560
561				@Override
562				public void userInputRequried(PendingIntent pi) {
563					askForPassphraseIntent = pi.getIntentSender();
564					pgpInfo.setVisibility(View.VISIBLE);
565				}
566
567				@Override
568				public void success() {
569					activity.xmppConnectionService.databaseBackend
570							.updateMessage(message);
571					updateMessages();
572				}
573
574				@Override
575				public void error(OpenPgpError openPgpError) {
576					Log.d("xmppService",
577							"decryption error" + openPgpError.getMessage());
578					message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
579					// updateMessages();
580				}
581			});
582		} else {
583			pgpInfo.setVisibility(View.VISIBLE);
584		}
585	}
586
587	public void updateMessages() {
588		ConversationActivity activity = (ConversationActivity) getActivity();
589		if (this.conversation != null) {
590			for (Message message : this.conversation.getMessages()) {
591				if ((message.getEncryption() == Message.ENCRYPTION_PGP)
592						&& (message.getStatus() == Message.STATUS_RECIEVED)) {
593					decryptMessage(message);
594					break;
595				}
596			}
597			this.messageList.clear();
598			this.messageList.addAll(this.conversation.getMessages());
599			this.messageListAdapter.notifyDataSetChanged();
600			if (conversation.getMode() == Conversation.MODE_SINGLE) {
601				if (messageList.size() >= 1) {
602					makeFingerprintWarning(conversation.getLatestEncryption());
603				}
604			} else {
605				if (conversation.getMucOptions().getError() != 0) {
606					mucError.setVisibility(View.VISIBLE);
607					if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
608						mucErrorText.setText(getString(R.string.nick_in_use));
609					}
610				} else {
611					mucError.setVisibility(View.GONE);
612				}
613			}
614			getActivity().invalidateOptionsMenu();
615			updateChatMsgHint();
616			int size = this.messageList.size();
617			if (size >= 1)
618				messagesView.setSelection(size - 1);
619			if (!activity.shouldPaneBeOpen()) {
620				conversation.markRead();
621				// TODO update notifications
622				UIHelper.updateNotification(getActivity(),
623						activity.getConversationList(), null, false);
624				activity.updateConversationList();
625			}
626		}
627	}
628
629	protected void makeFingerprintWarning(int latestEncryption) {
630		final LinearLayout fingerprintWarning = (LinearLayout) getView()
631				.findViewById(R.id.new_fingerprint);
632		if (conversation.getContact() != null) {
633			Set<String> knownFingerprints = conversation.getContact()
634					.getOtrFingerprints();
635			if ((latestEncryption == Message.ENCRYPTION_OTR)
636					&& (conversation.hasValidOtrSession()
637							&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
638								.contains(conversation.getOtrFingerprint())))) {
639				fingerprintWarning.setVisibility(View.VISIBLE);
640				TextView fingerprint = (TextView) getView().findViewById(
641						R.id.otr_fingerprint);
642				fingerprint.setText(conversation.getOtrFingerprint());
643				fingerprintWarning.setOnClickListener(new OnClickListener() {
644
645					@Override
646					public void onClick(View v) {
647						AlertDialog dialog = UIHelper
648								.getVerifyFingerprintDialog(
649										(ConversationActivity) getActivity(),
650										conversation, fingerprintWarning);
651						dialog.show();
652					}
653				});
654			} else {
655				fingerprintWarning.setVisibility(View.GONE);
656			}
657		} else {
658			fingerprintWarning.setVisibility(View.GONE);
659		}
660	}
661
662	protected void sendPlainTextMessage(Message message) {
663		ConversationActivity activity = (ConversationActivity) getActivity();
664		activity.xmppConnectionService.sendMessage(message, null);
665		chatMsg.setText("");
666	}
667
668	protected void sendPgpMessage(final Message message) {
669		activity.pendingMessage = message;
670		final ConversationActivity activity = (ConversationActivity) getActivity();
671		final XmppConnectionService xmppService = activity.xmppConnectionService;
672		final Contact contact = message.getConversation().getContact();
673		if (activity.hasPgp()) {
674			if (contact.getPgpKeyId() != 0) {
675				xmppService.getPgpEngine().hasKey(contact,
676						new OnPgpEngineResult() {
677
678							@Override
679							public void userInputRequried(PendingIntent pi) {
680								activity.runIntent(
681										pi,
682										ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
683							}
684
685							@Override
686							public void success() {
687								activity.encryptTextMessage();
688							}
689
690							@Override
691							public void error(OpenPgpError openPgpError) {
692								Log.d("xmppService", "openpgp error"
693										+ openPgpError.getMessage());
694							}
695						});
696
697			} else {
698				showNoPGPKeyDialog(new DialogInterface.OnClickListener() {
699
700					@Override
701					public void onClick(DialogInterface dialog,
702							int which) {
703						conversation
704								.setNextEncryption(Message.ENCRYPTION_NONE);
705						message.setEncryption(Message.ENCRYPTION_NONE);
706						xmppService.sendMessage(message, null);
707						chatMsg.setText("");
708					}
709				});
710			}
711		}
712	}
713	
714	public void showNoPGPKeyDialog(DialogInterface.OnClickListener listener) {
715		AlertDialog.Builder builder = new AlertDialog.Builder(
716				getActivity());
717		builder.setTitle(getString(R.string.no_pgp_key));
718		builder.setIconAttribute(android.R.attr.alertDialogIcon);
719		builder.setMessage(getText(R.string.contact_has_no_pgp_key));
720		builder.setNegativeButton(getString(R.string.cancel), null);
721		builder.setPositiveButton(getString(R.string.send_unencrypted),listener);
722		builder.create().show();
723	}
724
725	protected void sendOtrMessage(final Message message) {
726		ConversationActivity activity = (ConversationActivity) getActivity();
727		final XmppConnectionService xmppService = activity.xmppConnectionService;
728		if (conversation.hasValidOtrSession()) {
729			activity.xmppConnectionService.sendMessage(message, null);
730			chatMsg.setText("");
731		} else {
732			activity.selectPresence(message.getConversation(),
733					new OnPresenceSelected() {
734
735						@Override
736						public void onPresenceSelected(boolean success,
737								String presence) {
738							if (success) {
739								xmppService.sendMessage(message, presence);
740								chatMsg.setText("");
741							}
742						}
743
744						@Override
745						public void onSendPlainTextInstead() {
746							message.setEncryption(Message.ENCRYPTION_NONE);
747							xmppService.sendMessage(message, null);
748							chatMsg.setText("");
749						}
750					}, "otr");
751		}
752	}
753
754	private static class ViewHolder {
755
756		protected Button download_button;
757		protected ImageView image;
758		protected ImageView indicator;
759		protected TextView time;
760		protected TextView messageBody;
761		protected ImageView contact_picture;
762
763	}
764
765	private class BitmapCache {
766		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
767		private Bitmap error = null;
768
769		public Bitmap get(String name, Contact contact, Context context) {
770			if (bitmaps.containsKey(name)) {
771				return bitmaps.get(name);
772			} else {
773				Bitmap bm;
774				if (contact != null) {
775					bm = UIHelper
776							.getContactPicture(contact, 48, context, false);
777				} else {
778					bm = UIHelper.getContactPicture(name, 48, context, false);
779				}
780				bitmaps.put(name, bm);
781				return bm;
782			}
783		}
784	}
785
786	public void setText(String text) {
787		this.pastedText = text;
788	}
789
790	public void clearInputField() {
791		this.chatMsg.setText("");
792	}
793}