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