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 public LinearLayout lastSeen;
111 private TextView mucErrorText;
112 private TextView lastSeenText;
113 private OnClickListener clickToMuc = new OnClickListener() {
114
115 @Override
116 public void onClick(View v) {
117 Intent intent = new Intent(getActivity(), MucDetailsActivity.class);
118 intent.setAction(MucDetailsActivity.ACTION_VIEW_MUC);
119 intent.putExtra("uuid", conversation.getUuid());
120 startActivity(intent);
121 }
122 };
123 private ConversationActivity activity;
124
125 public void hidePgpPassphraseBox() {
126 pgpInfo.setVisibility(View.GONE);
127 }
128
129 public void updateChatMsgHint() {
130 switch (conversation.getNextEncryption()) {
131 case Message.ENCRYPTION_NONE:
132 chatMsg.setHint(getString(R.string.send_plain_text_message));
133 break;
134 case Message.ENCRYPTION_OTR:
135 chatMsg.setHint(getString(R.string.send_otr_message));
136 break;
137 case Message.ENCRYPTION_PGP:
138 chatMsg.setHint(getString(R.string.send_pgp_message));
139 break;
140 default:
141 break;
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 lastSeen = (LinearLayout) view.findViewById(R.id.last_seen);
167 lastSeenText = (TextView) view.findViewById(R.id.last_seen_text);
168
169 messagesView = (ListView) view.findViewById(R.id.messages_view);
170
171 messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
172 .getApplicationContext(), R.layout.message_sent,
173 this.messageList) {
174
175 private static final int SENT = 0;
176 private static final int RECIEVED = 1;
177 private static final int STATUS = 2;
178
179 @Override
180 public int getViewTypeCount() {
181 return 3;
182 }
183
184 @Override
185 public int getItemViewType(int position) {
186 if (getItem(position).getType() == Message.TYPE_STATUS) {
187 return STATUS;
188 } else 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 try {
202 long size = Long.parseLong(fileParams[0]);
203 filesize = size / 1024 + " KB";
204 } catch (NumberFormatException e) {
205 filesize = "0 KB";
206 }
207 }
208 switch (message.getStatus()) {
209 case Message.STATUS_UNSEND:
210 info = getString(R.string.sending);
211 break;
212 case Message.STATUS_OFFERED:
213 info = getString(R.string.offering);
214 break;
215 case Message.STATUS_SEND_FAILED:
216 info = getString(R.string.send_failed);
217 error = true;
218 break;
219 case Message.STATUS_SEND_REJECTED:
220 info = getString(R.string.send_rejected);
221 error = true;
222 break;
223 default:
224 if ((message.getConversation().getMode() == Conversation.MODE_MULTI)
225 && (message.getStatus() <= Message.STATUS_RECIEVED)) {
226 info = message.getCounterpart();
227 }
228 break;
229 }
230 if (error) {
231 viewHolder.time.setTextColor(0xFFe92727);
232 } else {
233 viewHolder.time.setTextColor(0xFF8e8e8e);
234 }
235 if (message.getEncryption() == Message.ENCRYPTION_NONE) {
236 viewHolder.indicator.setVisibility(View.GONE);
237 } else {
238 viewHolder.indicator.setVisibility(View.VISIBLE);
239 }
240
241 String formatedTime = UIHelper.readableTimeDifference(
242 getContext(), message.getTimeSent());
243 if (message.getStatus() <= Message.STATUS_RECIEVED) {
244 if ((filesize != null) && (info != null)) {
245 viewHolder.time.setText(filesize + " \u00B7 " + info);
246 } else if ((filesize == null) && (info != null)) {
247 viewHolder.time.setText(formatedTime + " \u00B7 "
248 + info);
249 } else if ((filesize != null) && (info == null)) {
250 viewHolder.time.setText(formatedTime + " \u00B7 "
251 + filesize);
252 } else {
253 viewHolder.time.setText(formatedTime);
254 }
255 } else {
256 if ((filesize != null) && (info != null)) {
257 viewHolder.time.setText(filesize + " \u00B7 " + info);
258 } else if ((filesize == null) && (info != null)) {
259 viewHolder.time.setText(info + " \u00B7 "
260 + formatedTime);
261 } else if ((filesize != null) && (info == null)) {
262 viewHolder.time.setText(filesize + " \u00B7 "
263 + formatedTime);
264 } else {
265 viewHolder.time.setText(formatedTime);
266 }
267 }
268 }
269
270 private void displayInfoMessage(ViewHolder viewHolder, int r) {
271 if (viewHolder.download_button != null) {
272 viewHolder.download_button.setVisibility(View.GONE);
273 }
274 viewHolder.image.setVisibility(View.GONE);
275 viewHolder.messageBody.setVisibility(View.VISIBLE);
276 viewHolder.messageBody.setText(getString(r));
277 viewHolder.messageBody.setTextColor(0xff33B5E5);
278 viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
279 }
280
281 private void displayDecryptionFailed(ViewHolder viewHolder) {
282 viewHolder.download_button.setVisibility(View.GONE);
283 viewHolder.image.setVisibility(View.GONE);
284 viewHolder.messageBody.setVisibility(View.VISIBLE);
285 viewHolder.messageBody
286 .setText(getString(R.string.decryption_failed));
287 viewHolder.messageBody.setTextColor(0xFFe92727);
288 viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
289 }
290
291 private void displayTextMessage(ViewHolder viewHolder, String text) {
292 if (viewHolder.download_button != null) {
293 viewHolder.download_button.setVisibility(View.GONE);
294 }
295 viewHolder.image.setVisibility(View.GONE);
296 viewHolder.messageBody.setVisibility(View.VISIBLE);
297 if (text != null) {
298 viewHolder.messageBody.setText(text.trim());
299 } else {
300 viewHolder.messageBody.setText("");
301 }
302 viewHolder.messageBody.setTextColor(0xff333333);
303 viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
304 }
305
306 private void displayImageMessage(ViewHolder viewHolder,
307 final Message message) {
308 if (viewHolder.download_button != null) {
309 viewHolder.download_button.setVisibility(View.GONE);
310 }
311 viewHolder.messageBody.setVisibility(View.GONE);
312 viewHolder.image.setVisibility(View.VISIBLE);
313 String[] fileParams = message.getBody().split(",");
314 if (fileParams.length == 3) {
315 double target = metrics.density * 288;
316 int w = Integer.parseInt(fileParams[1]);
317 int h = Integer.parseInt(fileParams[2]);
318 int scalledW;
319 int scalledH;
320 if (w <= h) {
321 scalledW = (int) (w / ((double) h / target));
322 scalledH = (int) target;
323 } else {
324 scalledW = (int) target;
325 scalledH = (int) (h / ((double) w / target));
326 }
327 viewHolder.image
328 .setLayoutParams(new LinearLayout.LayoutParams(
329 scalledW, scalledH));
330 }
331 activity.loadBitmap(message, viewHolder.image);
332 viewHolder.image.setOnClickListener(new OnClickListener() {
333
334 @Override
335 public void onClick(View v) {
336 Intent intent = new Intent(Intent.ACTION_VIEW);
337 intent.setDataAndType(
338 ImageProvider.getContentUri(message), "image/*");
339 startActivity(intent);
340 }
341 });
342 viewHolder.image
343 .setOnLongClickListener(new OnLongClickListener() {
344
345 @Override
346 public boolean onLongClick(View v) {
347 Intent shareIntent = new Intent();
348 shareIntent.setAction(Intent.ACTION_SEND);
349 shareIntent.putExtra(Intent.EXTRA_STREAM,
350 ImageProvider.getContentUri(message));
351 shareIntent.setType("image/webp");
352 startActivity(Intent.createChooser(shareIntent,
353 getText(R.string.share_with)));
354 return true;
355 }
356 });
357 }
358
359 @Override
360 public View getView(int position, View view, ViewGroup parent) {
361 final Message item = getItem(position);
362 int type = getItemViewType(position);
363 ViewHolder viewHolder;
364 if (view == null) {
365 viewHolder = new ViewHolder();
366 switch (type) {
367 case SENT:
368 view = (View) inflater.inflate(R.layout.message_sent,
369 null);
370 viewHolder.contact_picture = (ImageView) view
371 .findViewById(R.id.message_photo);
372 viewHolder.contact_picture.setImageBitmap(selfBitmap);
373 viewHolder.indicator = (ImageView) view
374 .findViewById(R.id.security_indicator);
375 viewHolder.image = (ImageView) view
376 .findViewById(R.id.message_image);
377 viewHolder.messageBody = (TextView) view
378 .findViewById(R.id.message_body);
379 viewHolder.time = (TextView) view
380 .findViewById(R.id.message_time);
381 view.setTag(viewHolder);
382 break;
383 case RECIEVED:
384 view = (View) inflater.inflate(
385 R.layout.message_recieved, null);
386 viewHolder.contact_picture = (ImageView) view
387 .findViewById(R.id.message_photo);
388
389 viewHolder.download_button = (Button) view
390 .findViewById(R.id.download_button);
391
392 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
393
394 viewHolder.contact_picture
395 .setImageBitmap(mBitmapCache.get(
396 item.getConversation().getName(
397 useSubject), item
398 .getConversation()
399 .getContact(),
400 getActivity()
401 .getApplicationContext()));
402
403 }
404 viewHolder.indicator = (ImageView) view
405 .findViewById(R.id.security_indicator);
406 viewHolder.image = (ImageView) view
407 .findViewById(R.id.message_image);
408 viewHolder.messageBody = (TextView) view
409 .findViewById(R.id.message_body);
410 viewHolder.time = (TextView) view
411 .findViewById(R.id.message_time);
412 view.setTag(viewHolder);
413 break;
414 case STATUS:
415 view = (View) inflater.inflate(R.layout.message_status,
416 null);
417 viewHolder.contact_picture = (ImageView) view
418 .findViewById(R.id.message_photo);
419 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
420
421 viewHolder.contact_picture
422 .setImageBitmap(mBitmapCache.get(
423 item.getConversation().getName(
424 useSubject), item
425 .getConversation()
426 .getContact(),
427 getActivity()
428 .getApplicationContext()));
429 viewHolder.contact_picture.setAlpha(128);
430
431 }
432 break;
433 default:
434 viewHolder = null;
435 break;
436 }
437 } else {
438 viewHolder = (ViewHolder) view.getTag();
439 }
440
441 if (type == STATUS) {
442 return view;
443 }
444
445 if (type == RECIEVED) {
446 if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
447 viewHolder.contact_picture.setImageBitmap(mBitmapCache
448 .get(item.getCounterpart(), null, getActivity()
449 .getApplicationContext()));
450 viewHolder.contact_picture
451 .setOnClickListener(new OnClickListener() {
452
453 @Override
454 public void onClick(View v) {
455 highlightInConference(item
456 .getCounterpart());
457 }
458 });
459 }
460 }
461
462 if (item.getType() == Message.TYPE_IMAGE) {
463 if (item.getStatus() == Message.STATUS_RECIEVING) {
464 displayInfoMessage(viewHolder, R.string.receiving_image);
465 } else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
466 viewHolder.image.setVisibility(View.GONE);
467 viewHolder.messageBody.setVisibility(View.GONE);
468 viewHolder.download_button.setVisibility(View.VISIBLE);
469 viewHolder.download_button
470 .setOnClickListener(new OnClickListener() {
471
472 @Override
473 public void onClick(View v) {
474 JingleConnection connection = item
475 .getJingleConnection();
476 if (connection != null) {
477 connection.accept();
478 } else {
479 Log.d("xmppService",
480 "attached jingle connection was null");
481 }
482 }
483 });
484 } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
485 || (item.getEncryption() == Message.ENCRYPTION_NONE)) {
486 displayImageMessage(viewHolder, item);
487 } else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
488 displayInfoMessage(viewHolder,
489 R.string.encrypted_message);
490 } else {
491 displayDecryptionFailed(viewHolder);
492 }
493 } else {
494 if (item.getEncryption() == Message.ENCRYPTION_PGP) {
495 displayInfoMessage(viewHolder,
496 R.string.encrypted_message);
497 } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
498 displayDecryptionFailed(viewHolder);
499 } else {
500 displayTextMessage(viewHolder, item.getBody());
501 }
502 }
503
504 displayStatus(viewHolder, item);
505
506 return view;
507 }
508 };
509 messagesView.setAdapter(messageListAdapter);
510
511 return view;
512 }
513
514 protected void highlightInConference(String nick) {
515 String oldString = chatMsg.getText().toString().trim();
516 if (oldString.isEmpty()) {
517 chatMsg.setText(nick + ": ");
518 } else {
519 chatMsg.setText(oldString + " " + nick + " ");
520 }
521 int position = chatMsg.length();
522 Editable etext = chatMsg.getText();
523 Selection.setSelection(etext, position);
524 }
525
526 protected Bitmap findSelfPicture() {
527 SharedPreferences sharedPref = PreferenceManager
528 .getDefaultSharedPreferences(getActivity()
529 .getApplicationContext());
530 boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
531 "show_phone_selfcontact_picture", true);
532
533 return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
534 showPhoneSelfContactPicture, getActivity());
535 }
536
537 @Override
538 public void onStart() {
539 super.onStart();
540 this.activity = (ConversationActivity) getActivity();
541 SharedPreferences preferences = PreferenceManager
542 .getDefaultSharedPreferences(activity);
543 this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
544 if (activity.xmppConnectionServiceBound) {
545 this.onBackendConnected();
546 }
547 }
548
549 @Override
550 public void onStop() {
551 super.onStop();
552 if (this.conversation != null) {
553 this.conversation.setNextMessage(chatMsg.getText().toString());
554 }
555 }
556
557 public void onBackendConnected() {
558 this.conversation = activity.getSelectedConversation();
559 if (this.conversation == null) {
560 return;
561 }
562 String oldString = conversation.getNextMessage().trim();
563 if (this.pastedText == null) {
564 this.chatMsg.setText(oldString);
565 } else {
566
567 if (oldString.isEmpty()) {
568 chatMsg.setText(pastedText);
569 } else {
570 chatMsg.setText(oldString + " " + pastedText);
571 }
572 pastedText = null;
573 }
574 int position = chatMsg.length();
575 Editable etext = chatMsg.getText();
576 Selection.setSelection(etext, position);
577 this.selfBitmap = findSelfPicture();
578 updateMessages();
579 if (activity.getSlidingPaneLayout().isSlideable()) {
580 if (!activity.shouldPaneBeOpen()) {
581 activity.getSlidingPaneLayout().closePane();
582 activity.getActionBar().setDisplayHomeAsUpEnabled(true);
583 activity.getActionBar().setHomeButtonEnabled(true);
584 activity.getActionBar().setTitle(
585 conversation.getName(useSubject));
586 activity.invalidateOptionsMenu();
587 if (activity.showLastseen()) {
588 lastSeen.setVisibility(View.VISIBLE);
589 }
590 } else {
591 lastSeen.setVisibility(View.GONE);
592 }
593 }
594 if (conversation.getMode() == Conversation.MODE_MULTI) {
595 activity.xmppConnectionService
596 .setOnRenameListener(new OnRenameListener() {
597
598 @Override
599 public void onRename(final boolean success) {
600 activity.xmppConnectionService
601 .updateConversation(conversation);
602 getActivity().runOnUiThread(new Runnable() {
603
604 @Override
605 public void run() {
606 if (success) {
607 Toast.makeText(
608 getActivity(),
609 getString(R.string.your_nick_has_been_changed),
610 Toast.LENGTH_SHORT).show();
611 } else {
612 Toast.makeText(
613 getActivity(),
614 getString(R.string.nick_in_use),
615 Toast.LENGTH_SHORT).show();
616 }
617 }
618 });
619 }
620 });
621 }
622 }
623
624 private void decryptMessage(final Message message) {
625 PgpEngine engine = activity.xmppConnectionService.getPgpEngine();
626 if (engine != null) {
627 engine.decrypt(message, new UiCallback() {
628
629 @Override
630 public void userInputRequried(PendingIntent pi) {
631 askForPassphraseIntent = pi.getIntentSender();
632 pgpInfo.setVisibility(View.VISIBLE);
633 }
634
635 @Override
636 public void success() {
637 activity.xmppConnectionService.databaseBackend
638 .updateMessage(message);
639 updateMessages();
640 }
641
642 @Override
643 public void error(int error) {
644 message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
645 // updateMessages();
646 }
647 });
648 } else {
649 pgpInfo.setVisibility(View.VISIBLE);
650 }
651 }
652
653 public void updateMessages() {
654 if (getView() == null) {
655 return;
656 }
657 ConversationActivity activity = (ConversationActivity) getActivity();
658 if (this.conversation != null) {
659 for (Message message : this.conversation.getMessages()) {
660 if ((message.getEncryption() == Message.ENCRYPTION_PGP)
661 && ((message.getStatus() == Message.STATUS_RECIEVED) || (message
662 .getStatus() == Message.STATUS_SEND))) {
663 decryptMessage(message);
664 break;
665 }
666 }
667 if (activity.showLastseen()) {
668 Contact contact = conversation.getContact();
669 if ((contact.lastseen.presence != null)&&(contact.lastseen.time != 0)) {
670 lastSeenText.setText(getString(R.string.last_seen,
671 UIHelper.lastseen(getActivity(), contact.lastseen.time),
672 contact.lastseen.presence));
673 } else {
674 lastSeenText.setText(R.string.never_seen);
675 }
676 }
677 this.messageList.clear();
678 this.messageList.addAll(this.conversation.getMessages());
679 updateStatusMessages();
680 this.messageListAdapter.notifyDataSetChanged();
681 if (conversation.getMode() == Conversation.MODE_SINGLE) {
682 if (messageList.size() >= 1) {
683 makeFingerprintWarning(conversation.getLatestEncryption());
684 }
685 } else {
686 if (conversation.getMucOptions().getError() != 0) {
687 mucError.setVisibility(View.VISIBLE);
688 if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
689 mucErrorText.setText(getString(R.string.nick_in_use));
690 }
691 } else {
692 mucError.setVisibility(View.GONE);
693 }
694 }
695 getActivity().invalidateOptionsMenu();
696 updateChatMsgHint();
697 int size = this.messageList.size();
698 if (size >= 1)
699 messagesView.setSelection(size - 1);
700 if (!activity.shouldPaneBeOpen()) {
701 activity.xmppConnectionService.markRead(conversation);
702 // TODO update notifications
703 UIHelper.updateNotification(getActivity(),
704 activity.getConversationList(), null, false);
705 activity.updateConversationList();
706 }
707 }
708 }
709
710 protected void updateStatusMessages() {
711 if (conversation.getMode() == Conversation.MODE_SINGLE) {
712 for (int i = this.messageList.size() - 1; i >= 0; --i) {
713 if (this.messageList.get(i).getStatus() == Message.STATUS_RECIEVED) {
714 return;
715 } else {
716 if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) {
717 this.messageList.add(i + 1,
718 Message.createStatusMessage(conversation));
719 return;
720 }
721 }
722 }
723 }
724 }
725
726 protected void makeFingerprintWarning(int latestEncryption) {
727 final LinearLayout fingerprintWarning = (LinearLayout) getView()
728 .findViewById(R.id.new_fingerprint);
729 Set<String> knownFingerprints = conversation.getContact()
730 .getOtrFingerprints();
731 if ((latestEncryption == Message.ENCRYPTION_OTR)
732 && (conversation.hasValidOtrSession()
733 && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
734 .contains(conversation.getOtrFingerprint())))) {
735 fingerprintWarning.setVisibility(View.VISIBLE);
736 TextView fingerprint = (TextView) getView().findViewById(
737 R.id.otr_fingerprint);
738 fingerprint.setText(conversation.getOtrFingerprint());
739 fingerprintWarning.setOnClickListener(new OnClickListener() {
740
741 @Override
742 public void onClick(View v) {
743 AlertDialog dialog = UIHelper.getVerifyFingerprintDialog(
744 (ConversationActivity) getActivity(), conversation,
745 fingerprintWarning);
746 dialog.show();
747 }
748 });
749 } else {
750 fingerprintWarning.setVisibility(View.GONE);
751 }
752 }
753
754 protected void sendPlainTextMessage(Message message) {
755 ConversationActivity activity = (ConversationActivity) getActivity();
756 activity.xmppConnectionService.sendMessage(message, null);
757 chatMsg.setText("");
758 }
759
760 protected void sendPgpMessage(final Message message) {
761 activity.pendingMessage = message;
762 final ConversationActivity activity = (ConversationActivity) getActivity();
763 final XmppConnectionService xmppService = activity.xmppConnectionService;
764 final Contact contact = message.getConversation().getContact();
765 if (activity.hasPgp()) {
766 if (conversation.getMode() == Conversation.MODE_SINGLE) {
767 if (contact.getPgpKeyId() != 0) {
768 xmppService.getPgpEngine().hasKey(contact,
769 new UiCallback() {
770
771 @Override
772 public void userInputRequried(PendingIntent pi) {
773 activity.runIntent(
774 pi,
775 ConversationActivity.REQUEST_ENCRYPT_MESSAGE);
776 }
777
778 @Override
779 public void success() {
780 activity.encryptTextMessage();
781 }
782
783 @Override
784 public void error(int error) {
785
786 }
787 });
788
789 } else {
790 showNoPGPKeyDialog(false,
791 new DialogInterface.OnClickListener() {
792
793 @Override
794 public void onClick(DialogInterface dialog,
795 int which) {
796 conversation
797 .setNextEncryption(Message.ENCRYPTION_NONE);
798 message.setEncryption(Message.ENCRYPTION_NONE);
799 xmppService.sendMessage(message, null);
800 chatMsg.setText("");
801 }
802 });
803 }
804 } else {
805 if (conversation.getMucOptions().pgpKeysInUse()) {
806 if (!conversation.getMucOptions().everybodyHasKeys()) {
807 Toast warning = Toast
808 .makeText(getActivity(),
809 R.string.missing_public_keys,
810 Toast.LENGTH_LONG);
811 warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
812 warning.show();
813 }
814 activity.encryptTextMessage();
815 } else {
816 showNoPGPKeyDialog(true,
817 new DialogInterface.OnClickListener() {
818
819 @Override
820 public void onClick(DialogInterface dialog,
821 int which) {
822 conversation
823 .setNextEncryption(Message.ENCRYPTION_NONE);
824 message.setEncryption(Message.ENCRYPTION_NONE);
825 xmppService.sendMessage(message, null);
826 chatMsg.setText("");
827 }
828 });
829 }
830 }
831 }
832 }
833
834 public void showNoPGPKeyDialog(boolean plural,
835 DialogInterface.OnClickListener listener) {
836 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
837 builder.setIconAttribute(android.R.attr.alertDialogIcon);
838 if (plural) {
839 builder.setTitle(getString(R.string.no_pgp_keys));
840 builder.setMessage(getText(R.string.contacts_have_no_pgp_keys));
841 } else {
842 builder.setTitle(getString(R.string.no_pgp_key));
843 builder.setMessage(getText(R.string.contact_has_no_pgp_key));
844 }
845 builder.setNegativeButton(getString(R.string.cancel), null);
846 builder.setPositiveButton(getString(R.string.send_unencrypted),
847 listener);
848 builder.create().show();
849 }
850
851 protected void sendOtrMessage(final Message message) {
852 ConversationActivity activity = (ConversationActivity) getActivity();
853 final XmppConnectionService xmppService = activity.xmppConnectionService;
854 if (conversation.hasValidOtrSession()) {
855 activity.xmppConnectionService.sendMessage(message, null);
856 chatMsg.setText("");
857 } else {
858 activity.selectPresence(message.getConversation(),
859 new OnPresenceSelected() {
860
861 @Override
862 public void onPresenceSelected(boolean success,
863 String presence) {
864 if (success) {
865 xmppService.sendMessage(message, presence);
866 chatMsg.setText("");
867 }
868 }
869
870 @Override
871 public void onSendPlainTextInstead() {
872 message.setEncryption(Message.ENCRYPTION_NONE);
873 xmppService.sendMessage(message, null);
874 chatMsg.setText("");
875 }
876 }, "otr");
877 }
878 }
879
880 private static class ViewHolder {
881
882 protected Button download_button;
883 protected ImageView image;
884 protected ImageView indicator;
885 protected TextView time;
886 protected TextView messageBody;
887 protected ImageView contact_picture;
888
889 }
890
891 private class BitmapCache {
892 private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
893
894 public Bitmap get(String name, Contact contact, Context context) {
895 if (bitmaps.containsKey(name)) {
896 return bitmaps.get(name);
897 } else {
898 Bitmap bm;
899 if (contact != null) {
900 bm = UIHelper
901 .getContactPicture(contact, 48, context, false);
902 } else {
903 bm = UIHelper.getContactPicture(name, 48, context, false);
904 }
905 bitmaps.put(name, bm);
906 return bm;
907 }
908 }
909 }
910
911 public void setText(String text) {
912 this.pastedText = text;
913 }
914
915 public void clearInputField() {
916 this.chatMsg.setText("");
917 }
918}