ConversationActivity.java

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