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 viewHolder.messageBody.setVisibility(View.GONE);
301 viewHolder.image.setVisibility(View.VISIBLE);
302 String[] params = item.getBody().split(",");
303 if (params.length==3) {
304 double target = metrics.density * 288;
305 int w = Integer.parseInt(params[1]);
306 int h = Integer.parseInt(params[2]);
307 int scalledW;
308 int scalledH;
309 if (w <= h) {
310 scalledW = (int) (w / ((double) h / target));
311 scalledH = (int) target;
312 } else {
313 scalledW = (int) target;
314 scalledH = (int) (h / ((double) w / target));
315 }
316 viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams(scalledW, scalledH));
317 } else {
318 Log.d("xmppService","message body has less than 3 params");
319 }
320 activity.loadBitmap(item, viewHolder.image);
321 viewHolder.image.setOnClickListener(new OnClickListener() {
322
323 @Override
324 public void onClick(View v) {
325 Uri uri = Uri.parse("content://eu.siacs.conversations.images/"+item.getConversationUuid()+"/"+item.getUuid());
326 Log.d("xmppService","staring intent with uri:"+uri.toString());
327 Intent intent = new Intent(Intent.ACTION_VIEW);
328 intent.setDataAndType(uri, "image/*");
329 startActivity(intent);
330 }
331 });
332 }
333 } else {
334 viewHolder.image.setVisibility(View.GONE);
335 viewHolder.messageBody.setVisibility(View.VISIBLE);
336 String body = item.getBody();
337 if (body != null) {
338 if (item.getEncryption() == Message.ENCRYPTION_PGP) {
339 viewHolder.messageBody
340 .setText(getString(R.string.encrypted_message));
341 viewHolder.messageBody.setTextColor(0xff33B5E5);
342 viewHolder.messageBody.setTypeface(null,
343 Typeface.ITALIC);
344 } else if ((item.getEncryption() == Message.ENCRYPTION_OTR)||(item.getEncryption() == Message.ENCRYPTION_DECRYPTED)) {
345 viewHolder.messageBody.setText(body.trim());
346 viewHolder.messageBody.setTextColor(0xff333333);
347 viewHolder.messageBody.setTypeface(null,
348 Typeface.NORMAL);
349 } else {
350 viewHolder.messageBody.setText(body.trim());
351 viewHolder.messageBody.setTextColor(0xff333333);
352 viewHolder.messageBody.setTypeface(null,
353 Typeface.NORMAL);
354 }
355 }
356 }
357 switch (item.getStatus()) {
358 case Message.STATUS_UNSEND:
359 viewHolder.time.setTypeface(null, Typeface.ITALIC);
360 viewHolder.time.setTextColor(0xFF8e8e8e);
361 viewHolder.time.setText("sending\u2026");
362 break;
363 case Message.STATUS_OFFERED:
364 viewHolder.time.setTypeface(null, Typeface.ITALIC);
365 viewHolder.time.setTextColor(0xFF8e8e8e);
366 viewHolder.time.setText("offering\u2026");
367 break;
368 case Message.STATUS_SEND_FAILED:
369 viewHolder.time.setText(getString(R.string.send_failed) + " \u00B7 " + UIHelper.readableTimeDifference(item
370 .getTimeSent()));
371 viewHolder.time.setTextColor(0xFFe92727);
372 viewHolder.time.setTypeface(null,Typeface.NORMAL);
373 break;
374 case Message.STATUS_SEND_REJECTED:
375 viewHolder.time.setText(getString(R.string.send_rejected));
376 viewHolder.time.setTextColor(0xFFe92727);
377 viewHolder.time.setTypeface(null,Typeface.NORMAL);
378 break;
379 default:
380 viewHolder.time.setTypeface(null, Typeface.NORMAL);
381 viewHolder.time.setTextColor(0xFF8e8e8e);
382 if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
383 viewHolder.time.setText(UIHelper
384 .readableTimeDifference(item.getTimeSent()));
385 } else {
386 viewHolder.time.setText(item.getCounterpart()
387 + " \u00B7 "
388 + UIHelper.readableTimeDifference(item
389 .getTimeSent()));
390 }
391 break;
392 }
393 return view;
394 }
395 };
396 messagesView.setAdapter(messageListAdapter);
397
398 return view;
399 }
400
401 protected Bitmap findSelfPicture() {
402 SharedPreferences sharedPref = PreferenceManager
403 .getDefaultSharedPreferences(getActivity()
404 .getApplicationContext());
405 boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
406 "show_phone_selfcontact_picture", true);
407
408 return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
409 showPhoneSelfContactPicture, getActivity());
410 }
411
412 @Override
413 public void onStart() {
414 super.onStart();
415 this.activity = (ConversationActivity) getActivity();
416 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
417 this.useSubject = preferences.getBoolean("use_subject_in_muc", true);
418 if (activity.xmppConnectionServiceBound) {
419 this.onBackendConnected();
420 }
421 }
422
423 public void onBackendConnected() {
424 this.conversation = activity.getSelectedConversation();
425 if (this.conversation == null) {
426 return;
427 }
428 this.selfBitmap = findSelfPicture();
429 updateMessages();
430 // rendering complete. now go tell activity to close pane
431 if (activity.getSlidingPaneLayout().isSlideable()) {
432 if (!activity.shouldPaneBeOpen()) {
433 activity.getSlidingPaneLayout().closePane();
434 activity.getActionBar().setDisplayHomeAsUpEnabled(true);
435 activity.getActionBar().setTitle(conversation.getName(useSubject));
436 activity.invalidateOptionsMenu();
437
438 }
439 }
440 if (queuedPqpMessage != null) {
441 this.conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
442 Message message = new Message(conversation, queuedPqpMessage,
443 Message.ENCRYPTION_PGP);
444 sendPgpMessage(message);
445 }
446 if (conversation.getMode() == Conversation.MODE_MULTI) {
447 activity.xmppConnectionService
448 .setOnRenameListener(new OnRenameListener() {
449
450 @Override
451 public void onRename(final boolean success) {
452 activity.xmppConnectionService.updateConversation(conversation);
453 getActivity().runOnUiThread(new Runnable() {
454
455 @Override
456 public void run() {
457 if (success) {
458 Toast.makeText(
459 getActivity(),
460 getString(R.string.your_nick_has_been_changed),
461 Toast.LENGTH_SHORT).show();
462 } else {
463 Toast.makeText(getActivity(),
464 getString(R.string.nick_in_use),
465 Toast.LENGTH_SHORT).show();
466 }
467 }
468 });
469 }
470 });
471 }
472 }
473
474 public void updateMessages() {
475 ConversationActivity activity = (ConversationActivity) getActivity();
476 if (this.conversation != null) {
477 List<Message> encryptedMessages = new LinkedList<Message>();
478 for (Message message : this.conversation.getMessages()) {
479 if (message.getEncryption() == Message.ENCRYPTION_PGP) {
480 encryptedMessages.add(message);
481 }
482 }
483 if (encryptedMessages.size() > 0) {
484 DecryptMessage task = new DecryptMessage();
485 Message[] msgs = new Message[encryptedMessages.size()];
486 task.execute(encryptedMessages.toArray(msgs));
487 }
488 this.messageList.clear();
489 this.messageList.addAll(this.conversation.getMessages());
490 this.messageListAdapter.notifyDataSetChanged();
491 if (conversation.getMode() == Conversation.MODE_SINGLE) {
492 if (messageList.size() >= 1) {
493 int latestEncryption = this.conversation.getLatestMessage()
494 .getEncryption();
495 if (latestEncryption == Message.ENCRYPTION_DECRYPTED) {
496 conversation.nextMessageEncryption = Message.ENCRYPTION_PGP;
497 } else {
498 conversation.nextMessageEncryption = latestEncryption;
499 }
500 makeFingerprintWarning(latestEncryption);
501 }
502 } else {
503 if (conversation.getMucOptions().getError() != 0) {
504 mucError.setVisibility(View.VISIBLE);
505 if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) {
506 mucErrorText.setText(getString(R.string.nick_in_use));
507 }
508 } else {
509 mucError.setVisibility(View.GONE);
510 }
511 }
512 getActivity().invalidateOptionsMenu();
513 updateChatMsgHint();
514 int size = this.messageList.size();
515 if (size >= 1)
516 messagesView.setSelection(size - 1);
517 if (!activity.shouldPaneBeOpen()) {
518 conversation.markRead();
519 // TODO update notifications
520 UIHelper.updateNotification(getActivity(),
521 activity.getConversationList(), null, false);
522 activity.updateConversationList();
523 }
524 }
525 }
526
527 protected void makeFingerprintWarning(int latestEncryption) {
528 final LinearLayout fingerprintWarning = (LinearLayout) getView()
529 .findViewById(R.id.new_fingerprint);
530 if (conversation.getContact() != null) {
531 Set<String> knownFingerprints = conversation.getContact()
532 .getOtrFingerprints();
533 if ((latestEncryption == Message.ENCRYPTION_OTR)
534 && (conversation.hasValidOtrSession()
535 && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
536 .contains(conversation.getOtrFingerprint())))) {
537 fingerprintWarning.setVisibility(View.VISIBLE);
538 TextView fingerprint = (TextView) getView().findViewById(
539 R.id.otr_fingerprint);
540 fingerprint.setText(conversation.getOtrFingerprint());
541 fingerprintWarning.setOnClickListener(new OnClickListener() {
542
543 @Override
544 public void onClick(View v) {
545 AlertDialog dialog = UIHelper
546 .getVerifyFingerprintDialog(
547 (ConversationActivity) getActivity(),
548 conversation, fingerprintWarning);
549 dialog.show();
550 }
551 });
552 } else {
553 fingerprintWarning.setVisibility(View.GONE);
554 }
555 } else {
556 fingerprintWarning.setVisibility(View.GONE);
557 }
558 }
559
560 protected void sendPlainTextMessage(Message message) {
561 ConversationActivity activity = (ConversationActivity) getActivity();
562 activity.xmppConnectionService.sendMessage(message, null);
563 chatMsg.setText("");
564 }
565
566 protected void sendPgpMessage(final Message message) {
567 ConversationActivity activity = (ConversationActivity) getActivity();
568 final XmppConnectionService xmppService = activity.xmppConnectionService;
569 Contact contact = message.getConversation().getContact();
570 Account account = message.getConversation().getAccount();
571 if (activity.hasPgp()) {
572 if (contact.getPgpKeyId() != 0) {
573 try {
574 message.setEncryptedBody(xmppService.getPgpEngine().encrypt(account, contact.getPgpKeyId(), message.getBody()));
575 xmppService.sendMessage(message, null);
576 chatMsg.setText("");
577 } catch (UserInputRequiredException e) {
578 try {
579 getActivity().startIntentSenderForResult(e.getPendingIntent().getIntentSender(),
580 ConversationActivity.REQUEST_SEND_MESSAGE, null, 0,
581 0, 0);
582 } catch (SendIntentException e1) {
583 Log.d("xmppService","failed to start intent to send message");
584 }
585 } catch (OpenPgpException e) {
586 Log.d("xmppService","error encrypting with pgp: "+e.getOpenPgpError().getMessage());
587 }
588 } else {
589 AlertDialog.Builder builder = new AlertDialog.Builder(
590 getActivity());
591 builder.setTitle("No openPGP key found");
592 builder.setIconAttribute(android.R.attr.alertDialogIcon);
593 builder.setMessage("There is no openPGP key associated with this contact");
594 builder.setNegativeButton("Cancel", null);
595 builder.setPositiveButton("Send plain text",
596 new DialogInterface.OnClickListener() {
597
598 @Override
599 public void onClick(DialogInterface dialog,
600 int which) {
601 conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
602 message.setEncryption(Message.ENCRYPTION_NONE);
603 xmppService.sendMessage(message, null);
604 chatMsg.setText("");
605 }
606 });
607 builder.create().show();
608 }
609 }
610 }
611
612 protected void sendOtrMessage(final Message message) {
613 ConversationActivity activity = (ConversationActivity) getActivity();
614 final XmppConnectionService xmppService = activity.xmppConnectionService;
615 if (conversation.hasValidOtrSession()) {
616 activity.xmppConnectionService.sendMessage(message, null);
617 chatMsg.setText("");
618 } else {
619 Hashtable<String, Integer> presences;
620 if (conversation.getContact() != null) {
621 presences = conversation.getContact().getPresences();
622 } else {
623 presences = null;
624 }
625 if ((presences == null) || (presences.size() == 0)) {
626 AlertDialog.Builder builder = new AlertDialog.Builder(
627 getActivity());
628 builder.setTitle("Contact is offline");
629 builder.setIconAttribute(android.R.attr.alertDialogIcon);
630 builder.setMessage("Sending OTR encrypted messages to an offline contact is impossible.");
631 builder.setPositiveButton("Send plain text",
632 new DialogInterface.OnClickListener() {
633
634 @Override
635 public void onClick(DialogInterface dialog,
636 int which) {
637 conversation.nextMessageEncryption = Message.ENCRYPTION_NONE;
638 message.setEncryption(Message.ENCRYPTION_NONE);
639 xmppService.sendMessage(message, null);
640 chatMsg.setText("");
641 }
642 });
643 builder.setNegativeButton("Cancel", null);
644 builder.create().show();
645 } else if (presences.size() == 1) {
646 xmppService.sendMessage(message, (String) presences.keySet()
647 .toArray()[0]);
648 chatMsg.setText("");
649 } else {
650 AlertDialog.Builder builder = new AlertDialog.Builder(
651 getActivity());
652 builder.setTitle("Choose Presence");
653 final String[] presencesArray = new String[presences.size()];
654 presences.keySet().toArray(presencesArray);
655 builder.setItems(presencesArray,
656 new DialogInterface.OnClickListener() {
657
658 @Override
659 public void onClick(DialogInterface dialog,
660 int which) {
661 xmppService.sendMessage(message,
662 presencesArray[which]);
663 chatMsg.setText("");
664 }
665 });
666 builder.create().show();
667 }
668 }
669 }
670
671 private static class ViewHolder {
672
673 protected Button download_button;
674 protected ImageView image;
675 protected ImageView indicator;
676 protected TextView time;
677 protected TextView messageBody;
678 protected ImageView contact_picture;
679
680 }
681
682 private class BitmapCache {
683 private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
684 private Bitmap error = null;
685
686 public Bitmap get(String name, Contact contact, Context context) {
687 if (bitmaps.containsKey(name)) {
688 return bitmaps.get(name);
689 } else {
690 Bitmap bm;
691 if (contact != null){
692 bm = UIHelper.getContactPicture(contact, 48, context, false);
693 } else {
694 bm = UIHelper.getContactPicture(name, 48, context, false);
695 }
696 bitmaps.put(name, bm);
697 return bm;
698 }
699 }
700 }
701
702 class DecryptMessage extends AsyncTask<Message, Void, Boolean> {
703
704 @Override
705 protected Boolean doInBackground(Message... params) {
706 final ConversationActivity activity = (ConversationActivity) getActivity();
707 askForPassphraseIntent = null;
708 for (int i = 0; i < params.length; ++i) {
709 if (params[i].getEncryption() == Message.ENCRYPTION_PGP) {
710 String body = params[i].getBody();
711 String decrypted = null;
712 if (activity == null) {
713 return false;
714 } else if (!activity.xmppConnectionServiceBound) {
715 return false;
716 }
717 try {
718 decrypted = activity.xmppConnectionService
719 .getPgpEngine().decrypt(conversation.getAccount(),body);
720 } catch (UserInputRequiredException e) {
721 askForPassphraseIntent = e.getPendingIntent()
722 .getIntentSender();
723 activity.runOnUiThread(new Runnable() {
724
725 @Override
726 public void run() {
727 pgpInfo.setVisibility(View.VISIBLE);
728 }
729 });
730
731 return false;
732
733 } catch (OpenPgpException e) {
734 Log.d("gultsch", "error decrypting pgp");
735 }
736 if (decrypted != null) {
737 params[i].setBody(decrypted);
738 params[i].setEncryption(Message.ENCRYPTION_DECRYPTED);
739 activity.xmppConnectionService.updateMessage(params[i]);
740 }
741 if (activity != null) {
742 activity.runOnUiThread(new Runnable() {
743
744 @Override
745 public void run() {
746 messageListAdapter.notifyDataSetChanged();
747 }
748 });
749 }
750 }
751 if (activity != null) {
752 activity.runOnUiThread(new Runnable() {
753
754 @Override
755 public void run() {
756 activity.updateConversationList();
757 }
758 });
759 }
760 }
761 return true;
762 }
763
764 }
765
766 public void setText(String text) {
767 this.pastedText = text;
768 }
769}