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