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