ConversationFragment.java

  1package eu.siacs.conversations.ui;
  2
  3import java.util.ArrayList;
  4import java.util.HashMap;
  5import java.util.Hashtable;
  6import java.util.LinkedList;
  7import java.util.List;
  8import java.util.Set;
  9
 10import net.java.otr4j.session.SessionStatus;
 11
 12import eu.siacs.conversations.R;
 13import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException;
 14import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException;
 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 android.app.AlertDialog;
 24import android.app.Fragment;
 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.os.AsyncTask;
 34import android.os.Bundle;
 35import android.preference.PreferenceManager;
 36import android.util.DisplayMetrics;
 37import android.util.Log;
 38import android.view.LayoutInflater;
 39import android.view.View;
 40import android.view.View.OnClickListener;
 41import android.view.ViewGroup;
 42import android.widget.ArrayAdapter;
 43import android.widget.EditText;
 44import android.widget.LinearLayout;
 45import android.widget.ListView;
 46import android.widget.ImageButton;
 47import android.widget.ImageView;
 48import android.widget.TextView;
 49import android.widget.Toast;
 50
 51public class ConversationFragment extends Fragment {
 52
 53	protected Conversation conversation;
 54	protected ListView messagesView;
 55	protected LayoutInflater inflater;
 56	protected List<Message> messageList = new ArrayList<Message>();
 57	protected ArrayAdapter<Message> messageListAdapter;
 58	protected Contact contact;
 59	protected BitmapCache mBitmapCache = new BitmapCache();
 60
 61	protected String queuedPqpMessage = null;
 62
 63	private EditText chatMsg;
 64	private String pastedText = null;
 65
 66	protected Bitmap selfBitmap;
 67	
 68	private boolean useSubject = true;
 69
 70	private IntentSender askForPassphraseIntent = null;
 71
 72	private OnClickListener sendMsgListener = new OnClickListener() {
 73
 74		@Override
 75		public void onClick(View v) {
 76			if (chatMsg.getText().length() < 1)
 77				return;
 78			Message message = new Message(conversation, chatMsg.getText()
 79					.toString(), conversation.nextMessageEncryption);
 80			if (conversation.nextMessageEncryption == Message.ENCRYPTION_OTR) {
 81				sendOtrMessage(message);
 82			} else if (conversation.nextMessageEncryption == Message.ENCRYPTION_PGP) {
 83				sendPgpMessage(message);
 84			} else {
 85				sendPlainTextMessage(message);
 86			}
 87		}
 88	};
 89	protected OnClickListener clickToDecryptListener = new OnClickListener() {
 90
 91		@Override
 92		public void onClick(View v) {
 93			if (askForPassphraseIntent != null) {
 94				try {
 95					getActivity().startIntentSenderForResult(
 96							askForPassphraseIntent,
 97							ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
 98							0, 0);
 99				} catch (SendIntentException e) {
100					Log.d("xmppService", "couldnt fire intent");
101				}
102			}
103		}
104	};
105
106	private LinearLayout pgpInfo;
107	private LinearLayout mucError;
108	private TextView mucErrorText;
109	private OnClickListener clickToMuc = new OnClickListener() {
110
111		@Override
112		public void onClick(View v) {
113			Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
114			intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
115			intent.putExtra("uuid", conversation.getUuid());
116			startActivity(intent);
117		}
118	};
119	private ConversationActivity activity;
120
121	public void hidePgpPassphraseBox() {
122		pgpInfo.setVisibility(View.GONE);
123	}
124
125	public void updateChatMsgHint() {
126		if (conversation.getMode() == Conversation.MODE_MULTI) {
127			chatMsg.setHint("Send message to conference");
128		} else {
129			switch (conversation.nextMessageEncryption) {
130			case Message.ENCRYPTION_NONE:
131				chatMsg.setHint("Send plain text message");
132				break;
133			case Message.ENCRYPTION_OTR:
134				chatMsg.setHint("Send OTR encrypted message");
135				break;
136			case Message.ENCRYPTION_PGP:
137				chatMsg.setHint("Send openPGP encryted messeage");
138				break;
139			case Message.ENCRYPTION_DECRYPTED:
140				chatMsg.setHint("Send openPGP encryted messeage");
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		if (pastedText!=null) {
161			chatMsg.setText(pastedText);
162		}
163		
164		ImageButton sendButton = (ImageButton) view
165				.findViewById(R.id.textSendButton);
166		sendButton.setOnClickListener(this.sendMsgListener);
167
168		pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
169		pgpInfo.setOnClickListener(clickToDecryptListener);
170		mucError = (LinearLayout) view.findViewById(R.id.muc_error);
171		mucError.setOnClickListener(clickToMuc);
172		mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
173
174		messagesView = (ListView) view.findViewById(R.id.messages_view);
175
176		messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
177				.getApplicationContext(), R.layout.message_sent,
178				this.messageList) {
179
180			private static final int SENT = 0;
181			private static final int RECIEVED = 1;
182			private static final int ERROR = 2;
183
184			@Override
185			public int getViewTypeCount() {
186				return 3;
187			}
188
189			@Override
190			public int getItemViewType(int position) {
191				if (getItem(position).getStatus() == Message.STATUS_RECIEVED) {
192					return RECIEVED;
193				} else if (getItem(position).getStatus() == Message.STATUS_ERROR) {
194					return ERROR;
195				} else {
196					return SENT;
197				}
198			}
199
200			@Override
201			public View getView(int position, View view, ViewGroup parent) {
202				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.imageView = (ImageView) view
212								.findViewById(R.id.message_photo);
213						viewHolder.imageView.setImageBitmap(selfBitmap);
214						viewHolder.indicator = (ImageView) view.findViewById(R.id.security_indicator);
215						viewHolder.image = (ImageView) view.findViewById(R.id.message_image);
216						break;
217					case RECIEVED:
218						view = (View) inflater.inflate(
219								R.layout.message_recieved, null);
220						viewHolder.imageView = (ImageView) view
221								.findViewById(R.id.message_photo);
222						viewHolder.indicator = (ImageView) view.findViewById(R.id.security_indicator);
223						if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
224
225							viewHolder.imageView.setImageBitmap(mBitmapCache
226									.get(item.getConversation().getName(useSubject), item
227											.getConversation().getContact(),
228											getActivity()
229													.getApplicationContext()));
230
231						}
232						break;
233					case ERROR:
234						view = (View) inflater.inflate(R.layout.message_error,
235								null);
236						viewHolder.imageView = (ImageView) view
237								.findViewById(R.id.message_photo);
238						viewHolder.imageView.setImageBitmap(mBitmapCache
239								.getError());
240						break;
241					default:
242						viewHolder = null;
243						break;
244					}
245					viewHolder.messageBody = (TextView) view
246							.findViewById(R.id.message_body);
247					viewHolder.time = (TextView) view
248							.findViewById(R.id.message_time);
249					view.setTag(viewHolder);
250				} else {
251					viewHolder = (ViewHolder) view.getTag();
252				}
253				if (type == RECIEVED) {
254					if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
255						if (item.getCounterpart() != null) {
256							viewHolder.imageView.setImageBitmap(mBitmapCache
257									.get(item.getCounterpart(), null,
258											getActivity()
259													.getApplicationContext()));
260						} else {
261							viewHolder.imageView.setImageBitmap(mBitmapCache
262									.get(item.getConversation().getName(useSubject),
263											null, getActivity()
264													.getApplicationContext()));
265						}
266					}
267				}
268				if (item.getType() == Message.TYPE_IMAGE) {
269					viewHolder.image.setVisibility(View.VISIBLE);
270					viewHolder.image.setImageBitmap(activity.xmppConnectionService.getFileBackend().getThumbnailFromMessage(item,(int) (metrics.density * 288)));
271					viewHolder.messageBody.setVisibility(View.GONE);
272				} else {
273					if (viewHolder.image != null) viewHolder.image.setVisibility(View.GONE);
274					viewHolder.messageBody.setVisibility(View.VISIBLE);
275					String body = item.getBody();
276					if (body != null) {
277						if (item.getEncryption() == Message.ENCRYPTION_PGP) {
278							viewHolder.messageBody
279									.setText(getString(R.string.encrypted_message));
280							viewHolder.messageBody.setTextColor(0xff33B5E5);
281							viewHolder.messageBody.setTypeface(null,
282									Typeface.ITALIC);
283							viewHolder.indicator.setVisibility(View.VISIBLE);
284						} else if ((item.getEncryption() == Message.ENCRYPTION_OTR)||(item.getEncryption() == Message.ENCRYPTION_DECRYPTED)) {
285							viewHolder.messageBody.setText(body.trim());
286							viewHolder.messageBody.setTextColor(0xff000000);
287							viewHolder.messageBody.setTypeface(null,
288									Typeface.NORMAL);
289							viewHolder.indicator.setVisibility(View.VISIBLE);
290						} else {
291							viewHolder.messageBody.setText(body.trim());
292							viewHolder.messageBody.setTextColor(0xff000000);
293							viewHolder.messageBody.setTypeface(null,
294									Typeface.NORMAL);
295							if (item.getStatus() != Message.STATUS_ERROR) {
296								viewHolder.indicator.setVisibility(View.GONE);
297							}
298						}
299					} else {
300						viewHolder.indicator.setVisibility(View.GONE);
301					}
302				}
303				if (item.getStatus() == Message.STATUS_UNSEND) {
304					viewHolder.time.setTypeface(null, Typeface.ITALIC);
305					viewHolder.time.setText("sending\u2026");
306				} else {
307					viewHolder.time.setTypeface(null, Typeface.NORMAL);
308					if ((item.getConversation().getMode() == Conversation.MODE_SINGLE)
309							|| (type != RECIEVED)) {
310						viewHolder.time.setText(UIHelper
311								.readableTimeDifference(item.getTimeSent()));
312					} else {
313						viewHolder.time.setText(item.getCounterpart()
314								+ " \u00B7 "
315								+ UIHelper.readableTimeDifference(item
316										.getTimeSent()));
317					}
318				}
319				return view;
320			}
321		};
322		messagesView.setAdapter(messageListAdapter);
323
324		return view;
325	}
326
327	protected Bitmap findSelfPicture() {
328		SharedPreferences sharedPref = PreferenceManager
329				.getDefaultSharedPreferences(getActivity()
330						.getApplicationContext());
331		boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
332				"show_phone_selfcontact_picture", true);
333
334		return UIHelper.getSelfContactPicture(conversation.getAccount(), 200,
335				showPhoneSelfContactPicture, getActivity());
336	}
337
338	@Override
339	public void onStart() {
340		super.onStart();
341		this.activity = (ConversationActivity) getActivity();
342		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
343		this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
344		if (activity.xmppConnectionServiceBound) {
345			this.onBackendConnected();
346		}
347	}
348
349	public void onBackendConnected() {
350		this.conversation = activity.getSelectedConversation();
351		if (this.conversation == null) {
352			return;
353		}
354		this.selfBitmap = findSelfPicture();
355		updateMessages();
356		// rendering complete. now go tell activity to close pane
357		if (activity.getSlidingPaneLayout().isSlideable()) {
358			if (!activity.shouldPaneBeOpen()) {
359				activity.getSlidingPaneLayout().closePane();
360				activity.getActionBar().setDisplayHomeAsUpEnabled(true);
361				activity.getActionBar().setTitle(conversation.getName(useSubject));
362				activity.invalidateOptionsMenu();
363
364			}
365		}
366		if (queuedPqpMessage != null) {
367			this.conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
368			Message message = new Message(conversation, queuedPqpMessage,
369					Message.ENCRYPTION_PGP);
370			sendPgpMessage(message);
371		}
372		if (conversation.getMode() == Conversation.MODE_MULTI) {
373			activity.xmppConnectionService
374					.setOnRenameListener(new OnRenameListener() {
375
376						@Override
377						public void onRename(final boolean success) {
378							activity.xmppConnectionService.updateConversation(conversation);
379							getActivity().runOnUiThread(new Runnable() {
380
381								@Override
382								public void run() {
383									if (success) {
384										Toast.makeText(
385												getActivity(),
386												"Your nickname has been changed",
387												Toast.LENGTH_SHORT).show();
388									} else {
389										Toast.makeText(getActivity(),
390												"Nichname is already in use",
391												Toast.LENGTH_SHORT).show();
392									}
393								}
394							});
395						}
396					});
397		}
398	}
399
400	public void updateMessages() {
401		ConversationActivity activity = (ConversationActivity) getActivity();
402		if (this.conversation != null) {
403			List<Message> encryptedMessages = new LinkedList<Message>();
404			for (Message message : this.conversation.getMessages()) {
405				if (message.getEncryption() == Message.ENCRYPTION_PGP) {
406					encryptedMessages.add(message);
407				}
408			}
409			if (encryptedMessages.size() > 0) {
410				DecryptMessage task = new DecryptMessage();
411				Message[] msgs = new Message[encryptedMessages.size()];
412				task.execute(encryptedMessages.toArray(msgs));
413			}
414			this.messageList.clear();
415			this.messageList.addAll(this.conversation.getMessages());
416			this.messageListAdapter.notifyDataSetChanged();
417			if (conversation.getMode() == Conversation.MODE_SINGLE) {
418				if (messageList.size() >= 1) {
419					int latestEncryption = this.conversation.getLatestMessage()
420							.getEncryption();
421					if (latestEncryption == Message.ENCRYPTION_DECRYPTED) {
422						conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
423					} else {
424						conversation.nextMessageEncryption = latestEncryption;
425					}
426					makeFingerprintWarning(latestEncryption);
427				}
428			} else {
429				if (conversation.getMucOptions().getError() != 0) {
430					mucError.setVisibility(View.VISIBLE);
431					if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
432						mucErrorText.setText(getString(R.string.nick_in_use));
433					}
434				} else {
435					mucError.setVisibility(View.GONE);
436				}
437			}
438			getActivity().invalidateOptionsMenu();
439			updateChatMsgHint();
440			int size = this.messageList.size();
441			if (size >= 1)
442				messagesView.setSelection(size - 1);
443			if (!activity.shouldPaneBeOpen()) {
444				conversation.markRead();
445				// TODO update notifications
446				UIHelper.updateNotification(getActivity(),
447						activity.getConversationList(), null, false);
448				activity.updateConversationList();
449			}
450		}
451	}
452
453	protected void makeFingerprintWarning(int latestEncryption) {
454		final LinearLayout fingerprintWarning = (LinearLayout) getView()
455				.findViewById(R.id.new_fingerprint);
456		if (conversation.getContact() != null) {
457			Set<String> knownFingerprints = conversation.getContact()
458					.getOtrFingerprints();
459			if ((latestEncryption == Message.ENCRYPTION_OTR)
460					&& (conversation.hasValidOtrSession()
461							&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
462								.contains(conversation.getOtrFingerprint())))) {
463				fingerprintWarning.setVisibility(View.VISIBLE);
464				TextView fingerprint = (TextView) getView().findViewById(
465						R.id.otr_fingerprint);
466				fingerprint.setText(conversation.getOtrFingerprint());
467				fingerprintWarning.setOnClickListener(new OnClickListener() {
468
469					@Override
470					public void onClick(View v) {
471						AlertDialog dialog = UIHelper
472								.getVerifyFingerprintDialog(
473										(ConversationActivity) getActivity(),
474										conversation, fingerprintWarning);
475						dialog.show();
476					}
477				});
478			} else {
479				fingerprintWarning.setVisibility(View.GONE);
480			}
481		} else {
482			fingerprintWarning.setVisibility(View.GONE);
483		}
484	}
485
486	protected void sendPlainTextMessage(Message message) {
487		ConversationActivity activity = (ConversationActivity) getActivity();
488		activity.xmppConnectionService.sendMessage(message, null);
489		chatMsg.setText("");
490	}
491
492	protected void sendPgpMessage(final Message message) {
493		ConversationActivity activity = (ConversationActivity) getActivity();
494		final XmppConnectionService xmppService = activity.xmppConnectionService;
495		Contact contact = message.getConversation().getContact();
496		Account account = message.getConversation().getAccount();
497		if (activity.hasPgp()) {
498			if (contact.getPgpKeyId() != 0) {
499				try {
500					message.setEncryptedBody(xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message.getBody()));
501					xmppService.sendMessage(message, null);
502					chatMsg.setText("");
503				} catch (UserInputRequiredException e) {
504					try {
505						getActivity().startIntentSenderForResult(e.getPendingIntent().getIntentSender(),
506								ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
507								0, 0);
508					} catch (SendIntentException e1) {
509						Log.d("xmppService","failed to start intent to send message");
510					}
511				} catch (OpenPgpException e) {
512					Log.d("xmppService","error encrypting with pgp: "+e.getOpenPgpError().getMessage());
513				}
514			} else {
515				AlertDialog.Builder builder = new AlertDialog.Builder(
516						getActivity());
517				builder.setTitle("No openPGP key found");
518				builder.setIconAttribute(android.R.attr.alertDialogIcon);
519				builder.setMessage("There is no openPGP key assoziated with this contact");
520				builder.setNegativeButton("Cancel", null);
521				builder.setPositiveButton("Send plain text",
522						new DialogInterface.OnClickListener() {
523
524							@Override
525							public void onClick(DialogInterface dialog,
526									int which) {
527								conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
528								message.setEncryption(Message.ENCRYPTION_NONE);
529								xmppService.sendMessage(message, null);
530								chatMsg.setText("");
531							}
532						});
533				builder.create().show();
534			}
535		}
536	}
537
538	protected void sendOtrMessage(final Message message) {
539		ConversationActivity activity = (ConversationActivity) getActivity();
540		final XmppConnectionService xmppService = activity.xmppConnectionService;
541		if (conversation.hasValidOtrSession()) {
542			activity.xmppConnectionService.sendMessage(message, null);
543			chatMsg.setText("");
544		} else {
545			Hashtable<String, Integer> presences;
546			if (conversation.getContact() != null) {
547				presences = conversation.getContact().getPresences();
548			} else {
549				presences = null;
550			}
551			if ((presences == null) || (presences.size() == 0)) {
552				AlertDialog.Builder builder = new AlertDialog.Builder(
553						getActivity());
554				builder.setTitle("Contact is offline");
555				builder.setIconAttribute(android.R.attr.alertDialogIcon);
556				builder.setMessage("Sending OTR encrypted messages to an offline contact is impossible.");
557				builder.setPositiveButton("Send plain text",
558						new DialogInterface.OnClickListener() {
559
560							@Override
561							public void onClick(DialogInterface dialog,
562									int which) {
563								conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
564								message.setEncryption(Message.ENCRYPTION_NONE);
565								xmppService.sendMessage(message, null);
566								chatMsg.setText("");
567							}
568						});
569				builder.setNegativeButton("Cancel", null);
570				builder.create().show();
571			} else if (presences.size() == 1) {
572				xmppService.sendMessage(message, (String) presences.keySet()
573						.toArray()[0]);
574				chatMsg.setText("");
575			} else {
576				AlertDialog.Builder builder = new AlertDialog.Builder(
577						getActivity());
578				builder.setTitle("Choose Presence");
579				final String[] presencesArray = new String[presences.size()];
580				presences.keySet().toArray(presencesArray);
581				builder.setItems(presencesArray,
582						new DialogInterface.OnClickListener() {
583
584							@Override
585							public void onClick(DialogInterface dialog,
586									int which) {
587								xmppService.sendMessage(message,
588										presencesArray[which]);
589								chatMsg.setText("");
590							}
591						});
592				builder.create().show();
593			}
594		}
595	}
596
597	private static class ViewHolder {
598
599		protected ImageView image;
600		protected ImageView indicator;
601		protected TextView time;
602		protected TextView messageBody;
603		protected ImageView imageView;
604
605	}
606
607	private class BitmapCache {
608		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
609		private Bitmap error = null;
610
611		public Bitmap get(String name, Contact contact, Context context) {
612			if (bitmaps.containsKey(name)) {
613				return bitmaps.get(name);
614			} else {
615				Bitmap bm = UIHelper.getContactPicture(contact, name, 200, context);
616				bitmaps.put(name, bm);
617				return bm;
618			}
619		}
620
621		public Bitmap getError() {
622			if (error == null) {
623				error = UIHelper.getErrorPicture(200);
624			}
625			return error;
626		}
627	}
628
629	class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
630
631		@Override
632		protected Boolean doInBackground(Message... params) {
633			final ConversationActivity activity = (ConversationActivity) getActivity();
634			askForPassphraseIntent = null;
635			for (int i = 0; i < params.length; ++i) {
636				if (params[i].getEncryption() == Message.ENCRYPTION_PGP) {
637					String body = params[i].getBody();
638					String decrypted = null;
639					if (activity == null) {
640						return false;
641					} else if (!activity.xmppConnectionServiceBound) {
642						return false;
643					}
644					try {
645						decrypted = activity.xmppConnectionService
646								.getPgpEngine().decrypt(conversation.getAccount(),body);
647					} catch (UserInputRequiredException e) {
648						askForPassphraseIntent = e.getPendingIntent()
649								.getIntentSender();
650						activity.runOnUiThread(new Runnable() {
651
652							@Override
653							public void run() {
654								pgpInfo.setVisibility(View.VISIBLE);
655							}
656						});
657
658						return false;
659
660					} catch (OpenPgpException e) {
661						Log.d("gultsch", "error decrypting pgp");
662					}
663					if (decrypted != null) {
664						params[i].setBody(decrypted);
665						params[i].setEncryption(Message.ENCRYPTION_DECRYPTED);
666						activity.xmppConnectionService.updateMessage(params[i]);
667					}
668					if (activity != null) {
669						activity.runOnUiThread(new Runnable() {
670
671							@Override
672							public void run() {
673								messageListAdapter.notifyDataSetChanged();
674							}
675						});
676					}
677				}
678				if (activity != null) {
679					activity.runOnUiThread(new Runnable() {
680
681						@Override
682						public void run() {
683							activity.updateConversationList();
684						}
685					});
686				}
687			}
688			return true;
689		}
690
691	}
692
693	public void setText(String text) {
694		this.pastedText = text;
695	}
696}