1package eu.siacs.conversations.ui;
2
3import java.util.ArrayList;
4import java.util.HashMap;
5import java.util.List;
6import java.util.Set;
7
8import net.java.otr4j.session.SessionStatus;
9import eu.siacs.conversations.R;
10import eu.siacs.conversations.crypto.PgpEngine;
11import eu.siacs.conversations.entities.Contact;
12import eu.siacs.conversations.entities.Conversation;
13import eu.siacs.conversations.entities.Message;
14import eu.siacs.conversations.entities.MucOptions;
15import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
16import eu.siacs.conversations.services.ImageProvider;
17import eu.siacs.conversations.services.XmppConnectionService;
18import eu.siacs.conversations.utils.UIHelper;
19import eu.siacs.conversations.xmpp.jingle.JingleConnection;
20import android.app.AlertDialog;
21import android.app.Fragment;
22import android.app.PendingIntent;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.Intent;
26import android.content.IntentSender;
27import android.content.SharedPreferences;
28import android.content.IntentSender.SendIntentException;
29import android.graphics.Bitmap;
30import android.graphics.Typeface;
31import android.os.Bundle;
32import android.preference.PreferenceManager;
33import android.text.Editable;
34import android.text.Selection;
35import android.util.DisplayMetrics;
36import android.util.Log;
37import android.view.LayoutInflater;
38import android.view.View;
39import android.view.View.OnClickListener;
40import android.view.ViewGroup;
41import android.widget.ArrayAdapter;
42import android.widget.Button;
43import android.widget.EditText;
44import android.widget.LinearLayout;
45import android.widget.ListView;
46import android.widget.ImageButton;
47import android.widget.ImageView;
48import android.widget.TextView;
49import android.widget.Toast;
50
51public class ConversationFragment extends Fragment {
52
53 protected Conversation conversation;
54 protected ListView messagesView;
55 protected LayoutInflater inflater;
56 protected List<Message> messageList = new ArrayList<Message>();
57 protected ArrayAdapter<Message> messageListAdapter;
58 protected Contact contact;
59 protected BitmapCache mBitmapCache = new BitmapCache();
60
61 protected String queuedPqpMessage = null;
62
63 private EditText chatMsg;
64 private String pastedText = null;
65
66 protected Bitmap selfBitmap;
67
68 private boolean useSubject = true;
69
70 private IntentSender askForPassphraseIntent = null;
71
72 private OnClickListener sendMsgListener = new OnClickListener() {
73
74 @Override
75 public void onClick(View v) {
76 if (chatMsg.getText().length() < 1)
77 return;
78 Message message = new Message(conversation, chatMsg.getText()
79 .toString(), conversation.getNextEncryption());
80 if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
81 sendOtrMessage(message);
82 } else if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
83 sendPgpMessage(message);
84 } else {
85 sendPlainTextMessage(message);
86 }
87 }
88 };
89 protected OnClickListener clickToDecryptListener = new OnClickListener() {
90
91 @Override
92 public void onClick(View v) {
93 if (askForPassphraseIntent != null) {
94 try {
95 getActivity().startIntentSenderForResult(
96 askForPassphraseIntent,
97 ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
98 0, 0);
99 } catch (SendIntentException e) {
100 Log.d("xmppService", "couldnt fire intent");
101 }
102 }
103 }
104 };
105
106 private LinearLayout pgpInfo;
107 private LinearLayout mucError;
108 private TextView mucErrorText;
109 private OnClickListener clickToMuc = new OnClickListener() {
110
111 @Override
112 public void onClick(View v) {
113 Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
114 intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
115 intent.putExtra("uuid", conversation.getUuid());
116 startActivity(intent);
117 }
118 };
119 private ConversationActivity activity;
120
121 public void hidePgpPassphraseBox() {
122 pgpInfo.setVisibility(View.GONE);
123 }
124
125 public void updateChatMsgHint() {
126 if (conversation.getMode() == Conversation.MODE_MULTI) {
127 chatMsg.setHint(getString(R.string.send_message_to_conference));
128 } else {
129 switch (conversation.getNextEncryption()) {
130 case Message.ENCRYPTION_NONE:
131 chatMsg.setHint(getString(R.string.send_plain_text_message));
132 break;
133 case Message.ENCRYPTION_OTR:
134 chatMsg.setHint(getString(R.string.send_otr_message));
135 break;
136 case Message.ENCRYPTION_PGP:
137 chatMsg.setHint(getString(R.string.send_pgp_message));
138 break;
139 default:
140 break;
141 }
142 }
143 }
144
145 @Override
146 public View onCreateView(final LayoutInflater inflater,
147 ViewGroup container, Bundle savedInstanceState) {
148
149 final DisplayMetrics metrics = getResources().getDisplayMetrics();
150
151 this.inflater = inflater;
152
153 final View view = inflater.inflate(R.layout.fragment_conversation,
154 container, false);
155 chatMsg = (EditText) view.findViewById(R.id.textinput);
156
157 ImageButton sendButton = (ImageButton) view
158 .findViewById(R.id.textSendButton);
159 sendButton.setOnClickListener(this.sendMsgListener);
160
161 pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
162 pgpInfo.setOnClickListener(clickToDecryptListener);
163 mucError = (LinearLayout) view.findViewById(R.id.muc_error);
164 mucError.setOnClickListener(clickToMuc);
165 mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
166
167 messagesView = (ListView) view.findViewById(R.id.messages_view);
168
169 messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
170 .getApplicationContext(), R.layout.message_sent,
171 this.messageList) {
172
173 private static final int SENT = 0;
174 private static final int RECIEVED = 1;
175
176 @Override
177 public int getViewTypeCount() {
178 return 2;
179 }
180
181 @Override
182 public int getItemViewType(int position) {
183 if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
184 return RECIEVED;
185 } else {
186 return SENT;
187 }
188 }
189
190 private void displayStatus(ViewHolder viewHolder, Message message) {
191 String filesize = null;
192 String info = null;
193 boolean error = false;
194 if (message.getType() == Message.TYPE_IMAGE) {
195 String[] fileParams = message.getBody().split(",");
196 try {
197 long size = Long.parseLong(fileParams[0]);
198 filesize = size / 1024 + " KB";
199 } catch (NumberFormatException e) {
200 filesize = "0 KB";
201 }
202 }
203 switch (message.getStatus()) {
204 case Message.STATUS_UNSEND:
205 info = getString(R.string.sending);
206 break;
207 case Message.STATUS_OFFERED:
208 info = getString(R.string.offering);
209 break;
210 case Message.STATUS_SEND_FAILED:
211 info = getString(R.string.send_failed);
212 error = true;
213 break;
214 case Message.STATUS_SEND_REJECTED:
215 info = getString(R.string.send_rejected);
216 error = true;
217 break;
218 default:
219 if ((message.getConversation().getMode() == Conversation.MODE_MULTI)
220 && (message.getStatus() <= Message.STATUS_RECIEVED)) {
221 info = message.getCounterpart();
222 }
223 break;
224 }
225 if (error) {
226 viewHolder.time.setTextColor(0xFFe92727);
227 } else {
228 viewHolder.time.setTextColor(0xFF8e8e8e);
229 }
230 if (message.getEncryption() == Message.ENCRYPTION_NONE) {
231 viewHolder.indicator.setVisibility(View.GONE);
232 } else {
233 viewHolder.indicator.setVisibility(View.VISIBLE);
234 }
235
236 String formatedTime = UIHelper.readableTimeDifference(message
237 .getTimeSent());
238 if (message.getStatus() <= Message.STATUS_RECIEVED) {
239 if ((filesize != null) && (info != null)) {
240 viewHolder.time.setText(filesize + " \u00B7 " + info);
241 } else if ((filesize == null) && (info != null)) {
242 viewHolder.time.setText(formatedTime + " \u00B7 "
243 + info);
244 } else if ((filesize != null) && (info == null)) {
245 viewHolder.time.setText(formatedTime + " \u00B7 "
246 + filesize);
247 } else {
248 viewHolder.time.setText(formatedTime);
249 }
250 } else {
251 if ((filesize != null) && (info != null)) {
252 viewHolder.time.setText(filesize + " \u00B7 " + info);
253 } else if ((filesize == null) && (info != null)) {
254 viewHolder.time.setText(info + " \u00B7 "
255 + formatedTime);
256 } else if ((filesize != null) && (info == null)) {
257 viewHolder.time.setText(filesize + " \u00B7 "
258 + formatedTime);
259 } else {
260 viewHolder.time.setText(formatedTime);
261 }
262 }
263 }
264
265 private void displayInfoMessage(ViewHolder viewHolder, int r) {
266 if (viewHolder.download_button!=null) {
267 viewHolder.download_button.setVisibility(View.GONE);
268 }
269 viewHolder.image.setVisibility(View.GONE);
270 viewHolder.messageBody.setVisibility(View.VISIBLE);
271 viewHolder.messageBody.setText(getString(r));
272 viewHolder.messageBody.setTextColor(0xff33B5E5);
273 viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
274 }
275
276 private void displayDecryptionFailed(ViewHolder viewHolder) {
277 viewHolder.download_button.setVisibility(View.GONE);
278 viewHolder.image.setVisibility(View.GONE);
279 viewHolder.messageBody.setVisibility(View.VISIBLE);
280 viewHolder.messageBody
281 .setText(getString(R.string.decryption_failed));
282 viewHolder.messageBody.setTextColor(0xFFe92727);
283 viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
284 }
285
286 private void displayTextMessage(ViewHolder viewHolder, String text) {
287 if (viewHolder.download_button != null) {
288 viewHolder.download_button.setVisibility(View.GONE);
289 }
290 viewHolder.image.setVisibility(View.GONE);
291 viewHolder.messageBody.setVisibility(View.VISIBLE);
292 if (text != null) {
293 viewHolder.messageBody.setText(text.trim());
294 } else {
295 viewHolder.messageBody.setText("");
296 }
297 viewHolder.messageBody.setTextColor(0xff333333);
298 viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
299 }
300
301 private void displayImageMessage(ViewHolder viewHolder,
302 final Message message) {
303 if (viewHolder.download_button != null) {
304 viewHolder.download_button.setVisibility(View.GONE);
305 }
306 viewHolder.messageBody.setVisibility(View.GONE);
307 viewHolder.image.setVisibility(View.VISIBLE);
308 String[] fileParams = message.getBody().split(",");
309 if (fileParams.length == 3) {
310 double target = metrics.density * 288;
311 int w = Integer.parseInt(fileParams[1]);
312 int h = Integer.parseInt(fileParams[2]);
313 int scalledW;
314 int scalledH;
315 if (w <= h) {
316 scalledW = (int) (w / ((double) h / target));
317 scalledH = (int) target;
318 } else {
319 scalledW = (int) target;
320 scalledH = (int) (h / ((double) w / target));
321 }
322 viewHolder.image
323 .setLayoutParams(new LinearLayout.LayoutParams(
324 scalledW, scalledH));
325 }
326 activity.loadBitmap(message, viewHolder.image);
327 viewHolder.image.setOnClickListener(new OnClickListener() {
328
329 @Override
330 public void onClick(View v) {
331 Intent intent = new Intent(Intent.ACTION_VIEW);
332 intent.setDataAndType(ImageProvider.getContentUri(message), "image/*");
333 startActivity(intent);
334 }
335 });
336 }
337
338 @Override
339 public View getView(int position, View view, ViewGroup parent) {
340 final Message item = getItem(position);
341 int type = getItemViewType(position);
342 ViewHolder viewHolder;
343 if (view == null) {
344 viewHolder = new ViewHolder();
345 switch (type) {
346 case SENT:
347 view = (View) inflater.inflate(R.layout.message_sent,
348 null);
349 viewHolder.contact_picture = (ImageView) view
350 .findViewById(R.id.message_photo);
351 viewHolder.contact_picture.setImageBitmap(selfBitmap);
352 break;
353 case RECIEVED:
354 view = (View) inflater.inflate(
355 R.layout.message_recieved, null);
356 viewHolder.contact_picture = (ImageView) view
357 .findViewById(R.id.message_photo);
358
359 viewHolder.download_button = (Button) view
360 .findViewById(R.id.download_button);
361
362 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
363
364 viewHolder.contact_picture
365 .setImageBitmap(mBitmapCache.get(
366 item.getConversation().getName(
367 useSubject), item
368 .getConversation()
369 .getContact(),
370 getActivity()
371 .getApplicationContext()));
372
373 }
374 break;
375 default:
376 viewHolder = null;
377 break;
378 }
379 viewHolder.indicator = (ImageView) view
380 .findViewById(R.id.security_indicator);
381 viewHolder.image = (ImageView) view
382 .findViewById(R.id.message_image);
383 viewHolder.messageBody = (TextView) view
384 .findViewById(R.id.message_body);
385 viewHolder.time = (TextView) view
386 .findViewById(R.id.message_time);
387 view.setTag(viewHolder);
388 } else {
389 viewHolder = (ViewHolder) view.getTag();
390 }
391
392 if (type == RECIEVED) {
393 if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
394 if (item.getCounterpart() != null) {
395 viewHolder.contact_picture
396 .setImageBitmap(mBitmapCache.get(item
397 .getCounterpart(), null,
398 getActivity()
399 .getApplicationContext()));
400 } else {
401 viewHolder.contact_picture
402 .setImageBitmap(mBitmapCache.get(
403 item.getConversation().getName(
404 useSubject), null,
405 getActivity()
406 .getApplicationContext()));
407 }
408 }
409 }
410
411 if (item.getType() == Message.TYPE_IMAGE) {
412 if (item.getStatus() == Message.STATUS_RECIEVING) {
413 displayInfoMessage(viewHolder, R.string.receiving_image);
414 } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
415 viewHolder.image.setVisibility(View.GONE);
416 viewHolder.messageBody.setVisibility(View.GONE);
417 viewHolder.download_button.setVisibility(View.VISIBLE);
418 viewHolder.download_button
419 .setOnClickListener(new OnClickListener() {
420
421 @Override
422 public void onClick(View v) {
423 JingleConnection connection = item
424 .getJingleConnection();
425 if (connection != null) {
426 connection.accept();
427 } else {
428 Log.d("xmppService",
429 "attached jingle connection was null");
430 }
431 }
432 });
433 } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
434 || (item.getEncryption() == Message.ENCRYPTION_NONE)) {
435 displayImageMessage(viewHolder, item);
436 } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
437 displayInfoMessage(viewHolder,
438 R.string.encrypted_message);
439 } else {
440 displayDecryptionFailed(viewHolder);
441 }
442 } else {
443 if (item.getEncryption() == Message.ENCRYPTION_PGP) {
444 displayInfoMessage(viewHolder,
445 R.string.encrypted_message);
446 } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
447 displayDecryptionFailed(viewHolder);
448 } else {
449 displayTextMessage(viewHolder, item.getBody());
450 }
451 }
452
453 displayStatus(viewHolder, item);
454
455 return view;
456 }
457 };
458 messagesView.setAdapter(messageListAdapter);
459
460 return view;
461 }
462
463 protected Bitmap findSelfPicture() {
464 SharedPreferences sharedPref = PreferenceManager
465 .getDefaultSharedPreferences(getActivity()
466 .getApplicationContext());
467 boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
468 "show_phone_selfcontact_picture", true);
469
470 return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
471 showPhoneSelfContactPicture, getActivity());
472 }
473
474 @Override
475 public void onStart() {
476 super.onStart();
477 this.activity = (ConversationActivity) getActivity();
478 SharedPreferences preferences = PreferenceManager
479 .getDefaultSharedPreferences(activity);
480 this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
481 if (activity.xmppConnectionServiceBound) {
482 this.onBackendConnected();
483 }
484 }
485
486 @Override
487 public void onStop() {
488 super.onStop();
489 if (this.conversation!=null) {
490 this.conversation.setNextMessage(chatMsg.getText().toString());
491 }
492 }
493
494 public void onBackendConnected() {
495 this.conversation = activity.getSelectedConversation();
496 if (this.conversation == null) {
497 return;
498 }
499 if (this.pastedText == null) {
500 this.chatMsg.setText(conversation.getNextMessage());
501 } else {
502 chatMsg.setText(conversation.getNextMessage() + " " + pastedText);
503 pastedText = null;
504 }
505 int position = chatMsg.length();
506 Editable etext = chatMsg.getText();
507 Selection.setSelection(etext, position);
508 this.selfBitmap = findSelfPicture();
509 updateMessages();
510 if (activity.getSlidingPaneLayout().isSlideable()) {
511 if (!activity.shouldPaneBeOpen()) {
512 activity.getSlidingPaneLayout().closePane();
513 activity.getActionBar().setDisplayHomeAsUpEnabled(true);
514 activity.getActionBar().setTitle(
515 conversation.getName(useSubject));
516 activity.invalidateOptionsMenu();
517
518 }
519 }
520 if (conversation.getMode() == Conversation.MODE_MULTI) {
521 activity.xmppConnectionService
522 .setOnRenameListener(new OnRenameListener() {
523
524 @Override
525 public void onRename(final boolean success) {
526 activity.xmppConnectionService
527 .updateConversation(conversation);
528 getActivity().runOnUiThread(new Runnable() {
529
530 @Override
531 public void run() {
532 if (success) {
533 Toast.makeText(
534 getActivity(),
535 getString(R.string.your_nick_has_been_changed),
536 Toast.LENGTH_SHORT).show();
537 } else {
538 Toast.makeText(
539 getActivity(),
540 getString(R.string.nick_in_use),
541 Toast.LENGTH_SHORT).show();
542 }
543 }
544 });
545 }
546 });
547 }
548 }
549
550 private void decryptMessage(final Message message) {
551 PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
552 if (engine != null) {
553 engine.decrypt(message, new UiCallback() {
554
555 @Override
556 public void userInputRequried(PendingIntent pi) {
557 askForPassphraseIntent = pi.getIntentSender();
558 pgpInfo.setVisibility(View.VISIBLE);
559 }
560
561 @Override
562 public void success() {
563 activity.xmppConnectionService.databaseBackend
564 .updateMessage(message);
565 updateMessages();
566 }
567
568 @Override
569 public void error(int error) {
570 message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
571 // updateMessages();
572 }
573 });
574 } else {
575 pgpInfo.setVisibility(View.VISIBLE);
576 }
577 }
578
579 public void updateMessages() {
580 if (getView()==null) {
581 return;
582 }
583 ConversationActivity activity = (ConversationActivity) getActivity();
584 if (this.conversation != null) {
585 for (Message message : this.conversation.getMessages()) {
586 if (message.getEncryption() == Message.ENCRYPTION_PGP) {
587 decryptMessage(message);
588 break;
589 }
590 }
591 this.messageList.clear();
592 this.messageList.addAll(this.conversation.getMessages());
593 this.messageListAdapter.notifyDataSetChanged();
594 if (conversation.getMode() == Conversation.MODE_SINGLE) {
595 if (messageList.size() >= 1) {
596 makeFingerprintWarning(conversation.getLatestEncryption());
597 }
598 } else {
599 if (conversation.getMucOptions().getError() != 0) {
600 mucError.setVisibility(View.VISIBLE);
601 if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
602 mucErrorText.setText(getString(R.string.nick_in_use));
603 }
604 } else {
605 mucError.setVisibility(View.GONE);
606 }
607 }
608 getActivity().invalidateOptionsMenu();
609 updateChatMsgHint();
610 int size = this.messageList.size();
611 if (size >= 1)
612 messagesView.setSelection(size - 1);
613 if (!activity.shouldPaneBeOpen()) {
614 conversation.markRead();
615 // TODO update notifications
616 UIHelper.updateNotification(getActivity(),
617 activity.getConversationList(), null, false);
618 activity.updateConversationList();
619 }
620 }
621 }
622
623 protected void makeFingerprintWarning(int latestEncryption) {
624 final LinearLayout fingerprintWarning = (LinearLayout) getView()
625 .findViewById(R.id.new_fingerprint);
626 if (conversation.getContact() != null) {
627 Set<String> knownFingerprints = conversation.getContact()
628 .getOtrFingerprints();
629 if ((latestEncryption == Message.ENCRYPTION_OTR)
630 && (conversation.hasValidOtrSession()
631 && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
632 .contains(conversation.getOtrFingerprint())))) {
633 fingerprintWarning.setVisibility(View.VISIBLE);
634 TextView fingerprint = (TextView) getView().findViewById(
635 R.id.otr_fingerprint);
636 fingerprint.setText(conversation.getOtrFingerprint());
637 fingerprintWarning.setOnClickListener(new OnClickListener() {
638
639 @Override
640 public void onClick(View v) {
641 AlertDialog dialog = UIHelper
642 .getVerifyFingerprintDialog(
643 (ConversationActivity) getActivity(),
644 conversation, fingerprintWarning);
645 dialog.show();
646 }
647 });
648 } else {
649 fingerprintWarning.setVisibility(View.GONE);
650 }
651 } else {
652 fingerprintWarning.setVisibility(View.GONE);
653 }
654 }
655
656 protected void sendPlainTextMessage(Message message) {
657 ConversationActivity activity = (ConversationActivity) getActivity();
658 activity.xmppConnectionService.sendMessage(message, null);
659 chatMsg.setText("");
660 }
661
662 protected void sendPgpMessage(final Message message) {
663 activity.pendingMessage = message;
664 final ConversationActivity activity = (ConversationActivity) getActivity();
665 final XmppConnectionService xmppService = activity.xmppConnectionService;
666 final Contact contact = message.getConversation().getContact();
667 if (activity.hasPgp()) {
668 if (contact.getPgpKeyId() != 0) {
669 xmppService.getPgpEngine().hasKey(contact,
670 new UiCallback() {
671
672 @Override
673 public void userInputRequried(PendingIntent pi) {
674 activity.runIntent(
675 pi,
676 ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
677 }
678
679 @Override
680 public void success() {
681 activity.encryptTextMessage();
682 }
683
684 @Override
685 public void error(int error) {
686
687 }
688 });
689
690 } else {
691 showNoPGPKeyDialog(new DialogInterface.OnClickListener() {
692
693 @Override
694 public void onClick(DialogInterface dialog,
695 int which) {
696 conversation
697 .setNextEncryption(Message.ENCRYPTION_NONE);
698 message.setEncryption(Message.ENCRYPTION_NONE);
699 xmppService.sendMessage(message, null);
700 chatMsg.setText("");
701 }
702 });
703 }
704 }
705 }
706
707 public void showNoPGPKeyDialog(DialogInterface.OnClickListener listener) {
708 AlertDialog.Builder builder = new AlertDialog.Builder(
709 getActivity());
710 builder.setTitle(getString(R.string.no_pgp_key));
711 builder.setIconAttribute(android.R.attr.alertDialogIcon);
712 builder.setMessage(getText(R.string.contact_has_no_pgp_key));
713 builder.setNegativeButton(getString(R.string.cancel), null);
714 builder.setPositiveButton(getString(R.string.send_unencrypted),listener);
715 builder.create().show();
716 }
717
718 protected void sendOtrMessage(final Message message) {
719 ConversationActivity activity = (ConversationActivity) getActivity();
720 final XmppConnectionService xmppService = activity.xmppConnectionService;
721 if (conversation.hasValidOtrSession()) {
722 activity.xmppConnectionService.sendMessage(message, null);
723 chatMsg.setText("");
724 } else {
725 activity.selectPresence(message.getConversation(),
726 new OnPresenceSelected() {
727
728 @Override
729 public void onPresenceSelected(boolean success,
730 String presence) {
731 if (success) {
732 xmppService.sendMessage(message, presence);
733 chatMsg.setText("");
734 }
735 }
736
737 @Override
738 public void onSendPlainTextInstead() {
739 message.setEncryption(Message.ENCRYPTION_NONE);
740 xmppService.sendMessage(message, null);
741 chatMsg.setText("");
742 }
743 }, "otr");
744 }
745 }
746
747 private static class ViewHolder {
748
749 protected Button download_button;
750 protected ImageView image;
751 protected ImageView indicator;
752 protected TextView time;
753 protected TextView messageBody;
754 protected ImageView contact_picture;
755
756 }
757
758 private class BitmapCache {
759 private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
760
761 public Bitmap get(String name, Contact contact, Context context) {
762 if (bitmaps.containsKey(name)) {
763 return bitmaps.get(name);
764 } else {
765 Bitmap bm;
766 if (contact != null) {
767 bm = UIHelper
768 .getContactPicture(contact, 48, context, false);
769 } else {
770 bm = UIHelper.getContactPicture(name, 48, context, false);
771 }
772 bitmaps.put(name, bm);
773 return bm;
774 }
775 }
776 }
777
778 public void setText(String text) {
779 this.pastedText = text;
780 }
781
782 public void clearInputField() {
783 this.chatMsg.setText("");
784 }
785}