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