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.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.nextMessageEncryption);
 83			if (conversation.nextMessageEncryption == Message.ENCRYPTION_OTR) {
 84				sendOtrMessage(message);
 85			} else if (conversation.nextMessageEncryption == 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.nextMessageEncryption) {
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			case Message.ENCRYPTION_DECRYPTED:
143				chatMsg.setHint(getString(R.string.send_pgp_message));
144				break;
145			default:
146				break;
147			}
148		}
149	}
150
151	@Override
152	public View onCreateView(final LayoutInflater inflater,
153			ViewGroup container, Bundle savedInstanceState) {
154
155		final DisplayMetrics metrics = getResources().getDisplayMetrics();
156		
157		this.inflater = inflater;
158
159		final View view = inflater.inflate(R.layout.fragment_conversation,
160				container, false);
161		chatMsg = (EditText) view.findViewById(R.id.textinput);
162		
163		if (pastedText!=null) {
164			chatMsg.setText(pastedText);
165		}
166		
167		ImageButton sendButton = (ImageButton) view
168				.findViewById(R.id.textSendButton);
169		sendButton.setOnClickListener(this.sendMsgListener);
170
171		pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
172		pgpInfo.setOnClickListener(clickToDecryptListener);
173		mucError = (LinearLayout) view.findViewById(R.id.muc_error);
174		mucError.setOnClickListener(clickToMuc);
175		mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
176
177		messagesView = (ListView) view.findViewById(R.id.messages_view);
178
179		messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
180				.getApplicationContext(), R.layout.message_sent,
181				this.messageList) {
182
183			private static final int SENT = 0;
184			private static final int RECIEVED = 1;
185
186			@Override
187			public int getViewTypeCount() {
188				return 2;
189			}
190
191			@Override
192			public int getItemViewType(int position) {
193				if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
194					return RECIEVED;
195				} else {
196					return SENT;
197				}
198			}
199
200			@Override
201			public View getView(int position, View view, ViewGroup parent) {
202				final Message item = getItem(position);
203				int type = getItemViewType(position);
204				ViewHolder viewHolder;
205				if (view == null) {
206					viewHolder = new ViewHolder();
207					switch (type) {
208					case SENT:
209						view = (View) inflater.inflate(R.layout.message_sent,
210								null);
211						viewHolder.contact_picture = (ImageView) view
212								.findViewById(R.id.message_photo);
213						viewHolder.contact_picture.setImageBitmap(selfBitmap);
214						break;
215					case RECIEVED:
216						view = (View) inflater.inflate(
217								R.layout.message_recieved, null);
218						viewHolder.contact_picture = (ImageView) view
219								.findViewById(R.id.message_photo);
220						
221						viewHolder.download_button = (Button) view.findViewById(R.id.download_button);
222						
223						if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
224
225							viewHolder.contact_picture.setImageBitmap(mBitmapCache
226									.get(item.getConversation().getName(useSubject), item
227											.getConversation().getContact(),
228											getActivity()
229													.getApplicationContext()));
230
231						}
232						break;
233					default:
234						viewHolder = null;
235						break;
236					}
237					viewHolder.indicator = (ImageView) view.findViewById(R.id.security_indicator);
238					viewHolder.image = (ImageView) view.findViewById(R.id.message_image);
239					viewHolder.messageBody = (TextView) view
240							.findViewById(R.id.message_body);
241					viewHolder.time = (TextView) view
242							.findViewById(R.id.message_time);
243					view.setTag(viewHolder);
244				} else {
245					viewHolder = (ViewHolder) view.getTag();
246				}
247				
248				if (type == RECIEVED) {
249					if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
250						if (item.getCounterpart() != null) {
251							viewHolder.contact_picture.setImageBitmap(mBitmapCache
252									.get(item.getCounterpart(), null,
253											getActivity()
254													.getApplicationContext()));
255						} else {
256							viewHolder.contact_picture.setImageBitmap(mBitmapCache
257									.get(item.getConversation().getName(useSubject),
258											null, getActivity()
259													.getApplicationContext()));
260						}
261					}
262				}
263				
264				if (item.getEncryption() == Message.ENCRYPTION_NONE) {
265					viewHolder.indicator.setVisibility(View.GONE);
266				} else {
267					viewHolder.indicator.setVisibility(View.VISIBLE);
268				}
269				
270				String filesize = "";
271				
272				if ((item.getType() == Message.TYPE_IMAGE)&&((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)||(item.getEncryption() == Message.ENCRYPTION_NONE))) {
273					String[] fileParams = item.getBody().split(",");
274					if ((fileParams.length>=1)&&(item.getStatus() != Message.STATUS_PREPARING)) {
275						long size = Long.parseLong(fileParams[0]);
276						filesize = size/1024+" KB \u00B7 ";
277					}
278					if ((item.getStatus() == Message.STATUS_PREPARING)||(item.getStatus() == Message.STATUS_RECIEVING)) {
279						viewHolder.image.setVisibility(View.GONE);
280						viewHolder.messageBody.setVisibility(View.VISIBLE);
281						if (item.getStatus() == Message.STATUS_PREPARING) {
282							viewHolder.messageBody.setText(getString(R.string.preparing_image));
283						} else if (item.getStatus() == Message.STATUS_RECIEVING) {
284							viewHolder.download_button.setVisibility(View.GONE);
285							viewHolder.messageBody.setText(getString(R.string.receiving_image));
286						}
287						viewHolder.messageBody.setTextColor(0xff33B5E5);
288						viewHolder.messageBody.setTypeface(null,Typeface.ITALIC);
289					} else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
290						viewHolder.image.setVisibility(View.GONE);
291						viewHolder.messageBody.setVisibility(View.GONE);
292						viewHolder.download_button.setVisibility(View.VISIBLE);
293						viewHolder.download_button.setOnClickListener(new OnClickListener() {
294							
295							@Override
296							public void onClick(View v) {
297								JingleConnection connection = item.getJingleConnection();
298								if (connection!=null) {
299									connection.accept();
300								} else {
301									Log.d("xmppService","attached jingle connection was null");
302								}
303							}
304						});
305					} else {
306						viewHolder.messageBody.setVisibility(View.GONE);
307						viewHolder.image.setVisibility(View.VISIBLE);
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.setLayoutParams(new LinearLayout.LayoutParams(scalledW, scalledH));
322			        	} else {
323			        		Log.d("xmppService","message body has less than 3 params");
324			        	}
325						activity.loadBitmap(item, viewHolder.image);
326						viewHolder.image.setOnClickListener(new OnClickListener() {
327							
328							@Override
329							public void onClick(View v) {
330								Uri uri = Uri.parse("content://eu.siacs.conversations.images/"+item.getConversationUuid()+"/"+item.getUuid());
331								Log.d("xmppService","staring intent with uri:"+uri.toString());
332								Intent intent = new Intent(Intent.ACTION_VIEW);
333							    intent.setDataAndType(uri, "image/*");
334							    startActivity(intent);
335							}
336						});
337					}
338				} else {
339					viewHolder.image.setVisibility(View.GONE);
340					viewHolder.messageBody.setVisibility(View.VISIBLE);
341					String body = item.getBody();
342					if (body != null) {
343						if (item.getEncryption() == Message.ENCRYPTION_PGP) {
344							viewHolder.messageBody
345									.setText(getString(R.string.encrypted_message));
346							viewHolder.messageBody.setTextColor(0xff33B5E5);
347							viewHolder.messageBody.setTypeface(null,
348									Typeface.ITALIC);
349						} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
350							viewHolder.messageBody.setText(getString(R.string.decryption_failed));
351							viewHolder.messageBody.setTextColor(0xFFe92727);
352							viewHolder.messageBody.setTypeface(null,Typeface.NORMAL);
353						} else {
354							viewHolder.messageBody.setText(body.trim());
355							viewHolder.messageBody.setTextColor(0xff333333);
356							viewHolder.messageBody.setTypeface(null,
357									Typeface.NORMAL);
358						}
359					}
360				}
361				switch (item.getStatus()) {
362				case Message.STATUS_UNSEND:
363					viewHolder.time.setTypeface(null, Typeface.ITALIC);
364					viewHolder.time.setTextColor(0xFF8e8e8e);
365					viewHolder.time.setText(filesize+"sending\u2026");
366					break;
367				case Message.STATUS_OFFERED:
368					viewHolder.time.setTypeface(null, Typeface.ITALIC);
369					viewHolder.time.setTextColor(0xFF8e8e8e);
370					viewHolder.time.setText(filesize+"offering\u2026");
371					break;
372				case Message.STATUS_SEND_FAILED:
373					viewHolder.time.setText(filesize+getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item
374							.getTimeSent()));
375					viewHolder.time.setTextColor(0xFFe92727);
376					viewHolder.time.setTypeface(null,Typeface.NORMAL);
377					break;
378				case Message.STATUS_SEND_REJECTED:
379					viewHolder.time.setText(filesize+getString(R.string.send_rejected));
380					viewHolder.time.setTextColor(0xFFe92727);
381					viewHolder.time.setTypeface(null,Typeface.NORMAL);
382					break;
383				default:
384					viewHolder.time.setTypeface(null, Typeface.NORMAL);
385					viewHolder.time.setTextColor(0xFF8e8e8e);
386					if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
387						viewHolder.time.setText(filesize+UIHelper
388								.readableTimeDifference(item.getTimeSent()));
389					} else {
390						viewHolder.time.setText(item.getCounterpart()
391								+ " \u00B7 "
392								+ UIHelper.readableTimeDifference(item
393										.getTimeSent()));
394					}
395					break;
396				}
397				return view;
398			}
399		};
400		messagesView.setAdapter(messageListAdapter);
401
402		return view;
403	}
404
405	protected Bitmap findSelfPicture() {
406		SharedPreferences sharedPref = PreferenceManager
407				.getDefaultSharedPreferences(getActivity()
408						.getApplicationContext());
409		boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
410				"show_phone_selfcontact_picture", true);
411
412		return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
413				showPhoneSelfContactPicture, getActivity());
414	}
415
416	@Override
417	public void onStart() {
418		super.onStart();
419		this.activity = (ConversationActivity) getActivity();
420		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
421		this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
422		if (activity.xmppConnectionServiceBound) {
423			this.onBackendConnected();
424		}
425	}
426
427	public void onBackendConnected() {
428		this.conversation = activity.getSelectedConversation();
429		if (this.conversation == null) {
430			return;
431		}
432		this.selfBitmap = findSelfPicture();
433		updateMessages();
434		// rendering complete. now go tell activity to close pane
435		if (activity.getSlidingPaneLayout().isSlideable()) {
436			if (!activity.shouldPaneBeOpen()) {
437				activity.getSlidingPaneLayout().closePane();
438				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
439				activity.getActionBar().setTitle(conversation.getName(useSubject));
440				activity.invalidateOptionsMenu();
441
442			}
443		}
444		if (queuedPqpMessage != null) {
445			this.conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
446			Message message = new Message(conversation, queuedPqpMessage,
447					Message.ENCRYPTION_PGP);
448			sendPgpMessage(message);
449		}
450		if (conversation.getMode() == Conversation.MODE_MULTI) {
451			activity.xmppConnectionService
452					.setOnRenameListener(new OnRenameListener() {
453
454						@Override
455						public void onRename(final boolean success) {
456							activity.xmppConnectionService.updateConversation(conversation);
457							getActivity().runOnUiThread(new Runnable() {
458
459								@Override
460								public void run() {
461									if (success) {
462										Toast.makeText(
463												getActivity(),
464												getString(R.string.your_nick_has_been_changed),
465												Toast.LENGTH_SHORT).show();
466									} else {
467										Toast.makeText(getActivity(),
468												getString(R.string.nick_in_use),
469												Toast.LENGTH_SHORT).show();
470									}
471								}
472							});
473						}
474					});
475		}
476	}
477	
478	private void decryptMessage(final Message message) {
479		Log.d("xmppService","called to decrypt");
480		PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
481		if (engine!=null) {
482			engine.decrypt(message,new OnPgpEngineResult() {
483				
484				@Override
485				public void userInputRequried(PendingIntent pi) {
486					askForPassphraseIntent = pi.getIntentSender();
487					pgpInfo.setVisibility(View.VISIBLE);
488				}
489				
490				@Override
491				public void success() {
492					Log.d("xmppService","successfully decrypted");
493					activity.xmppConnectionService.databaseBackend.updateMessage(message);
494					updateMessages();
495				}
496				
497				@Override
498				public void error(OpenPgpError openPgpError) {
499					Log.d("xmppService","decryption error"+openPgpError.getMessage());
500					message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
501					//updateMessages();
502				}
503			});
504		} else {
505			Log.d("xmppService","engine was null");
506		}
507	}
508	
509	public void updateMessages() {
510		ConversationActivity activity = (ConversationActivity) getActivity();
511		if (this.conversation != null) {
512			for (Message message : this.conversation.getMessages()) {
513				if ((message.getEncryption() == Message.ENCRYPTION_PGP)&&(message.getStatus() == Message.STATUS_RECIEVED)) {
514					decryptMessage(message);
515					break;
516				}
517			}
518			this.messageList.clear();
519			this.messageList.addAll(this.conversation.getMessages());
520			this.messageListAdapter.notifyDataSetChanged();
521			if (conversation.getMode() == Conversation.MODE_SINGLE) {
522				if (messageList.size() >= 1) {
523					int latestEncryption = this.conversation.getLatestMessage()
524							.getEncryption();
525					if ((latestEncryption == Message.ENCRYPTION_DECRYPTED)||(latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) {
526						conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
527					} else {
528						conversation.nextMessageEncryption = latestEncryption;
529					}
530					makeFingerprintWarning(latestEncryption);
531				}
532			} else {
533				if (conversation.getMucOptions().getError() != 0) {
534					mucError.setVisibility(View.VISIBLE);
535					if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
536						mucErrorText.setText(getString(R.string.nick_in_use));
537					}
538				} else {
539					mucError.setVisibility(View.GONE);
540				}
541			}
542			getActivity().invalidateOptionsMenu();
543			updateChatMsgHint();
544			int size = this.messageList.size();
545			if (size >= 1)
546				messagesView.setSelection(size - 1);
547			if (!activity.shouldPaneBeOpen()) {
548				conversation.markRead();
549				// TODO update notifications
550				UIHelper.updateNotification(getActivity(),
551						activity.getConversationList(), null, false);
552				activity.updateConversationList();
553			}
554		}
555	}
556
557	protected void makeFingerprintWarning(int latestEncryption) {
558		final LinearLayout fingerprintWarning = (LinearLayout) getView()
559				.findViewById(R.id.new_fingerprint);
560		if (conversation.getContact() != null) {
561			Set<String> knownFingerprints = conversation.getContact()
562					.getOtrFingerprints();
563			if ((latestEncryption == Message.ENCRYPTION_OTR)
564					&& (conversation.hasValidOtrSession()
565							&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
566								.contains(conversation.getOtrFingerprint())))) {
567				fingerprintWarning.setVisibility(View.VISIBLE);
568				TextView fingerprint = (TextView) getView().findViewById(
569						R.id.otr_fingerprint);
570				fingerprint.setText(conversation.getOtrFingerprint());
571				fingerprintWarning.setOnClickListener(new OnClickListener() {
572
573					@Override
574					public void onClick(View v) {
575						AlertDialog dialog = UIHelper
576								.getVerifyFingerprintDialog(
577										(ConversationActivity) getActivity(),
578										conversation, fingerprintWarning);
579						dialog.show();
580					}
581				});
582			} else {
583				fingerprintWarning.setVisibility(View.GONE);
584			}
585		} else {
586			fingerprintWarning.setVisibility(View.GONE);
587		}
588	}
589
590	protected void sendPlainTextMessage(Message message) {
591		ConversationActivity activity = (ConversationActivity) getActivity();
592		activity.xmppConnectionService.sendMessage(message, null);
593		chatMsg.setText("");
594	}
595
596	protected void sendPgpMessage(final Message message) {
597		final ConversationActivity activity = (ConversationActivity) getActivity();
598		final XmppConnectionService xmppService = activity.xmppConnectionService;
599		final Contact contact = message.getConversation().getContact();
600		final Account account = message.getConversation().getAccount();
601		if (activity.hasPgp()) {
602			if (contact.getPgpKeyId() != 0) {
603				xmppService.getPgpEngine().hasKey(account,contact.getPgpKeyId(), new OnPgpEngineResult() {
604					
605					@Override
606					public void userInputRequried(PendingIntent pi) {
607						try {
608							getActivity().startIntentSenderForResult(pi.getIntentSender(),
609									ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
610									0, 0);
611						} catch (SendIntentException e1) {
612							Log.d("xmppService","failed to start intent to send message");
613						}
614					}
615					
616					@Override
617					public void success() {
618						xmppService.getPgpEngine().encrypt(account, message,new OnPgpEngineResult() {
619							
620							@Override
621							public void userInputRequried(PendingIntent pi) {
622								try {
623									activity.startIntentSenderForResult(pi.getIntentSender(),
624											ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
625											0, 0);
626								} catch (SendIntentException e1) {
627									Log.d("xmppService","failed to start intent to send message");
628								}
629							}
630							
631							@Override
632							public void success() {
633								xmppService.sendMessage(message, null);
634								chatMsg.setText("");
635							}
636							
637							@Override
638							public void error(OpenPgpError openPgpError) {
639								// TODO Auto-generated method stub
640								
641							}
642						});
643					}
644					
645					@Override
646					public void error(OpenPgpError openPgpError) {
647						Log.d("xmppService","openpgp error"+openPgpError.getMessage());
648					}
649				});
650				
651				
652					
653					
654			} else {
655				AlertDialog.Builder builder = new AlertDialog.Builder(
656						getActivity());
657				builder.setTitle("No openPGP key found");
658				builder.setIconAttribute(android.R.attr.alertDialogIcon);
659				builder.setMessage("There is no openPGP key associated with this contact");
660				builder.setNegativeButton("Cancel", null);
661				builder.setPositiveButton("Send plain text",
662						new DialogInterface.OnClickListener() {
663
664							@Override
665							public void onClick(DialogInterface dialog,
666									int which) {
667								conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
668								message.setEncryption(Message.ENCRYPTION_NONE);
669								xmppService.sendMessage(message, null);
670								chatMsg.setText("");
671							}
672						});
673				builder.create().show();
674			}
675		}
676	}
677
678	protected void sendOtrMessage(final Message message) {
679		ConversationActivity activity = (ConversationActivity) getActivity();
680		final XmppConnectionService xmppService = activity.xmppConnectionService;
681		if (conversation.hasValidOtrSession()) {
682			activity.xmppConnectionService.sendMessage(message, null);
683			chatMsg.setText("");
684		} else {
685			activity.selectPresence(message.getConversation(), new OnPresenceSelected() {
686				
687				@Override
688				public void onPresenceSelected(boolean success, String presence) {
689					if (success) {
690						xmppService.sendMessage(message,presence);
691						chatMsg.setText("");
692					}
693				}
694
695				@Override
696				public void onSendPlainTextInstead() {
697					message.setEncryption(Message.ENCRYPTION_NONE);
698					xmppService.sendMessage(message,null);
699					chatMsg.setText("");
700				}
701			},"otr");
702		}
703	}
704
705	private static class ViewHolder {
706
707		protected Button download_button;
708		protected ImageView image;
709		protected ImageView indicator;
710		protected TextView time;
711		protected TextView messageBody;
712		protected ImageView contact_picture;
713
714	}
715
716	private class BitmapCache {
717		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
718		private Bitmap error = null;
719
720		public Bitmap get(String name, Contact contact, Context context) {
721			if (bitmaps.containsKey(name)) {
722				return bitmaps.get(name);
723			} else {
724				Bitmap bm;
725				if (contact != null){
726					bm = UIHelper.getContactPicture(contact, 48, context, false);
727				} else {
728					bm = UIHelper.getContactPicture(name, 48, context, false);
729				}
730				bitmaps.put(name, bm);
731				return bm;
732			}
733		}
734	}
735
736	/*class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
737
738		@Override
739		protected Boolean doInBackground(Message... params) {
740			final ConversationActivity activity = (ConversationActivity) getActivity();
741			askForPassphraseIntent = null;
742			for (int i = 0; i < params.length; ++i) {
743				if (params[i].getEncryption() == Message.ENCRYPTION_PGP) {
744					String body = params[i].getBody();
745					String decrypted = null;
746					if (activity == null) {
747						return false;
748					} else if (!activity.xmppConnectionServiceBound) {
749						return false;
750					}
751					try {
752						decrypted = activity.xmppConnectionService
753								.getPgpEngine().decrypt(conversation.getAccount(),body);
754					} catch (UserInputRequiredException e) {
755						askForPassphraseIntent = e.getPendingIntent()
756								.getIntentSender();
757						activity.runOnUiThread(new Runnable() {
758
759							@Override
760							public void run() {
761								pgpInfo.setVisibility(View.VISIBLE);
762							}
763						});
764
765						return false;
766
767					} catch (OpenPgpException e) {
768						Log.d("gultsch", "error decrypting pgp");
769					}
770					if (decrypted != null) {
771						params[i].setBody(decrypted);
772						params[i].setEncryption(Message.ENCRYPTION_DECRYPTED);
773						activity.xmppConnectionService.updateMessage(params[i]);
774					}
775					if (activity != null) {
776						activity.runOnUiThread(new Runnable() {
777
778							@Override
779							public void run() {
780								messageListAdapter.notifyDataSetChanged();
781							}
782						});
783					}
784				}
785				if (activity != null) {
786					activity.runOnUiThread(new Runnable() {
787
788						@Override
789						public void run() {
790							activity.updateConversationList();
791						}
792					});
793				}
794			}
795			return true;
796		}
797
798	}*/
799
800	public void setText(String text) {
801		this.pastedText = text;
802	}
803}