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