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.Gravity;
38import android.view.LayoutInflater;
39import android.view.View;
40import android.view.View.OnClickListener;
41import android.view.View.OnLongClickListener;
42import android.view.ViewGroup;
43import android.widget.ArrayAdapter;
44import android.widget.Button;
45import android.widget.EditText;
46import android.widget.LinearLayout;
47import android.widget.ListView;
48import android.widget.ImageButton;
49import android.widget.ImageView;
50import android.widget.TextView;
51import android.widget.Toast;
52
53public class ConversationFragment extends Fragment {
54
55 protected Conversation conversation;
56 protected ListView messagesView;
57 protected LayoutInflater inflater;
58 protected List<Message> messageList = new ArrayList<Message>();
59 protected ArrayAdapter<Message> messageListAdapter;
60 protected Contact contact;
61 protected BitmapCache mBitmapCache = new BitmapCache();
62
63 protected String queuedPqpMessage = null;
64
65 private EditText chatMsg;
66 private String pastedText = null;
67
68 protected Bitmap selfBitmap;
69
70 private boolean useSubject = true;
71
72 private IntentSender askForPassphraseIntent = null;
73
74 private OnClickListener sendMsgListener = new OnClickListener() {
75
76 @Override
77 public void onClick(View v) {
78 if (chatMsg.getText().length() < 1)
79 return;
80 Message message = new Message(conversation, chatMsg.getText()
81 .toString(), conversation.getNextEncryption());
82 if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) {
83 sendOtrMessage(message);
84 } else if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
85 sendPgpMessage(message);
86 } else {
87 sendPlainTextMessage(message);
88 }
89 }
90 };
91 protected OnClickListener clickToDecryptListener = new OnClickListener() {
92
93 @Override
94 public void onClick(View v) {
95 if (activity.hasPgp() && askForPassphraseIntent != null) {
96 try {
97 getActivity().startIntentSenderForResult(
98 askForPassphraseIntent,
99 ConversationActivity.REQUEST_DECRYPT_PGP, null, 0,
100 0, 0);
101 } catch (SendIntentException e) {
102 Log.d("xmppService", "couldnt fire intent");
103 }
104 }
105 }
106 };
107
108 private LinearLayout pgpInfo;
109 private LinearLayout mucError;
110 private TextView mucErrorText;
111 private OnClickListener clickToMuc = new OnClickListener() {
112
113 @Override
114 public void onClick(View v) {
115 Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
116 intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
117 intent.putExtra("uuid", conversation.getUuid());
118 startActivity(intent);
119 }
120 };
121 private ConversationActivity activity;
122
123 public void hidePgpPassphraseBox() {
124 pgpInfo.setVisibility(View.GONE);
125 }
126
127 public void updateChatMsgHint() {
128 switch (conversation.getNextEncryption()) {
129 case Message.ENCRYPTION_NONE:
130 chatMsg.setHint(getString(R.string.send_plain_text_message));
131 break;
132 case Message.ENCRYPTION_OTR:
133 chatMsg.setHint(getString(R.string.send_otr_message));
134 break;
135 case Message.ENCRYPTION_PGP:
136 chatMsg.setHint(getString(R.string.send_pgp_message));
137 break;
138 default:
139 break;
140 }
141 }
142
143 @Override
144 public View onCreateView(final LayoutInflater inflater,
145 ViewGroup container, Bundle savedInstanceState) {
146
147 final DisplayMetrics metrics = getResources().getDisplayMetrics();
148
149 this.inflater = inflater;
150
151 final View view = inflater.inflate(R.layout.fragment_conversation,
152 container, false);
153 chatMsg = (EditText) view.findViewById(R.id.textinput);
154
155 ImageButton sendButton = (ImageButton) view
156 .findViewById(R.id.textSendButton);
157 sendButton.setOnClickListener(this.sendMsgListener);
158
159 pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry);
160 pgpInfo.setOnClickListener(clickToDecryptListener);
161 mucError = (LinearLayout) view.findViewById(R.id.muc_error);
162 mucError.setOnClickListener(clickToMuc);
163 mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg);
164
165 messagesView = (ListView) view.findViewById(R.id.messages_view);
166
167 messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
168 .getApplicationContext(), R.layout.message_sent,
169 this.messageList) {
170
171 private static final int SENT = 0;
172 private static final int RECIEVED = 1;
173 private static final int STATUS = 2;
174
175 @Override
176 public int getViewTypeCount() {
177 return 3;
178 }
179
180 @Override
181 public int getItemViewType(int position) {
182 if (getItem(position).getType() == Message.TYPE_STATUS) {
183 return STATUS;
184 } else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
185 return RECIEVED;
186 } else {
187 return SENT;
188 }
189 }
190
191 private void displayStatus(ViewHolder viewHolder, Message message) {
192 String filesize = null;
193 String info = null;
194 boolean error = false;
195 if (message.getType() == Message.TYPE_IMAGE) {
196 String[] fileParams = message.getBody().split(",");
197 try {
198 long size = Long.parseLong(fileParams[0]);
199 filesize = size / 1024 + " KB";
200 } catch (NumberFormatException e) {
201 filesize = "0 KB";
202 }
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(
238 getContext(), message.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 if (viewHolder.download_button != null) {
268 viewHolder.download_button.setVisibility(View.GONE);
269 }
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 Intent intent = new Intent(Intent.ACTION_VIEW);
333 intent.setDataAndType(
334 ImageProvider.getContentUri(message), "image/*");
335 startActivity(intent);
336 }
337 });
338 viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
339
340 @Override
341 public boolean onLongClick(View v) {
342 Intent shareIntent = new Intent();
343 shareIntent.setAction(Intent.ACTION_SEND);
344 shareIntent.putExtra(Intent.EXTRA_STREAM, ImageProvider.getContentUri(message));
345 shareIntent.setType("image/webp");
346 startActivity(Intent.createChooser(shareIntent, getText(R.string.share_with)));
347 return true;
348 }
349 });
350 }
351
352 @Override
353 public View getView(int position, View view, ViewGroup parent) {
354 final Message item = getItem(position);
355 int type = getItemViewType(position);
356 ViewHolder viewHolder;
357 if (view == null) {
358 viewHolder = new ViewHolder();
359 switch (type) {
360 case SENT:
361 view = (View) inflater.inflate(R.layout.message_sent,
362 null);
363 viewHolder.contact_picture = (ImageView) view
364 .findViewById(R.id.message_photo);
365 viewHolder.contact_picture.setImageBitmap(selfBitmap);
366 viewHolder.indicator = (ImageView) view
367 .findViewById(R.id.security_indicator);
368 viewHolder.image = (ImageView) view
369 .findViewById(R.id.message_image);
370 viewHolder.messageBody = (TextView) view
371 .findViewById(R.id.message_body);
372 viewHolder.time = (TextView) view
373 .findViewById(R.id.message_time);
374 view.setTag(viewHolder);
375 break;
376 case RECIEVED:
377 view = (View) inflater.inflate(
378 R.layout.message_recieved, null);
379 viewHolder.contact_picture = (ImageView) view
380 .findViewById(R.id.message_photo);
381
382 viewHolder.download_button = (Button) view
383 .findViewById(R.id.download_button);
384
385 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
386
387 viewHolder.contact_picture
388 .setImageBitmap(mBitmapCache.get(
389 item.getConversation().getName(
390 useSubject), item
391 .getConversation()
392 .getContact(),
393 getActivity()
394 .getApplicationContext()));
395
396 }
397 viewHolder.indicator = (ImageView) view
398 .findViewById(R.id.security_indicator);
399 viewHolder.image = (ImageView) view
400 .findViewById(R.id.message_image);
401 viewHolder.messageBody = (TextView) view
402 .findViewById(R.id.message_body);
403 viewHolder.time = (TextView) view
404 .findViewById(R.id.message_time);
405 view.setTag(viewHolder);
406 break;
407 case STATUS:
408 view = (View) inflater.inflate(
409 R.layout.message_status, null);
410 viewHolder.contact_picture = (ImageView) view
411 .findViewById(R.id.message_photo);
412 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
413
414 viewHolder.contact_picture
415 .setImageBitmap(mBitmapCache.get(
416 item.getConversation().getName(
417 useSubject), item
418 .getConversation()
419 .getContact(),
420 getActivity()
421 .getApplicationContext()));
422 viewHolder.contact_picture.setAlpha(128);
423
424 }
425 break;
426 default:
427 viewHolder = null;
428 break;
429 }
430 } else {
431 viewHolder = (ViewHolder) view.getTag();
432 }
433
434 if (type == STATUS) {
435 return view;
436 }
437
438 if (type == RECIEVED) {
439 if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
440 viewHolder.contact_picture.setImageBitmap(mBitmapCache
441 .get(item.getCounterpart(), null, getActivity()
442 .getApplicationContext()));
443 viewHolder.contact_picture
444 .setOnClickListener(new OnClickListener() {
445
446 @Override
447 public void onClick(View v) {
448 highlightInConference(item
449 .getCounterpart());
450 }
451 });
452 }
453 }
454
455 if (item.getType() == Message.TYPE_IMAGE) {
456 if (item.getStatus() == Message.STATUS_RECIEVING) {
457 displayInfoMessage(viewHolder, R.string.receiving_image);
458 } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
459 viewHolder.image.setVisibility(View.GONE);
460 viewHolder.messageBody.setVisibility(View.GONE);
461 viewHolder.download_button.setVisibility(View.VISIBLE);
462 viewHolder.download_button
463 .setOnClickListener(new OnClickListener() {
464
465 @Override
466 public void onClick(View v) {
467 JingleConnection connection = item
468 .getJingleConnection();
469 if (connection != null) {
470 connection.accept();
471 } else {
472 Log.d("xmppService",
473 "attached jingle connection was null");
474 }
475 }
476 });
477 } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
478 || (item.getEncryption() == Message.ENCRYPTION_NONE)) {
479 displayImageMessage(viewHolder, item);
480 } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
481 displayInfoMessage(viewHolder,
482 R.string.encrypted_message);
483 } else {
484 displayDecryptionFailed(viewHolder);
485 }
486 } else {
487 if (item.getEncryption() == Message.ENCRYPTION_PGP) {
488 displayInfoMessage(viewHolder,
489 R.string.encrypted_message);
490 } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
491 displayDecryptionFailed(viewHolder);
492 } else {
493 displayTextMessage(viewHolder, item.getBody());
494 }
495 }
496
497 displayStatus(viewHolder, item);
498
499 return view;
500 }
501 };
502 messagesView.setAdapter(messageListAdapter);
503
504 return view;
505 }
506
507 protected void highlightInConference(String nick) {
508 String oldString = chatMsg.getText().toString().trim();
509 if (oldString.isEmpty()) {
510 chatMsg.setText(nick + ": ");
511 } else {
512 chatMsg.setText(oldString + " " + nick + " ");
513 }
514 int position = chatMsg.length();
515 Editable etext = chatMsg.getText();
516 Selection.setSelection(etext, position);
517 }
518
519 protected Bitmap findSelfPicture() {
520 SharedPreferences sharedPref = PreferenceManager
521 .getDefaultSharedPreferences(getActivity()
522 .getApplicationContext());
523 boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
524 "show_phone_selfcontact_picture", true);
525
526 return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
527 showPhoneSelfContactPicture, getActivity());
528 }
529
530 @Override
531 public void onStart() {
532 super.onStart();
533 this.activity = (ConversationActivity) getActivity();
534 SharedPreferences preferences = PreferenceManager
535 .getDefaultSharedPreferences(activity);
536 this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
537 if (activity.xmppConnectionServiceBound) {
538 this.onBackendConnected();
539 }
540 }
541
542 @Override
543 public void onStop() {
544 super.onStop();
545 if (this.conversation != null) {
546 this.conversation.setNextMessage(chatMsg.getText().toString());
547 }
548 }
549
550 public void onBackendConnected() {
551 this.conversation = activity.getSelectedConversation();
552 if (this.conversation == null) {
553 return;
554 }
555 String oldString = conversation.getNextMessage().trim();
556 if (this.pastedText == null) {
557 this.chatMsg.setText(oldString);
558 } else {
559
560 if (oldString.isEmpty()) {
561 chatMsg.setText(pastedText);
562 } else {
563 chatMsg.setText(oldString + " " + pastedText);
564 }
565 pastedText = null;
566 }
567 int position = chatMsg.length();
568 Editable etext = chatMsg.getText();
569 Selection.setSelection(etext, position);
570 this.selfBitmap = findSelfPicture();
571 updateMessages();
572 if (activity.getSlidingPaneLayout().isSlideable()) {
573 if (!activity.shouldPaneBeOpen()) {
574 activity.getSlidingPaneLayout().closePane();
575 activity.getActionBar().setDisplayHomeAsUpEnabled(true);
576 activity.getActionBar().setHomeButtonEnabled(true);
577 activity.getActionBar().setTitle(
578 conversation.getName(useSubject));
579 activity.invalidateOptionsMenu();
580
581 }
582 }
583 if (conversation.getMode() == Conversation.MODE_MULTI) {
584 activity.xmppConnectionService
585 .setOnRenameListener(new OnRenameListener() {
586
587 @Override
588 public void onRename(final boolean success) {
589 activity.xmppConnectionService
590 .updateConversation(conversation);
591 getActivity().runOnUiThread(new Runnable() {
592
593 @Override
594 public void run() {
595 if (success) {
596 Toast.makeText(
597 getActivity(),
598 getString(R.string.your_nick_has_been_changed),
599 Toast.LENGTH_SHORT).show();
600 } else {
601 Toast.makeText(
602 getActivity(),
603 getString(R.string.nick_in_use),
604 Toast.LENGTH_SHORT).show();
605 }
606 }
607 });
608 }
609 });
610 }
611 }
612
613 private void decryptMessage(final Message message) {
614 PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
615 if (engine != null) {
616 engine.decrypt(message, new UiCallback() {
617
618 @Override
619 public void userInputRequried(PendingIntent pi) {
620 askForPassphraseIntent = pi.getIntentSender();
621 pgpInfo.setVisibility(View.VISIBLE);
622 }
623
624 @Override
625 public void success() {
626 activity.xmppConnectionService.databaseBackend
627 .updateMessage(message);
628 updateMessages();
629 }
630
631 @Override
632 public void error(int error) {
633 message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
634 // updateMessages();
635 }
636 });
637 } else {
638 pgpInfo.setVisibility(View.VISIBLE);
639 }
640 }
641
642 public void updateMessages() {
643 if (getView() == null) {
644 return;
645 }
646 ConversationActivity activity = (ConversationActivity) getActivity();
647 if (this.conversation != null) {
648 for (Message message : this.conversation.getMessages()) {
649 if ((message.getEncryption() == Message.ENCRYPTION_PGP)
650 && ((message.getStatus() == Message.STATUS_RECIEVED) || (message
651 .getStatus() == Message.STATUS_SEND))) {
652 decryptMessage(message);
653 break;
654 }
655 }
656 this.messageList.clear();
657 this.messageList.addAll(this.conversation.getMessages());
658 updateStatusMessages();
659 this.messageListAdapter.notifyDataSetChanged();
660 if (conversation.getMode() == Conversation.MODE_SINGLE) {
661 if (messageList.size() >= 1) {
662 makeFingerprintWarning(conversation.getLatestEncryption());
663 }
664 } else {
665 if (conversation.getMucOptions().getError() != 0) {
666 mucError.setVisibility(View.VISIBLE);
667 if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
668 mucErrorText.setText(getString(R.string.nick_in_use));
669 }
670 } else {
671 mucError.setVisibility(View.GONE);
672 }
673 }
674 getActivity().invalidateOptionsMenu();
675 updateChatMsgHint();
676 int size = this.messageList.size();
677 if (size >= 1)
678 messagesView.setSelection(size - 1);
679 if (!activity.shouldPaneBeOpen()) {
680 activity.xmppConnectionService.markRead(conversation);
681 // TODO update notifications
682 UIHelper.updateNotification(getActivity(),
683 activity.getConversationList(), null, false);
684 activity.updateConversationList();
685 }
686 }
687 }
688
689 protected void updateStatusMessages() {
690 if (conversation.getMode() == Conversation.MODE_SINGLE) {
691 for(int i = this.messageList.size() - 1; i >= 0; --i) {
692 if (this.messageList.get(i).getStatus() == Message.STATUS_RECIEVED) {
693 return;
694 } else {
695 if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
696 this.messageList.add(i+1, Message.createStatusMessage(conversation));
697 return;
698 }
699 }
700 }
701 }
702 }
703
704 protected void makeFingerprintWarning(int latestEncryption) {
705 final LinearLayout fingerprintWarning = (LinearLayout) getView()
706 .findViewById(R.id.new_fingerprint);
707 Set<String> knownFingerprints = conversation.getContact()
708 .getOtrFingerprints();
709 if ((latestEncryption == Message.ENCRYPTION_OTR)
710 && (conversation.hasValidOtrSession()
711 && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
712 .contains(conversation.getOtrFingerprint())))) {
713 fingerprintWarning.setVisibility(View.VISIBLE);
714 TextView fingerprint = (TextView) getView().findViewById(
715 R.id.otr_fingerprint);
716 fingerprint.setText(conversation.getOtrFingerprint());
717 fingerprintWarning.setOnClickListener(new OnClickListener() {
718
719 @Override
720 public void onClick(View v) {
721 AlertDialog dialog = UIHelper.getVerifyFingerprintDialog(
722 (ConversationActivity) getActivity(), conversation,
723 fingerprintWarning);
724 dialog.show();
725 }
726 });
727 } else {
728 fingerprintWarning.setVisibility(View.GONE);
729 }
730 }
731
732 protected void sendPlainTextMessage(Message message) {
733 ConversationActivity activity = (ConversationActivity) getActivity();
734 activity.xmppConnectionService.sendMessage(message, null);
735 chatMsg.setText("");
736 }
737
738 protected void sendPgpMessage(final Message message) {
739 activity.pendingMessage = message;
740 final ConversationActivity activity = (ConversationActivity) getActivity();
741 final XmppConnectionService xmppService = activity.xmppConnectionService;
742 final Contact contact = message.getConversation().getContact();
743 if (activity.hasPgp()) {
744 if (conversation.getMode() == Conversation.MODE_SINGLE) {
745 if (contact.getPgpKeyId() != 0) {
746 xmppService.getPgpEngine().hasKey(contact,
747 new UiCallback() {
748
749 @Override
750 public void userInputRequried(PendingIntent pi) {
751 activity.runIntent(
752 pi,
753 ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
754 }
755
756 @Override
757 public void success() {
758 activity.encryptTextMessage();
759 }
760
761 @Override
762 public void error(int error) {
763
764 }
765 });
766
767 } else {
768 showNoPGPKeyDialog(false,
769 new DialogInterface.OnClickListener() {
770
771 @Override
772 public void onClick(DialogInterface dialog,
773 int which) {
774 conversation
775 .setNextEncryption(Message.ENCRYPTION_NONE);
776 message.setEncryption(Message.ENCRYPTION_NONE);
777 xmppService.sendMessage(message, null);
778 chatMsg.setText("");
779 }
780 });
781 }
782 } else {
783 if (conversation.getMucOptions().pgpKeysInUse()) {
784 if (!conversation.getMucOptions().everybodyHasKeys()) {
785 Toast warning = Toast
786 .makeText(getActivity(),
787 R.string.missing_public_keys,
788 Toast.LENGTH_LONG);
789 warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
790 warning.show();
791 }
792 activity.encryptTextMessage();
793 } else {
794 showNoPGPKeyDialog(true,
795 new DialogInterface.OnClickListener() {
796
797 @Override
798 public void onClick(DialogInterface dialog,
799 int which) {
800 conversation
801 .setNextEncryption(Message.ENCRYPTION_NONE);
802 message.setEncryption(Message.ENCRYPTION_NONE);
803 xmppService.sendMessage(message, null);
804 chatMsg.setText("");
805 }
806 });
807 }
808 }
809 }
810 }
811
812 public void showNoPGPKeyDialog(boolean plural,
813 DialogInterface.OnClickListener listener) {
814 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
815 builder.setIconAttribute(android.R.attr.alertDialogIcon);
816 if (plural) {
817 builder.setTitle(getString(R.string.no_pgp_keys));
818 builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));
819 } else {
820 builder.setTitle(getString(R.string.no_pgp_key));
821 builder.setMessage(getText(R.string.contact_has_no_pgp_key));
822 }
823 builder.setNegativeButton(getString(R.string.cancel), null);
824 builder.setPositiveButton(getString(R.string.send_unencrypted),
825 listener);
826 builder.create().show();
827 }
828
829 protected void sendOtrMessage(final Message message) {
830 ConversationActivity activity = (ConversationActivity) getActivity();
831 final XmppConnectionService xmppService = activity.xmppConnectionService;
832 if (conversation.hasValidOtrSession()) {
833 activity.xmppConnectionService.sendMessage(message, null);
834 chatMsg.setText("");
835 } else {
836 activity.selectPresence(message.getConversation(),
837 new OnPresenceSelected() {
838
839 @Override
840 public void onPresenceSelected(boolean success,
841 String presence) {
842 if (success) {
843 xmppService.sendMessage(message, presence);
844 chatMsg.setText("");
845 }
846 }
847
848 @Override
849 public void onSendPlainTextInstead() {
850 message.setEncryption(Message.ENCRYPTION_NONE);
851 xmppService.sendMessage(message, null);
852 chatMsg.setText("");
853 }
854 }, "otr");
855 }
856 }
857
858 private static class ViewHolder {
859
860 protected Button download_button;
861 protected ImageView image;
862 protected ImageView indicator;
863 protected TextView time;
864 protected TextView messageBody;
865 protected ImageView contact_picture;
866
867 }
868
869 private class BitmapCache {
870 private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
871
872 public Bitmap get(String name, Contact contact, Context context) {
873 if (bitmaps.containsKey(name)) {
874 return bitmaps.get(name);
875 } else {
876 Bitmap bm;
877 if (contact != null) {
878 bm = UIHelper
879 .getContactPicture(contact, 48, context, false);
880 } else {
881 bm = UIHelper.getContactPicture(name, 48, context, false);
882 }
883 bitmaps.put(name, bm);
884 return bm;
885 }
886 }
887 }
888
889 public void setText(String text) {
890 this.pastedText = text;
891 }
892
893 public void clearInputField() {
894 this.chatMsg.setText("");
895 }
896}