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