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