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