ConversationActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import java.io.FileNotFoundException;
  4import java.lang.ref.WeakReference;
  5import java.util.ArrayList;
  6import java.util.List;
  7import java.util.concurrent.RejectedExecutionException;
  8
  9import eu.siacs.conversations.R;
 10import eu.siacs.conversations.entities.Contact;
 11import eu.siacs.conversations.entities.Conversation;
 12import eu.siacs.conversations.entities.Message;
 13import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
 14import eu.siacs.conversations.ui.adapter.ConversationAdapter;
 15import eu.siacs.conversations.utils.ExceptionHelper;
 16import eu.siacs.conversations.utils.UIHelper;
 17import android.net.Uri;
 18import android.os.AsyncTask;
 19import android.os.Bundle;
 20import android.preference.PreferenceManager;
 21import android.provider.MediaStore;
 22import android.app.ActionBar;
 23import android.app.AlertDialog;
 24import android.app.FragmentTransaction;
 25import android.app.PendingIntent;
 26import android.content.DialogInterface;
 27import android.content.DialogInterface.OnClickListener;
 28import android.content.IntentSender.SendIntentException;
 29import android.content.Intent;
 30import android.content.SharedPreferences;
 31import android.content.res.Resources;
 32import android.graphics.Bitmap;
 33import android.graphics.drawable.BitmapDrawable;
 34import android.graphics.drawable.Drawable;
 35import android.support.v4.widget.SlidingPaneLayout;
 36import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
 37import android.util.DisplayMetrics;
 38import android.util.Log;
 39import android.view.KeyEvent;
 40import android.view.Menu;
 41import android.view.MenuItem;
 42import android.view.View;
 43import android.widget.AdapterView;
 44import android.widget.AdapterView.OnItemClickListener;
 45import android.widget.ArrayAdapter;
 46import android.widget.CheckBox;
 47import android.widget.ListView;
 48import android.widget.PopupMenu;
 49import android.widget.PopupMenu.OnMenuItemClickListener;
 50import android.widget.ImageView;
 51import android.widget.Toast;
 52
 53public class ConversationActivity extends XmppActivity {
 54
 55	public static final String VIEW_CONVERSATION = "viewConversation";
 56	public static final String CONVERSATION = "conversationUuid";
 57	public static final String TEXT = "text";
 58	public static final String PRESENCE = "eu.siacs.conversations.presence";
 59
 60	public static final int REQUEST_SEND_MESSAGE = 0x0201;
 61	public static final int REQUEST_DECRYPT_PGP = 0x0202;
 62	private static final int REQUEST_ATTACH_FILE_DIALOG = 0x0203;
 63	private static final int REQUEST_IMAGE_CAPTURE = 0x0204;
 64	private static final int REQUEST_RECORD_AUDIO = 0x0205;
 65	private static final int REQUEST_SEND_PGP_IMAGE = 0x0206;
 66	public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207;
 67
 68	private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301;
 69	private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302;
 70	private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0303;
 71
 72	protected SlidingPaneLayout spl;
 73
 74	private List<Conversation> conversationList = new ArrayList<Conversation>();
 75	private Conversation selectedConversation = null;
 76	private ListView listView;
 77
 78	private boolean paneShouldBeOpen = true;
 79	private boolean useSubject = true;
 80	private boolean showLastseen = false;
 81	private ArrayAdapter<Conversation> listAdapter;
 82
 83	private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
 84		
 85		@Override
 86		public void onConversationUpdate() {
 87			runOnUiThread(new Runnable() {
 88
 89				@Override
 90				public void run() {
 91					updateConversationList();
 92					if (paneShouldBeOpen) {
 93						if (conversationList.size() >= 1) {
 94							swapConversationFragment();
 95						} else {
 96							startActivity(new Intent(getApplicationContext(),
 97									StartConversationActivity.class));
 98							finish();
 99						}
100					}
101					ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
102							.findFragmentByTag("conversation");
103					if (selectedFragment != null) {
104						selectedFragment.updateMessages();
105					}
106				}
107			});
108		}
109	};
110
111	protected ConversationActivity activity = this;
112	private DisplayMetrics metrics;
113	private Toast prepareImageToast;
114	
115	private Uri pendingImageUri = null;
116
117	public List<Conversation> getConversationList() {
118		return this.conversationList;
119	}
120
121	public Conversation getSelectedConversation() {
122		return this.selectedConversation;
123	}
124
125	public void setSelectedConversation(Conversation conversation) {
126		this.selectedConversation = conversation;
127	}
128
129	public ListView getConversationListView() {
130		return this.listView;
131	}
132
133	public SlidingPaneLayout getSlidingPaneLayout() {
134		return this.spl;
135	}
136
137	public boolean shouldPaneBeOpen() {
138		return paneShouldBeOpen;
139	}
140
141	@Override
142	protected void onCreate(Bundle savedInstanceState) {
143
144		metrics = getResources().getDisplayMetrics();
145
146		super.onCreate(savedInstanceState);
147
148		setContentView(R.layout.fragment_conversations_overview);
149
150		listView = (ListView) findViewById(R.id.list);
151		
152		getActionBar().setDisplayHomeAsUpEnabled(false);
153		getActionBar().setHomeButtonEnabled(false);
154
155		this.listAdapter = new ConversationAdapter(this, conversationList);
156		listView.setAdapter(this.listAdapter);
157
158		listView.setOnItemClickListener(new OnItemClickListener() {
159
160			@Override
161			public void onItemClick(AdapterView<?> arg0, View clickedView,
162					int position, long arg3) {
163				paneShouldBeOpen = false;
164				if (getSelectedConversation() != conversationList.get(position)) {
165					setSelectedConversation(conversationList.get(position));
166					swapConversationFragment();
167				} else {
168					spl.closePane();
169				}
170			}
171		});
172		spl = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout);
173		spl.setParallaxDistance(150);
174		spl.setShadowResource(R.drawable.es_slidingpane_shadow);
175		spl.setSliderFadeColor(0);
176		spl.setPanelSlideListener(new PanelSlideListener() {
177
178			@Override
179			public void onPanelOpened(View arg0) {
180				paneShouldBeOpen = true;
181				ActionBar ab = getActionBar();
182				if (ab!=null) {
183					ab.setDisplayHomeAsUpEnabled(false);
184					ab.setHomeButtonEnabled(false);
185					ab.setTitle(R.string.app_name);
186				}
187				invalidateOptionsMenu();
188				hideKeyboard();
189			}
190
191			@Override
192			public void onPanelClosed(View arg0) {
193				paneShouldBeOpen = false;
194				if ((conversationList.size() > 0)
195						&& (getSelectedConversation() != null)) {
196					ActionBar ab = getActionBar();
197					if (ab!=null) {
198						ab.setDisplayHomeAsUpEnabled(true);
199						ab.setHomeButtonEnabled(true);
200						ab.setTitle(
201							getSelectedConversation().getName(useSubject));
202					}
203					invalidateOptionsMenu();
204					if (!getSelectedConversation().isRead()) {
205						xmppConnectionService
206								.markRead(getSelectedConversation());
207						UIHelper.updateNotification(getApplicationContext(),
208								getConversationList(), null, false);
209						listView.invalidateViews();
210					}
211				}
212			}
213
214			@Override
215			public void onPanelSlide(View arg0, float arg1) {
216				// TODO Auto-generated method stub
217
218			}
219		});
220	}
221
222	@Override
223	public boolean onCreateOptionsMenu(Menu menu) {
224		getMenuInflater().inflate(R.menu.conversations, menu);
225		MenuItem menuSecure = (MenuItem) menu.findItem(R.id.action_security);
226		MenuItem menuArchive = (MenuItem) menu.findItem(R.id.action_archive);
227		MenuItem menuMucDetails = (MenuItem) menu
228				.findItem(R.id.action_muc_details);
229		MenuItem menuContactDetails = (MenuItem) menu
230				.findItem(R.id.action_contact_details);
231		MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file);
232		MenuItem menuClearHistory = (MenuItem) menu
233				.findItem(R.id.action_clear_history);
234		MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
235		MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite);
236
237		if ((spl.isOpen() && (spl.isSlideable()))) {
238			menuArchive.setVisible(false);
239			menuMucDetails.setVisible(false);
240			menuContactDetails.setVisible(false);
241			menuSecure.setVisible(false);
242			menuInviteContact.setVisible(false);
243			menuAttach.setVisible(false);
244			menuClearHistory.setVisible(false);
245		} else {
246			menuAdd.setVisible(!spl.isSlideable());
247			if (this.getSelectedConversation() != null) {
248				if (this.getSelectedConversation().getLatestMessage()
249						.getEncryption() != Message.ENCRYPTION_NONE) {
250					menuSecure.setIcon(R.drawable.ic_action_secure);
251				}
252				if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
253					menuContactDetails.setVisible(false);
254					menuAttach.setVisible(false);
255				} else {
256					menuMucDetails.setVisible(false);
257					menuInviteContact.setVisible(false);
258				}
259			}
260		}
261		return true;
262	}
263
264	private void selectPresenceToAttachFile(final int attachmentChoice) {
265		selectPresence(getSelectedConversation(), new OnPresenceSelected() {
266
267			@Override
268			public void onPresenceSelected() {
269				if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
270					pendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri();
271					Log.d("xmppService",pendingImageUri.toString());
272					Intent takePictureIntent = new Intent(
273							MediaStore.ACTION_IMAGE_CAPTURE);
274					takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,pendingImageUri);
275					if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
276						startActivityForResult(takePictureIntent,
277								REQUEST_IMAGE_CAPTURE);
278					}
279				} else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
280					Intent attachFileIntent = new Intent();
281					attachFileIntent.setType("image/*");
282					attachFileIntent.setAction(Intent.ACTION_GET_CONTENT);
283					Intent chooser = Intent.createChooser(attachFileIntent,
284							getString(R.string.attach_file));
285					startActivityForResult(chooser, REQUEST_ATTACH_FILE_DIALOG);
286				} else if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) {
287					Intent intent = new Intent(
288							MediaStore.Audio.Media.RECORD_SOUND_ACTION);
289					startActivityForResult(intent, REQUEST_RECORD_AUDIO);
290				}
291			}
292		});
293	}
294
295	private void attachFile(final int attachmentChoice) {
296		final Conversation conversation = getSelectedConversation();
297		if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
298			if (hasPgp()) {
299				if (conversation.getContact().getPgpKeyId() != 0) {
300					xmppConnectionService.getPgpEngine().hasKey(
301							conversation.getContact(),
302							new UiCallback<Contact>() {
303
304								@Override
305								public void userInputRequried(PendingIntent pi,
306										Contact contact) {
307									ConversationActivity.this.runIntent(pi,
308											attachmentChoice);
309								}
310
311								@Override
312								public void success(Contact contact) {
313									selectPresenceToAttachFile(attachmentChoice);
314								}
315
316								@Override
317								public void error(int error, Contact contact) {
318									displayErrorDialog(error);
319								}
320							});
321				} else {
322					final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
323							.findFragmentByTag("conversation");
324					if (fragment != null) {
325						fragment.showNoPGPKeyDialog(false,
326								new OnClickListener() {
327
328									@Override
329									public void onClick(DialogInterface dialog,
330											int which) {
331										conversation
332												.setNextEncryption(Message.ENCRYPTION_NONE);
333										selectPresenceToAttachFile(attachmentChoice);
334									}
335								});
336					}
337				}
338			} else {
339				showInstallPgpDialog();
340			}
341		} else if (getSelectedConversation().getNextEncryption() == Message.ENCRYPTION_NONE) {
342			selectPresenceToAttachFile(attachmentChoice);
343		} else {
344			selectPresenceToAttachFile(attachmentChoice);
345		}
346	}
347
348	@Override
349	public boolean onOptionsItemSelected(MenuItem item) {
350		switch (item.getItemId()) {
351		case android.R.id.home:
352			spl.openPane();
353			return true;
354		case R.id.action_attach_file:
355			View menuAttachFile = findViewById(R.id.action_attach_file);
356			if (menuAttachFile==null) {
357				break;
358			}
359			PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
360			attachFilePopup.inflate(R.menu.attachment_choices);
361			attachFilePopup
362					.setOnMenuItemClickListener(new OnMenuItemClickListener() {
363
364						@Override
365						public boolean onMenuItemClick(MenuItem item) {
366							switch (item.getItemId()) {
367							case R.id.attach_choose_picture:
368								attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
369								break;
370							case R.id.attach_take_picture:
371								attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
372								break;
373							case R.id.attach_record_voice:
374								attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
375								break;
376							}
377							return false;
378						}
379					});
380			attachFilePopup.show();
381			break;
382		case R.id.action_add:
383			startActivity(new Intent(this, StartConversationActivity.class));
384			break;
385		case R.id.action_archive:
386			this.endConversation(getSelectedConversation());
387			break;
388		case R.id.action_contact_details:
389			Contact contact = this.getSelectedConversation().getContact();
390			if (contact.showInRoster()) {
391				switchToContactDetails(contact);
392			} else {
393				showAddToRosterDialog(getSelectedConversation());
394			}
395			break;
396		case R.id.action_muc_details:
397			Intent intent = new Intent(this, ConferenceDetailsActivity.class);
398			intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
399			intent.putExtra("uuid", getSelectedConversation().getUuid());
400			startActivity(intent);
401			break;
402		case R.id.action_invite:
403			inviteToConversation(getSelectedConversation());
404			break;
405		case R.id.action_security:
406			final Conversation conversation = getSelectedConversation();
407			View menuItemView = findViewById(R.id.action_security);
408			if (menuItemView==null) {
409				break;
410			}
411			PopupMenu popup = new PopupMenu(this, menuItemView);
412			final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
413					.findFragmentByTag("conversation");
414			if (fragment != null) {
415				popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
416
417					@Override
418					public boolean onMenuItemClick(MenuItem item) {
419						switch (item.getItemId()) {
420						case R.id.encryption_choice_none:
421							conversation
422									.setNextEncryption(Message.ENCRYPTION_NONE);
423							item.setChecked(true);
424							break;
425						case R.id.encryption_choice_otr:
426							conversation
427									.setNextEncryption(Message.ENCRYPTION_OTR);
428							item.setChecked(true);
429							break;
430						case R.id.encryption_choice_pgp:
431							if (hasPgp()) {
432								if (conversation.getAccount().getKeys()
433										.has("pgp_signature")) {
434									conversation
435											.setNextEncryption(Message.ENCRYPTION_PGP);
436									item.setChecked(true);
437								} else {
438									announcePgp(conversation.getAccount(),
439											conversation);
440								}
441							} else {
442								showInstallPgpDialog();
443							}
444							break;
445						default:
446							conversation
447									.setNextEncryption(Message.ENCRYPTION_NONE);
448							break;
449						}
450						fragment.updateChatMsgHint();
451						return true;
452					}
453				});
454				popup.inflate(R.menu.encryption_choices);
455				MenuItem otr = popup.getMenu().findItem(
456						R.id.encryption_choice_otr);
457				if (conversation.getMode() == Conversation.MODE_MULTI) {
458					otr.setEnabled(false);
459				}
460				switch (conversation.getNextEncryption()) {
461				case Message.ENCRYPTION_NONE:
462					popup.getMenu().findItem(R.id.encryption_choice_none)
463							.setChecked(true);
464					break;
465				case Message.ENCRYPTION_OTR:
466					otr.setChecked(true);
467					break;
468				case Message.ENCRYPTION_PGP:
469					popup.getMenu().findItem(R.id.encryption_choice_pgp)
470							.setChecked(true);
471					break;
472				default:
473					popup.getMenu().findItem(R.id.encryption_choice_none)
474							.setChecked(true);
475					break;
476				}
477				popup.show();
478			}
479
480			break;
481		case R.id.action_clear_history:
482			clearHistoryDialog(getSelectedConversation());
483			break;
484		default:
485			break;
486		}
487		return super.onOptionsItemSelected(item);
488	}
489
490	public void endConversation(Conversation conversation) {
491		conversation.setStatus(Conversation.STATUS_ARCHIVED);
492		paneShouldBeOpen = true;
493		spl.openPane();
494		xmppConnectionService.archiveConversation(conversation);
495		if (conversationList.size() > 0) {
496			setSelectedConversation(conversationList.get(0));
497		} else {
498			setSelectedConversation(null);
499		}
500	}
501
502	protected void clearHistoryDialog(final Conversation conversation) {
503		AlertDialog.Builder builder = new AlertDialog.Builder(this);
504		builder.setTitle(getString(R.string.clear_conversation_history));
505		View dialogView = getLayoutInflater().inflate(
506				R.layout.dialog_clear_history, null);
507		final CheckBox endConversationCheckBox = (CheckBox) dialogView
508				.findViewById(R.id.end_conversation_checkbox);
509		builder.setView(dialogView);
510		builder.setNegativeButton(getString(R.string.cancel), null);
511		builder.setPositiveButton(getString(R.string.delete_messages),
512				new OnClickListener() {
513
514					@Override
515					public void onClick(DialogInterface dialog, int which) {
516						activity.xmppConnectionService
517								.clearConversationHistory(conversation);
518						if (endConversationCheckBox.isChecked()) {
519							endConversation(conversation);
520						}
521					}
522				});
523		builder.create().show();
524	}
525
526	protected ConversationFragment swapConversationFragment() {
527		ConversationFragment selectedFragment = new ConversationFragment();
528		if (!isFinishing()) {
529
530		FragmentTransaction transaction = getFragmentManager()
531				.beginTransaction();
532		transaction.replace(R.id.selected_conversation, selectedFragment,
533				"conversation");
534		
535			transaction.commitAllowingStateLoss();
536		}
537		return selectedFragment;
538	}
539
540	@Override
541	public boolean onKeyDown(int keyCode, KeyEvent event) {
542		if (keyCode == KeyEvent.KEYCODE_BACK) {
543			if (!spl.isOpen()) {
544				spl.openPane();
545				return false;
546			}
547		}
548		return super.onKeyDown(keyCode, event);
549	}
550
551	@Override
552	protected void onNewIntent(Intent intent) {
553		if (xmppConnectionServiceBound) {
554			if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION
555					.equals(intent.getType())))) {
556				String convToView = (String) intent.getExtras().get(CONVERSATION);
557				updateConversationList();
558				for (int i = 0; i < conversationList.size(); ++i) {
559					if (conversationList.get(i).getUuid().equals(convToView)) {
560						setSelectedConversation(conversationList.get(i));
561						break;
562					}
563				}
564				paneShouldBeOpen = false;
565				String text = intent.getExtras().getString(TEXT, null);
566				swapConversationFragment().setText(text);
567			}
568		} else {
569			handledViewIntent = false;
570			setIntent(intent);
571		}
572	}
573
574	@Override
575	public void onStart() {
576		super.onStart();
577		SharedPreferences preferences = PreferenceManager
578				.getDefaultSharedPreferences(this);
579		this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
580		this.showLastseen = preferences.getBoolean("show_last_seen", false);
581		if (this.xmppConnectionServiceBound) {
582			this.onBackendConnected();
583		}
584		if (conversationList.size() >= 1) {
585			onConvChanged.onConversationUpdate();
586		}
587	}
588
589	@Override
590	protected void onStop() {
591		if (xmppConnectionServiceBound) {
592			xmppConnectionService.removeOnConversationListChangedListener();
593		}
594		super.onStop();
595	}
596
597	@Override
598	void onBackendConnected() {
599		this.registerListener();
600		if (conversationList.size() == 0) {
601			updateConversationList();
602		}
603		
604		if (getSelectedConversation()!=null && pendingImageUri !=null) {
605			attachImageToConversation(getSelectedConversation(), pendingImageUri);
606			pendingImageUri = null;
607		} else {
608			pendingImageUri = null;
609		}
610
611		if ((getIntent().getAction() != null)
612				&& (getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
613			if (getIntent().getType().equals(
614					ConversationActivity.VIEW_CONVERSATION)) {
615				handledViewIntent = true;
616
617				String convToView = (String) getIntent().getExtras().get(
618						CONVERSATION);
619
620				for (int i = 0; i < conversationList.size(); ++i) {
621					if (conversationList.get(i).getUuid().equals(convToView)) {
622						setSelectedConversation(conversationList.get(i));
623					}
624				}
625				paneShouldBeOpen = false;
626				String text = getIntent().getExtras().getString(TEXT, null);
627				swapConversationFragment().setText(text);
628			}
629		} else {
630			if (xmppConnectionService.getAccounts().size() == 0) {
631				startActivity(new Intent(this, ManageAccountActivity.class));
632				finish();
633			} else if (conversationList.size() <= 0) {
634				// add no history
635				startActivity(new Intent(this, StartConversationActivity.class));
636				finish();
637			} else {
638				spl.openPane();
639				// find currently loaded fragment
640				ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
641						.findFragmentByTag("conversation");
642				if (selectedFragment != null) {
643					selectedFragment.onBackendConnected();
644				} else {
645					setSelectedConversation(conversationList.get(0));
646					swapConversationFragment();
647				}
648				ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
649			}
650		}
651	}
652
653	public void registerListener() {
654		if (xmppConnectionServiceBound) {
655			xmppConnectionService
656					.setOnConversationListChangedListener(this.onConvChanged);
657		}
658	}
659
660	@Override
661	protected void onActivityResult(int requestCode, int resultCode,
662			final Intent data) {
663		super.onActivityResult(requestCode, resultCode, data);
664		if (resultCode == RESULT_OK) {
665			if (requestCode == REQUEST_DECRYPT_PGP) {
666				ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
667						.findFragmentByTag("conversation");
668				if (selectedFragment != null) {
669					selectedFragment.hideSnackbar();
670				}
671			} else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
672				pendingImageUri = data.getData();
673				if (xmppConnectionServiceBound) {
674					attachImageToConversation(getSelectedConversation(),pendingImageUri);
675					pendingImageUri = null;
676				}
677			} else if (requestCode == REQUEST_SEND_PGP_IMAGE) {
678
679			} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
680				attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
681			} else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
682				attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
683			} else if (requestCode == REQUEST_ANNOUNCE_PGP) {
684				announcePgp(getSelectedConversation().getAccount(),
685						getSelectedConversation());
686			} else if (requestCode == REQUEST_ENCRYPT_MESSAGE) {
687				// encryptTextMessage();
688			} else if (requestCode == REQUEST_IMAGE_CAPTURE) {
689				if (xmppConnectionServiceBound) {
690					attachImageToConversation(getSelectedConversation(), pendingImageUri);
691					pendingImageUri = null;
692				}
693				Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
694				intent.setData(pendingImageUri);
695				sendBroadcast(intent);
696			} else if (requestCode == REQUEST_RECORD_AUDIO) {
697				attachAudioToConversation(getSelectedConversation(),
698						data.getData());
699			}
700		}
701	}
702
703	private void attachAudioToConversation(Conversation conversation, Uri uri) {
704		
705	}
706
707	private void attachImageToConversation(Conversation conversation, Uri uri) {
708		prepareImageToast = Toast.makeText(getApplicationContext(),
709				getText(R.string.preparing_image), Toast.LENGTH_LONG);
710		prepareImageToast.show();
711		xmppConnectionService.attachImageToConversation(conversation, uri,
712				new UiCallback<Message>() {
713
714					@Override
715					public void userInputRequried(PendingIntent pi,
716							Message object) {
717						hidePrepareImageToast();
718						ConversationActivity.this.runIntent(pi,
719								ConversationActivity.REQUEST_SEND_PGP_IMAGE);
720					}
721
722					@Override
723					public void success(Message message) {
724						xmppConnectionService.sendMessage(message);
725					}
726
727					@Override
728					public void error(int error, Message message) {
729						hidePrepareImageToast();
730						displayErrorDialog(error);
731					}
732				});
733	}
734
735	private void hidePrepareImageToast() {
736		if (prepareImageToast != null) {
737			runOnUiThread(new Runnable() {
738
739				@Override
740				public void run() {
741					prepareImageToast.cancel();
742				}
743			});
744		}
745	}
746
747	public void updateConversationList() {
748		xmppConnectionService.populateWithOrderedConversations(conversationList);
749		listView.invalidateViews();
750	}
751
752	public boolean showLastseen() {
753		if (getSelectedConversation() == null) {
754			return false;
755		} else {
756			return this.showLastseen
757					&& getSelectedConversation().getMode() == Conversation.MODE_SINGLE;
758		}
759	}
760
761	public void runIntent(PendingIntent pi, int requestCode) {
762		try {
763			this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
764					null, 0, 0, 0);
765		} catch (SendIntentException e1) {}
766	}
767
768	class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
769		private final WeakReference<ImageView> imageViewReference;
770		private Message message = null;
771
772		public BitmapWorkerTask(ImageView imageView) {
773			imageViewReference = new WeakReference<ImageView>(imageView);
774		}
775
776		@Override
777		protected Bitmap doInBackground(Message... params) {
778			message = params[0];
779			try {
780				return xmppConnectionService.getFileBackend().getThumbnail(
781						message, (int) (metrics.density * 288), false);
782			} catch (FileNotFoundException e) {
783				return null;
784			}
785		}
786
787		@Override
788		protected void onPostExecute(Bitmap bitmap) {
789			if (imageViewReference != null && bitmap != null) {
790				final ImageView imageView = imageViewReference.get();
791				if (imageView != null) {
792					imageView.setImageBitmap(bitmap);
793					imageView.setBackgroundColor(0x00000000);
794				}
795			}
796		}
797	}
798
799	public void loadBitmap(Message message, ImageView imageView) {
800		Bitmap bm;
801		try {
802			bm = xmppConnectionService.getFileBackend().getThumbnail(message,
803					(int) (metrics.density * 288), true);
804		} catch (FileNotFoundException e) {
805			bm = null;
806		}
807		if (bm != null) {
808			imageView.setImageBitmap(bm);
809			imageView.setBackgroundColor(0x00000000);
810		} else {
811			if (cancelPotentialWork(message, imageView)) {
812				imageView.setBackgroundColor(0xff333333);
813				final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
814				final AsyncDrawable asyncDrawable = new AsyncDrawable(
815						getResources(), null, task);
816				imageView.setImageDrawable(asyncDrawable);
817				try {
818					task.execute(message);
819				} catch (RejectedExecutionException e) {
820					return;
821				}
822			}
823		}
824	}
825
826	public static boolean cancelPotentialWork(Message message,
827			ImageView imageView) {
828		final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
829
830		if (bitmapWorkerTask != null) {
831			final Message oldMessage = bitmapWorkerTask.message;
832			if (oldMessage == null || message != oldMessage) {
833				bitmapWorkerTask.cancel(true);
834			} else {
835				return false;
836			}
837		}
838		return true;
839	}
840
841	private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
842		if (imageView != null) {
843			final Drawable drawable = imageView.getDrawable();
844			if (drawable instanceof AsyncDrawable) {
845				final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
846				return asyncDrawable.getBitmapWorkerTask();
847			}
848		}
849		return null;
850	}
851
852	static class AsyncDrawable extends BitmapDrawable {
853		private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
854
855		public AsyncDrawable(Resources res, Bitmap bitmap,
856				BitmapWorkerTask bitmapWorkerTask) {
857			super(res, bitmap);
858			bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
859					bitmapWorkerTask);
860		}
861
862		public BitmapWorkerTask getBitmapWorkerTask() {
863			return bitmapWorkerTaskReference.get();
864		}
865	}
866
867	public void encryptTextMessage(Message message) {
868		xmppConnectionService.getPgpEngine().encrypt(message,
869				new UiCallback<Message>() {
870
871					@Override
872					public void userInputRequried(PendingIntent pi,
873							Message message) {
874						activity.runIntent(pi,
875								ConversationActivity.REQUEST_SEND_MESSAGE);
876					}
877
878					@Override
879					public void success(Message message) {
880						message.setEncryption(Message.ENCRYPTION_DECRYPTED);
881						xmppConnectionService.sendMessage(message);
882					}
883
884					@Override
885					public void error(int error, Message message) {
886
887					}
888				});
889	}
890}