1package eu.siacs.conversations.ui;
2
3import java.io.FileNotFoundException;
4import java.lang.ref.WeakReference;
5import java.util.ArrayList;
6import java.util.List;
7
8import eu.siacs.conversations.R;
9import eu.siacs.conversations.entities.Contact;
10import eu.siacs.conversations.entities.Conversation;
11import eu.siacs.conversations.entities.Message;
12import eu.siacs.conversations.services.ImageProvider;
13import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
14import eu.siacs.conversations.utils.ExceptionHelper;
15import eu.siacs.conversations.utils.UIHelper;
16import android.net.Uri;
17import android.os.AsyncTask;
18import android.os.Bundle;
19import android.preference.PreferenceManager;
20import android.provider.MediaStore;
21import android.app.AlertDialog;
22import android.app.FragmentTransaction;
23import android.app.PendingIntent;
24import android.content.Context;
25import android.content.DialogInterface;
26import android.content.DialogInterface.OnClickListener;
27import android.content.IntentSender.SendIntentException;
28import android.content.Intent;
29import android.content.SharedPreferences;
30import android.content.res.Resources;
31import android.graphics.Bitmap;
32import android.graphics.Color;
33import android.graphics.Typeface;
34import android.graphics.drawable.BitmapDrawable;
35import android.graphics.drawable.Drawable;
36import android.support.v4.widget.SlidingPaneLayout;
37import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener;
38import android.util.DisplayMetrics;
39import android.view.KeyEvent;
40import android.view.LayoutInflater;
41import android.view.Menu;
42import android.view.MenuItem;
43import android.view.View;
44import android.view.ViewGroup;
45import android.widget.AdapterView;
46import android.widget.AdapterView.OnItemClickListener;
47import android.widget.ArrayAdapter;
48import android.widget.CheckBox;
49import android.widget.ListView;
50import android.widget.PopupMenu;
51import android.widget.PopupMenu.OnMenuItemClickListener;
52import android.widget.TextView;
53import android.widget.ImageView;
54import android.widget.Toast;
55
56public class ConversationActivity extends XmppActivity {
57
58 public static final String VIEW_CONVERSATION = "viewConversation";
59 public static final String CONVERSATION = "conversationUuid";
60 public static final String TEXT = "text";
61 public static final String PRESENCE = "eu.siacs.conversations.presence";
62
63 public static final int REQUEST_SEND_MESSAGE = 0x75441;
64 public static final int REQUEST_DECRYPT_PGP = 0x76783;
65 private static final int REQUEST_ATTACH_FILE_DIALOG = 0x48502;
66 private static final int REQUEST_IMAGE_CAPTURE = 0x33788;
67 private static final int REQUEST_RECORD_AUDIO = 0x46189;
68 private static final int REQUEST_SEND_PGP_IMAGE = 0x53883;
69 public static final int REQUEST_ENCRYPT_MESSAGE = 0x378018;
70
71 private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x92734;
72 private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x84123;
73 private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x75291;
74
75 protected SlidingPaneLayout spl;
76
77 private List<Conversation> conversationList = new ArrayList<Conversation>();
78 private Conversation selectedConversation = null;
79 private ListView listView;
80
81 private boolean paneShouldBeOpen = true;
82 private boolean useSubject = true;
83 private boolean showLastseen = false;
84 private ArrayAdapter<Conversation> listAdapter;
85
86 private OnConversationUpdate onConvChanged = new OnConversationUpdate() {
87
88 @Override
89 public void onConversationUpdate() {
90 runOnUiThread(new Runnable() {
91
92 @Override
93 public void run() {
94 updateConversationList();
95 if (paneShouldBeOpen) {
96 if (conversationList.size() >= 1) {
97 swapConversationFragment();
98 } else {
99 startActivity(new Intent(getApplicationContext(),
100 StartConversationActivity.class));
101 finish();
102 }
103 }
104 ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
105 .findFragmentByTag("conversation");
106 if (selectedFragment != null) {
107 selectedFragment.updateMessages();
108 }
109 }
110 });
111 }
112 };
113
114 protected ConversationActivity activity = this;
115 private DisplayMetrics metrics;
116 private Toast prepareImageToast;
117
118 public List<Conversation> getConversationList() {
119 return this.conversationList;
120 }
121
122 public Conversation getSelectedConversation() {
123 return this.selectedConversation;
124 }
125
126 public void setSelectedConversation(Conversation conversation) {
127 this.selectedConversation = conversation;
128 }
129
130 public ListView getConversationListView() {
131 return this.listView;
132 }
133
134 public SlidingPaneLayout getSlidingPaneLayout() {
135 return this.spl;
136 }
137
138 public boolean shouldPaneBeOpen() {
139 return paneShouldBeOpen;
140 }
141
142 @Override
143 protected void onCreate(Bundle savedInstanceState) {
144
145 metrics = getResources().getDisplayMetrics();
146
147 super.onCreate(savedInstanceState);
148
149 setContentView(R.layout.fragment_conversations_overview);
150
151 listView = (ListView) findViewById(R.id.list);
152
153 this.listAdapter = new ArrayAdapter<Conversation>(this,
154 R.layout.conversation_list_row, conversationList) {
155 @Override
156 public View getView(int position, View view, ViewGroup parent) {
157 if (view == null) {
158 LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
159 view = (View) inflater.inflate(
160 R.layout.conversation_list_row, null);
161 }
162 Conversation conv;
163 if (conversationList.size() > position) {
164 conv = getItem(position);
165 } else {
166 return view;
167 }
168 if (!spl.isSlideable()) {
169 if (conv == getSelectedConversation()) {
170 view.setBackgroundColor(0xffdddddd);
171 } else {
172 view.setBackgroundColor(Color.TRANSPARENT);
173 }
174 } else {
175 view.setBackgroundColor(Color.TRANSPARENT);
176 }
177 TextView convName = (TextView) view
178 .findViewById(R.id.conversation_name);
179 convName.setText(conv.getName(useSubject));
180 TextView convLastMsg = (TextView) view
181 .findViewById(R.id.conversation_lastmsg);
182 ImageView imagePreview = (ImageView) view
183 .findViewById(R.id.conversation_lastimage);
184
185 Message latestMessage = conv.getLatestMessage();
186
187 if (latestMessage.getType() == Message.TYPE_TEXT) {
188 if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP)
189 && (latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) {
190 convLastMsg.setText(conv.getLatestMessage().getBody());
191 } else {
192 convLastMsg
193 .setText(getText(R.string.encrypted_message_received));
194 }
195 convLastMsg.setVisibility(View.VISIBLE);
196 imagePreview.setVisibility(View.GONE);
197 } else if (latestMessage.getType() == Message.TYPE_IMAGE) {
198 if (latestMessage.getStatus() >= Message.STATUS_RECIEVED) {
199 convLastMsg.setVisibility(View.GONE);
200 imagePreview.setVisibility(View.VISIBLE);
201 loadBitmap(latestMessage, imagePreview);
202 } else {
203 convLastMsg.setVisibility(View.VISIBLE);
204 imagePreview.setVisibility(View.GONE);
205 if (latestMessage.getStatus() == Message.STATUS_RECEIVED_OFFER) {
206 convLastMsg
207 .setText(getText(R.string.image_offered_for_download));
208 } else if (latestMessage.getStatus() == Message.STATUS_RECIEVING) {
209 convLastMsg
210 .setText(getText(R.string.receiving_image));
211 } else {
212 convLastMsg.setText("");
213 }
214 }
215 }
216
217 if (!conv.isRead()) {
218 convName.setTypeface(null, Typeface.BOLD);
219 convLastMsg.setTypeface(null, Typeface.BOLD);
220 } else {
221 convName.setTypeface(null, Typeface.NORMAL);
222 convLastMsg.setTypeface(null, Typeface.NORMAL);
223 }
224
225 ((TextView) view.findViewById(R.id.conversation_lastupdate))
226 .setText(UIHelper.readableTimeDifference(getContext(),
227 conv.getLatestMessage().getTimeSent()));
228
229 ImageView profilePicture = (ImageView) view
230 .findViewById(R.id.conversation_image);
231 profilePicture.setImageBitmap(UIHelper.getContactPicture(conv,
232 56, activity.getApplicationContext(), false));
233
234 return view;
235 }
236
237 };
238
239 listView.setAdapter(this.listAdapter);
240
241 listView.setOnItemClickListener(new OnItemClickListener() {
242
243 @Override
244 public void onItemClick(AdapterView<?> arg0, View clickedView,
245 int position, long arg3) {
246 paneShouldBeOpen = false;
247 if (getSelectedConversation() != conversationList.get(position)) {
248 setSelectedConversation(conversationList.get(position));
249 swapConversationFragment(); // .onBackendConnected(conversationList.get(position));
250 } else {
251 spl.closePane();
252 }
253 }
254 });
255 spl = (SlidingPaneLayout) findViewById(R.id.slidingpanelayout);
256 spl.setParallaxDistance(150);
257 spl.setShadowResource(R.drawable.es_slidingpane_shadow);
258 spl.setSliderFadeColor(0);
259 spl.setPanelSlideListener(new PanelSlideListener() {
260
261 @Override
262 public void onPanelOpened(View arg0) {
263 paneShouldBeOpen = true;
264 getActionBar().setDisplayHomeAsUpEnabled(false);
265 getActionBar().setHomeButtonEnabled(false);
266 getActionBar().setTitle(R.string.app_name);
267 invalidateOptionsMenu();
268 hideKeyboard();
269 }
270
271 @Override
272 public void onPanelClosed(View arg0) {
273 paneShouldBeOpen = false;
274 if ((conversationList.size() > 0)
275 && (getSelectedConversation() != null)) {
276 getActionBar().setDisplayHomeAsUpEnabled(true);
277 getActionBar().setHomeButtonEnabled(true);
278 getActionBar().setTitle(
279 getSelectedConversation().getName(useSubject));
280 invalidateOptionsMenu();
281 if (!getSelectedConversation().isRead()) {
282 xmppConnectionService
283 .markRead(getSelectedConversation());
284 UIHelper.updateNotification(getApplicationContext(),
285 getConversationList(), null, false);
286 listView.invalidateViews();
287 }
288 }
289 }
290
291 @Override
292 public void onPanelSlide(View arg0, float arg1) {
293 // TODO Auto-generated method stub
294
295 }
296 });
297 }
298
299 @Override
300 public boolean onCreateOptionsMenu(Menu menu) {
301 getMenuInflater().inflate(R.menu.conversations, menu);
302 MenuItem menuSecure = (MenuItem) menu.findItem(R.id.action_security);
303 MenuItem menuArchive = (MenuItem) menu.findItem(R.id.action_archive);
304 MenuItem menuMucDetails = (MenuItem) menu
305 .findItem(R.id.action_muc_details);
306 MenuItem menuContactDetails = (MenuItem) menu
307 .findItem(R.id.action_contact_details);
308 MenuItem menuAttach = (MenuItem) menu.findItem(R.id.action_attach_file);
309 MenuItem menuClearHistory = (MenuItem) menu
310 .findItem(R.id.action_clear_history);
311 MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add);
312 MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite);
313
314 if ((spl.isOpen() && (spl.isSlideable()))) {
315 menuArchive.setVisible(false);
316 menuMucDetails.setVisible(false);
317 menuContactDetails.setVisible(false);
318 menuSecure.setVisible(false);
319 menuInviteContact.setVisible(false);
320 menuAttach.setVisible(false);
321 menuClearHistory.setVisible(false);
322 } else {
323 menuAdd.setVisible(!spl.isSlideable());
324 if (this.getSelectedConversation() != null) {
325 if (this.getSelectedConversation().getLatestMessage()
326 .getEncryption() != Message.ENCRYPTION_NONE) {
327 menuSecure.setIcon(R.drawable.ic_action_secure);
328 }
329 if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) {
330 menuContactDetails.setVisible(false);
331 menuAttach.setVisible(false);
332 } else {
333 menuMucDetails.setVisible(false);
334 menuInviteContact.setVisible(false);
335 }
336 }
337 }
338 return true;
339 }
340
341 private void selectPresenceToAttachFile(final int attachmentChoice) {
342 selectPresence(getSelectedConversation(), new OnPresenceSelected() {
343
344 @Override
345 public void onPresenceSelected() {
346 if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) {
347 Intent takePictureIntent = new Intent(
348 MediaStore.ACTION_IMAGE_CAPTURE);
349 takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
350 ImageProvider.getIncomingContentUri());
351 if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
352 startActivityForResult(takePictureIntent,
353 REQUEST_IMAGE_CAPTURE);
354 }
355 } else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
356 Intent attachFileIntent = new Intent();
357 attachFileIntent.setType("image/*");
358 attachFileIntent.setAction(Intent.ACTION_GET_CONTENT);
359 Intent chooser = Intent.createChooser(attachFileIntent,
360 getString(R.string.attach_file));
361 startActivityForResult(chooser, REQUEST_ATTACH_FILE_DIALOG);
362 } else if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) {
363 Intent intent = new Intent(
364 MediaStore.Audio.Media.RECORD_SOUND_ACTION);
365 startActivityForResult(intent, REQUEST_RECORD_AUDIO);
366 }
367 }
368 });
369 }
370
371 private void attachFile(final int attachmentChoice) {
372 final Conversation conversation = getSelectedConversation();
373 if (conversation.getNextEncryption() == 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 selectPresenceToAttachFile(attachmentChoice);
410 }
411 });
412 }
413 }
414 } else {
415 showInstallPgpDialog();
416 }
417 } else if (getSelectedConversation().getNextEncryption() == Message.ENCRYPTION_NONE) {
418 selectPresenceToAttachFile(attachmentChoice);
419 } else {
420 selectPresenceToAttachFile(attachmentChoice);
421 }
422 }
423
424 @Override
425 public boolean onOptionsItemSelected(MenuItem item) {
426 switch (item.getItemId()) {
427 case android.R.id.home:
428 spl.openPane();
429 break;
430 case R.id.action_attach_file:
431 View menuAttachFile = findViewById(R.id.action_attach_file);
432 if (menuAttachFile==null) {
433 break;
434 }
435 PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile);
436 attachFilePopup.inflate(R.menu.attachment_choices);
437 attachFilePopup
438 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
439
440 @Override
441 public boolean onMenuItemClick(MenuItem item) {
442 switch (item.getItemId()) {
443 case R.id.attach_choose_picture:
444 attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
445 break;
446 case R.id.attach_take_picture:
447 attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
448 break;
449 case R.id.attach_record_voice:
450 attachFile(ATTACHMENT_CHOICE_RECORD_VOICE);
451 break;
452 }
453 return false;
454 }
455 });
456 attachFilePopup.show();
457 break;
458 case R.id.action_add:
459 startActivity(new Intent(this, StartConversationActivity.class));
460 break;
461 case R.id.action_archive:
462 this.endConversation(getSelectedConversation());
463 break;
464 case R.id.action_contact_details:
465 Contact contact = this.getSelectedConversation().getContact();
466 if (contact.showInRoster()) {
467 switchToContactDetails(contact);
468 } else {
469 showAddToRosterDialog(getSelectedConversation());
470 }
471 break;
472 case R.id.action_muc_details:
473 Intent intent = new Intent(this, ConferenceDetailsActivity.class);
474 intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
475 intent.putExtra("uuid", getSelectedConversation().getUuid());
476 startActivity(intent);
477 break;
478 case R.id.action_invite:
479 inviteToConversation(getSelectedConversation());
480 break;
481 case R.id.action_security:
482 final Conversation conversation = getSelectedConversation();
483 View menuItemView = findViewById(R.id.action_security);
484 if (menuItemView==null) {
485 break;
486 }
487 PopupMenu popup = new PopupMenu(this, menuItemView);
488 final ConversationFragment fragment = (ConversationFragment) getFragmentManager()
489 .findFragmentByTag("conversation");
490 if (fragment != null) {
491 popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
492
493 @Override
494 public boolean onMenuItemClick(MenuItem item) {
495 switch (item.getItemId()) {
496 case R.id.encryption_choice_none:
497 conversation
498 .setNextEncryption(Message.ENCRYPTION_NONE);
499 item.setChecked(true);
500 break;
501 case R.id.encryption_choice_otr:
502 conversation
503 .setNextEncryption(Message.ENCRYPTION_OTR);
504 item.setChecked(true);
505 break;
506 case R.id.encryption_choice_pgp:
507 if (hasPgp()) {
508 if (conversation.getAccount().getKeys()
509 .has("pgp_signature")) {
510 conversation
511 .setNextEncryption(Message.ENCRYPTION_PGP);
512 item.setChecked(true);
513 } else {
514 announcePgp(conversation.getAccount(),
515 conversation);
516 }
517 } else {
518 showInstallPgpDialog();
519 }
520 break;
521 default:
522 conversation
523 .setNextEncryption(Message.ENCRYPTION_NONE);
524 break;
525 }
526 fragment.updateChatMsgHint();
527 return true;
528 }
529 });
530 popup.inflate(R.menu.encryption_choices);
531 MenuItem otr = popup.getMenu().findItem(
532 R.id.encryption_choice_otr);
533 if (conversation.getMode() == Conversation.MODE_MULTI) {
534 otr.setEnabled(false);
535 }
536 switch (conversation.getNextEncryption()) {
537 case Message.ENCRYPTION_NONE:
538 popup.getMenu().findItem(R.id.encryption_choice_none)
539 .setChecked(true);
540 break;
541 case Message.ENCRYPTION_OTR:
542 otr.setChecked(true);
543 break;
544 case Message.ENCRYPTION_PGP:
545 popup.getMenu().findItem(R.id.encryption_choice_pgp)
546 .setChecked(true);
547 break;
548 default:
549 popup.getMenu().findItem(R.id.encryption_choice_none)
550 .setChecked(true);
551 break;
552 }
553 popup.show();
554 }
555
556 break;
557 case R.id.action_clear_history:
558 clearHistoryDialog(getSelectedConversation());
559 break;
560 default:
561 break;
562 }
563 return super.onOptionsItemSelected(item);
564 }
565
566 public void endConversation(Conversation conversation) {
567 conversation.setStatus(Conversation.STATUS_ARCHIVED);
568 paneShouldBeOpen = true;
569 spl.openPane();
570 xmppConnectionService.archiveConversation(conversation);
571 if (conversationList.size() > 0) {
572 setSelectedConversation(conversationList.get(0));
573 } else {
574 setSelectedConversation(null);
575 }
576 }
577
578 protected void clearHistoryDialog(final Conversation conversation) {
579 AlertDialog.Builder builder = new AlertDialog.Builder(this);
580 builder.setTitle(getString(R.string.clear_conversation_history));
581 View dialogView = getLayoutInflater().inflate(
582 R.layout.dialog_clear_history, null);
583 final CheckBox endConversationCheckBox = (CheckBox) dialogView
584 .findViewById(R.id.end_conversation_checkbox);
585 builder.setView(dialogView);
586 builder.setNegativeButton(getString(R.string.cancel), null);
587 builder.setPositiveButton(getString(R.string.delete_messages),
588 new OnClickListener() {
589
590 @Override
591 public void onClick(DialogInterface dialog, int which) {
592 activity.xmppConnectionService
593 .clearConversationHistory(conversation);
594 if (endConversationCheckBox.isChecked()) {
595 endConversation(conversation);
596 }
597 }
598 });
599 builder.create().show();
600 }
601
602 protected ConversationFragment swapConversationFragment() {
603 ConversationFragment selectedFragment = new ConversationFragment();
604
605 FragmentTransaction transaction = getFragmentManager()
606 .beginTransaction();
607 transaction.replace(R.id.selected_conversation, selectedFragment,
608 "conversation");
609 transaction.commitAllowingStateLoss();
610 return selectedFragment;
611 }
612
613 @Override
614 public boolean onKeyDown(int keyCode, KeyEvent event) {
615 if (keyCode == KeyEvent.KEYCODE_BACK) {
616 if (!spl.isOpen()) {
617 spl.openPane();
618 return false;
619 }
620 }
621 return super.onKeyDown(keyCode, event);
622 }
623
624 @Override
625 protected void onNewIntent(Intent intent) {
626 if (xmppConnectionServiceBound) {
627 if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION
628 .equals(intent.getType())))) {
629 String convToView = (String) intent.getExtras().get(CONVERSATION);
630 updateConversationList();
631 for (int i = 0; i < conversationList.size(); ++i) {
632 if (conversationList.get(i).getUuid().equals(convToView)) {
633 setSelectedConversation(conversationList.get(i));
634 break;
635 }
636 }
637 paneShouldBeOpen = false;
638 String text = intent.getExtras().getString(TEXT, null);
639 swapConversationFragment().setText(text);
640 }
641 } else {
642 handledViewIntent = false;
643 setIntent(intent);
644 }
645 }
646
647 @Override
648 public void onStart() {
649 super.onStart();
650 SharedPreferences preferences = PreferenceManager
651 .getDefaultSharedPreferences(this);
652 this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
653 this.showLastseen = preferences.getBoolean("show_last_seen", false);
654 if (this.xmppConnectionServiceBound) {
655 this.onBackendConnected();
656 }
657 if (conversationList.size() >= 1) {
658 onConvChanged.onConversationUpdate();
659 }
660 }
661
662 @Override
663 protected void onStop() {
664 if (xmppConnectionServiceBound) {
665 xmppConnectionService.removeOnConversationListChangedListener();
666 }
667 super.onStop();
668 }
669
670 @Override
671 void onBackendConnected() {
672 this.registerListener();
673 if (conversationList.size() == 0) {
674 updateConversationList();
675 }
676
677 if ((getIntent().getAction() != null)
678 && (getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
679 if (getIntent().getType().equals(
680 ConversationActivity.VIEW_CONVERSATION)) {
681 handledViewIntent = true;
682
683 String convToView = (String) getIntent().getExtras().get(
684 CONVERSATION);
685
686 for (int i = 0; i < conversationList.size(); ++i) {
687 if (conversationList.get(i).getUuid().equals(convToView)) {
688 setSelectedConversation(conversationList.get(i));
689 }
690 }
691 paneShouldBeOpen = false;
692 String text = getIntent().getExtras().getString(TEXT, null);
693 swapConversationFragment().setText(text);
694 }
695 } else {
696 if (xmppConnectionService.getAccounts().size() == 0) {
697 startActivity(new Intent(this, ManageAccountActivity.class));
698 finish();
699 } else if (conversationList.size() <= 0) {
700 // add no history
701 startActivity(new Intent(this, StartConversationActivity.class));
702 finish();
703 } else {
704 spl.openPane();
705 // find currently loaded fragment
706 ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
707 .findFragmentByTag("conversation");
708 if (selectedFragment != null) {
709 selectedFragment.onBackendConnected();
710 } else {
711 setSelectedConversation(conversationList.get(0));
712 swapConversationFragment();
713 }
714 ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
715 }
716 }
717 }
718
719 public void registerListener() {
720 if (xmppConnectionServiceBound) {
721 xmppConnectionService
722 .setOnConversationListChangedListener(this.onConvChanged);
723 }
724 }
725
726 @Override
727 protected void onActivityResult(int requestCode, int resultCode,
728 final Intent data) {
729 super.onActivityResult(requestCode, resultCode, data);
730 if (resultCode == RESULT_OK) {
731 if (requestCode == REQUEST_DECRYPT_PGP) {
732 ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager()
733 .findFragmentByTag("conversation");
734 if (selectedFragment != null) {
735 selectedFragment.hideSnackbar();
736 }
737 } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) {
738 attachImageToConversation(getSelectedConversation(),
739 data.getData());
740 } else if (requestCode == REQUEST_SEND_PGP_IMAGE) {
741
742 } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
743 attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE);
744 } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
745 attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO);
746 } else if (requestCode == REQUEST_ANNOUNCE_PGP) {
747 announcePgp(getSelectedConversation().getAccount(),
748 getSelectedConversation());
749 } else if (requestCode == REQUEST_ENCRYPT_MESSAGE) {
750 // encryptTextMessage();
751 } else if (requestCode == REQUEST_IMAGE_CAPTURE) {
752 attachImageToConversation(getSelectedConversation(), null);
753 } else if (requestCode == REQUEST_RECORD_AUDIO) {
754 attachAudioToConversation(getSelectedConversation(),
755 data.getData());
756 }
757 }
758 }
759
760 private void attachAudioToConversation(Conversation conversation, Uri uri) {
761
762 }
763
764 private void attachImageToConversation(Conversation conversation, Uri uri) {
765 prepareImageToast = Toast.makeText(getApplicationContext(),
766 getText(R.string.preparing_image), Toast.LENGTH_LONG);
767 prepareImageToast.show();
768 xmppConnectionService.attachImageToConversation(conversation, uri,
769 new UiCallback<Message>() {
770
771 @Override
772 public void userInputRequried(PendingIntent pi,
773 Message object) {
774 hidePrepareImageToast();
775 ConversationActivity.this.runIntent(pi,
776 ConversationActivity.REQUEST_SEND_PGP_IMAGE);
777 }
778
779 @Override
780 public void success(Message message) {
781 xmppConnectionService.sendMessage(message);
782 }
783
784 @Override
785 public void error(int error, Message message) {
786 hidePrepareImageToast();
787 displayErrorDialog(error);
788 }
789 });
790 }
791
792 private void hidePrepareImageToast() {
793 if (prepareImageToast != null) {
794 runOnUiThread(new Runnable() {
795
796 @Override
797 public void run() {
798 prepareImageToast.cancel();
799 }
800 });
801 }
802 }
803
804 public void updateConversationList() {
805 xmppConnectionService.populateWithOrderedConversations(conversationList);
806 listView.invalidateViews();
807 }
808
809 public boolean showLastseen() {
810 if (getSelectedConversation() == null) {
811 return false;
812 } else {
813 return this.showLastseen
814 && getSelectedConversation().getMode() == Conversation.MODE_SINGLE;
815 }
816 }
817
818 public void runIntent(PendingIntent pi, int requestCode) {
819 try {
820 this.startIntentSenderForResult(pi.getIntentSender(), requestCode,
821 null, 0, 0, 0);
822 } catch (SendIntentException e1) {}
823 }
824
825 class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> {
826 private final WeakReference<ImageView> imageViewReference;
827 private Message message = null;
828
829 public BitmapWorkerTask(ImageView imageView) {
830 imageViewReference = new WeakReference<ImageView>(imageView);
831 }
832
833 @Override
834 protected Bitmap doInBackground(Message... params) {
835 message = params[0];
836 try {
837 return xmppConnectionService.getFileBackend().getThumbnail(
838 message, (int) (metrics.density * 288), false);
839 } catch (FileNotFoundException e) {
840 return null;
841 }
842 }
843
844 @Override
845 protected void onPostExecute(Bitmap bitmap) {
846 if (imageViewReference != null && bitmap != null) {
847 final ImageView imageView = imageViewReference.get();
848 if (imageView != null) {
849 imageView.setImageBitmap(bitmap);
850 imageView.setBackgroundColor(0x00000000);
851 }
852 }
853 }
854 }
855
856 public void loadBitmap(Message message, ImageView imageView) {
857 Bitmap bm;
858 try {
859 bm = xmppConnectionService.getFileBackend().getThumbnail(message,
860 (int) (metrics.density * 288), true);
861 } catch (FileNotFoundException e) {
862 bm = null;
863 }
864 if (bm != null) {
865 imageView.setImageBitmap(bm);
866 imageView.setBackgroundColor(0x00000000);
867 } else {
868 if (cancelPotentialWork(message, imageView)) {
869 imageView.setBackgroundColor(0xff333333);
870 final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
871 final AsyncDrawable asyncDrawable = new AsyncDrawable(
872 getResources(), null, task);
873 imageView.setImageDrawable(asyncDrawable);
874 task.execute(message);
875 }
876 }
877 }
878
879 public static boolean cancelPotentialWork(Message message,
880 ImageView imageView) {
881 final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
882
883 if (bitmapWorkerTask != null) {
884 final Message oldMessage = bitmapWorkerTask.message;
885 if (oldMessage == null || message != oldMessage) {
886 bitmapWorkerTask.cancel(true);
887 } else {
888 return false;
889 }
890 }
891 return true;
892 }
893
894 private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
895 if (imageView != null) {
896 final Drawable drawable = imageView.getDrawable();
897 if (drawable instanceof AsyncDrawable) {
898 final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
899 return asyncDrawable.getBitmapWorkerTask();
900 }
901 }
902 return null;
903 }
904
905 static class AsyncDrawable extends BitmapDrawable {
906 private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
907
908 public AsyncDrawable(Resources res, Bitmap bitmap,
909 BitmapWorkerTask bitmapWorkerTask) {
910 super(res, bitmap);
911 bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(
912 bitmapWorkerTask);
913 }
914
915 public BitmapWorkerTask getBitmapWorkerTask() {
916 return bitmapWorkerTaskReference.get();
917 }
918 }
919
920 public void encryptTextMessage(Message message) {
921 xmppConnectionService.getPgpEngine().encrypt(message,
922 new UiCallback<Message>() {
923
924 @Override
925 public void userInputRequried(PendingIntent pi,
926 Message message) {
927 activity.runIntent(pi,
928 ConversationActivity.REQUEST_SEND_MESSAGE);
929 }
930
931 @Override
932 public void success(Message message) {
933 message.setEncryption(Message.ENCRYPTION_DECRYPTED);
934 xmppConnectionService.sendMessage(message);
935 }
936
937 @Override
938 public void error(int error, Message message) {
939
940 }
941 });
942 }
943}