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