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