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}