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