refactored message adapter into seperate class

Daniel Gultsch created

Change summary

src/eu/siacs/conversations/ui/ConversationFragment.java   | 456 --------
src/eu/siacs/conversations/ui/XmppActivity.java           |  13 
src/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 474 +++++++++
3 files changed, 498 insertions(+), 445 deletions(-)

Detailed changes

src/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -1,7 +1,6 @@
 package eu.siacs.conversations.ui;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Set;
 
@@ -13,42 +12,34 @@ import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions;
-import eu.siacs.conversations.services.ImageProvider;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected;
+import eu.siacs.conversations.ui.adapter.MessageAdapter;
+import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
 import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jingle.JingleConnection;
 import android.app.AlertDialog;
 import android.app.Fragment;
 import android.app.PendingIntent;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.IntentSender.SendIntentException;
-import android.graphics.Bitmap;
-import android.graphics.Typeface;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.text.Editable;
 import android.text.Selection;
-import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.AbsListView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
+
 import android.widget.EditText;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.ImageButton;
-import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -59,12 +50,8 @@ public class ConversationFragment extends Fragment {
 	protected ListView messagesView;
 	protected LayoutInflater inflater;
 	protected List<Message> messageList = new ArrayList<Message>();
-	protected ArrayAdapter<Message> messageListAdapter;
+	protected MessageAdapter messageListAdapter;
 	protected Contact contact;
-	protected BitmapCache mBitmapCache = new BitmapCache();
-
-	protected int mPrimaryTextColor;
-	protected int mSecondaryTextColor;
 
 	protected String queuedPqpMessage = null;
 
@@ -74,8 +61,6 @@ public class ConversationFragment extends Fragment {
 	private TextView snackbarMessage;
 	private TextView snackbarAction;
 
-	protected Bitmap selfBitmap;
-
 	private boolean useSubject = true;
 	private boolean messagesLoaded = false;
 
@@ -182,14 +167,6 @@ public class ConversationFragment extends Fragment {
 	@Override
 	public View onCreateView(final LayoutInflater inflater,
 			ViewGroup container, Bundle savedInstanceState) {
-
-		final DisplayMetrics metrics = getResources().getDisplayMetrics();
-
-		this.inflater = inflater;
-
-		mPrimaryTextColor = getResources().getColor(R.color.primarytext);
-		mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
-
 		final View view = inflater.inflate(R.layout.fragment_conversation,
 				container, false);
 		chatMsg = (EditText) view.findViewById(R.id.textinput);
@@ -214,383 +191,16 @@ public class ConversationFragment extends Fragment {
 		messagesView = (ListView) view.findViewById(R.id.messages_view);
 		messagesView.setOnScrollListener(mOnScrollListener);
 		messagesView.setTranscriptMode(ListView.TRANSCRIPT_MODE_NORMAL);
-
-		messageListAdapter = new ArrayAdapter<Message>(this.getActivity()
-				.getApplicationContext(), R.layout.message_sent,
-				this.messageList) {
-
-			private static final int SENT = 0;
-			private static final int RECIEVED = 1;
-			private static final int STATUS = 2;
-
+		messageListAdapter = new MessageAdapter((ConversationActivity) getActivity(), this.messageList);
+		messageListAdapter.setOnContactPictureClicked(new OnContactPictureClicked() {
+			
 			@Override
-			public int getViewTypeCount() {
-				return 3;
-			}
-
-			@Override
-			public int getItemViewType(int position) {
-				if (getItem(position).getType() == Message.TYPE_STATUS) {
-					return STATUS;
-				} else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
-					return RECIEVED;
-				} else {
-					return SENT;
+			public void onContactPictureClicked(Message message) {
+				if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
+					highlightInConference(message.getCounterpart());
 				}
 			}
-
-			private void displayStatus(ViewHolder viewHolder, Message message) {
-				String filesize = null;
-				String info = null;
-				boolean error = false;
-				boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
-						&& message.getStatus() <= Message.STATUS_RECIEVED;
-				if (message.getType() == Message.TYPE_IMAGE) {
-					String[] fileParams = message.getBody().split(",");
-					try {
-						long size = Long.parseLong(fileParams[0]);
-						filesize = size / 1024 + " KB";
-					} catch (NumberFormatException e) {
-						filesize = "0 KB";
-					}
-				}
-				switch (message.getStatus()) {
-				case Message.STATUS_WAITING:
-					info = getString(R.string.waiting);
-					break;
-				case Message.STATUS_UNSEND:
-					info = getString(R.string.sending);
-					break;
-				case Message.STATUS_OFFERED:
-					info = getString(R.string.offering);
-					break;
-				case Message.STATUS_SEND_FAILED:
-					info = getString(R.string.send_failed);
-					error = true;
-					break;
-				case Message.STATUS_SEND_REJECTED:
-					info = getString(R.string.send_rejected);
-					error = true;
-					break;
-				case Message.STATUS_RECEPTION_FAILED:
-					info = getString(R.string.reception_failed);
-					error = true;
-				default:
-					if (multiReceived) {
-						info = message.getCounterpart();
-					}
-					break;
-				}
-				if (error) {
-					viewHolder.time.setTextColor(0xFFe92727);
-				} else {
-					viewHolder.time.setTextColor(mSecondaryTextColor);
-				}
-				if (message.getEncryption() == Message.ENCRYPTION_NONE) {
-					viewHolder.indicator.setVisibility(View.GONE);
-				} else {
-					viewHolder.indicator.setVisibility(View.VISIBLE);
-				}
-
-				String formatedTime = UIHelper.readableTimeDifference(
-						getContext(), message.getTimeSent());
-				if (message.getStatus() <= Message.STATUS_RECIEVED) {
-					if ((filesize != null) && (info != null)) {
-						viewHolder.time.setText(filesize + " \u00B7 " + info);
-					} else if ((filesize == null) && (info != null)) {
-						viewHolder.time.setText(formatedTime + " \u00B7 "
-								+ info);
-					} else if ((filesize != null) && (info == null)) {
-						viewHolder.time.setText(formatedTime + " \u00B7 "
-								+ filesize);
-					} else {
-						viewHolder.time.setText(formatedTime);
-					}
-				} else {
-					if ((filesize != null) && (info != null)) {
-						viewHolder.time.setText(filesize + " \u00B7 " + info);
-					} else if ((filesize == null) && (info != null)) {
-						if (error) {
-							viewHolder.time.setText(info + " \u00B7 "
-									+ formatedTime);
-						} else {
-							viewHolder.time.setText(info);
-						}
-					} else if ((filesize != null) && (info == null)) {
-						viewHolder.time.setText(filesize + " \u00B7 "
-								+ formatedTime);
-					} else {
-						viewHolder.time.setText(formatedTime);
-					}
-				}
-			}
-
-			private void displayInfoMessage(ViewHolder viewHolder, int r) {
-				if (viewHolder.download_button != null) {
-					viewHolder.download_button.setVisibility(View.GONE);
-				}
-				viewHolder.image.setVisibility(View.GONE);
-				viewHolder.messageBody.setVisibility(View.VISIBLE);
-				viewHolder.messageBody.setText(getString(r));
-				viewHolder.messageBody.setTextColor(0xff33B5E5);
-				viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
-				viewHolder.messageBody.setTextIsSelectable(false);
-			}
-
-			private void displayDecryptionFailed(ViewHolder viewHolder) {
-				if (viewHolder.download_button != null) {
-					viewHolder.download_button.setVisibility(View.GONE);
-				}
-				viewHolder.image.setVisibility(View.GONE);
-				viewHolder.messageBody.setVisibility(View.VISIBLE);
-				viewHolder.messageBody
-						.setText(getString(R.string.decryption_failed));
-				viewHolder.messageBody.setTextColor(0xFFe92727);
-				viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
-				viewHolder.messageBody.setTextIsSelectable(false);
-			}
-
-			private void displayTextMessage(ViewHolder viewHolder, String text) {
-				if (viewHolder.download_button != null) {
-					viewHolder.download_button.setVisibility(View.GONE);
-				}
-				viewHolder.image.setVisibility(View.GONE);
-				viewHolder.messageBody.setVisibility(View.VISIBLE);
-				if (text != null) {
-					viewHolder.messageBody.setText(text.trim());
-				} else {
-					viewHolder.messageBody.setText("");
-				}
-				viewHolder.messageBody.setTextColor(mPrimaryTextColor);
-				viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
-				viewHolder.messageBody.setTextIsSelectable(true);
-			}
-
-			private void displayImageMessage(ViewHolder viewHolder,
-					final Message message) {
-				if (viewHolder.download_button != null) {
-					viewHolder.download_button.setVisibility(View.GONE);
-				}
-				viewHolder.messageBody.setVisibility(View.GONE);
-				viewHolder.image.setVisibility(View.VISIBLE);
-				String[] fileParams = message.getBody().split(",");
-				if (fileParams.length == 3) {
-					double target = metrics.density * 288;
-					int w = Integer.parseInt(fileParams[1]);
-					int h = Integer.parseInt(fileParams[2]);
-					int scalledW;
-					int scalledH;
-					if (w <= h) {
-						scalledW = (int) (w / ((double) h / target));
-						scalledH = (int) target;
-					} else {
-						scalledW = (int) target;
-						scalledH = (int) (h / ((double) w / target));
-					}
-					viewHolder.image
-							.setLayoutParams(new LinearLayout.LayoutParams(
-									scalledW, scalledH));
-				}
-				activity.loadBitmap(message, viewHolder.image);
-				viewHolder.image.setOnClickListener(new OnClickListener() {
-
-					@Override
-					public void onClick(View v) {
-						Intent intent = new Intent(Intent.ACTION_VIEW);
-						intent.setDataAndType(
-								ImageProvider.getContentUri(message), "image/*");
-						startActivity(intent);
-					}
-				});
-				viewHolder.image
-						.setOnLongClickListener(new OnLongClickListener() {
-
-							@Override
-							public boolean onLongClick(View v) {
-								Intent shareIntent = new Intent();
-								shareIntent.setAction(Intent.ACTION_SEND);
-								shareIntent.putExtra(Intent.EXTRA_STREAM,
-										ImageProvider.getContentUri(message));
-								shareIntent.setType("image/webp");
-								startActivity(Intent.createChooser(shareIntent,
-										getText(R.string.share_with)));
-								return true;
-							}
-						});
-			}
-
-			@Override
-			public View getView(int position, View view, ViewGroup parent) {
-				final Message item = getItem(position);
-				int type = getItemViewType(position);
-				ViewHolder viewHolder;
-				if (view == null) {
-					viewHolder = new ViewHolder();
-					switch (type) {
-					case SENT:
-						view = (View) inflater.inflate(R.layout.message_sent,
-								null);
-						viewHolder.message_box = (LinearLayout) view
-								.findViewById(R.id.message_box);
-						viewHolder.contact_picture = (ImageView) view
-								.findViewById(R.id.message_photo);
-						viewHolder.contact_picture.setImageBitmap(selfBitmap);
-						viewHolder.indicator = (ImageView) view
-								.findViewById(R.id.security_indicator);
-						viewHolder.image = (ImageView) view
-								.findViewById(R.id.message_image);
-						viewHolder.messageBody = (TextView) view
-								.findViewById(R.id.message_body);
-						viewHolder.time = (TextView) view
-								.findViewById(R.id.message_time);
-						view.setTag(viewHolder);
-						break;
-					case RECIEVED:
-						view = (View) inflater.inflate(
-								R.layout.message_recieved, null);
-						viewHolder.message_box = (LinearLayout) view
-								.findViewById(R.id.message_box);
-						viewHolder.contact_picture = (ImageView) view
-								.findViewById(R.id.message_photo);
-
-						viewHolder.download_button = (Button) view
-								.findViewById(R.id.download_button);
-
-						if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-
-							viewHolder.contact_picture
-									.setImageBitmap(mBitmapCache.get(
-											item.getConversation().getName(
-													useSubject), item
-													.getConversation()
-													.getContact(),
-											getActivity()
-													.getApplicationContext()));
-
-						}
-						viewHolder.indicator = (ImageView) view
-								.findViewById(R.id.security_indicator);
-						viewHolder.image = (ImageView) view
-								.findViewById(R.id.message_image);
-						viewHolder.messageBody = (TextView) view
-								.findViewById(R.id.message_body);
-						viewHolder.time = (TextView) view
-								.findViewById(R.id.message_time);
-						view.setTag(viewHolder);
-						break;
-					case STATUS:
-						view = (View) inflater.inflate(R.layout.message_status,
-								null);
-						viewHolder.contact_picture = (ImageView) view
-								.findViewById(R.id.message_photo);
-						if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
-
-							viewHolder.contact_picture
-									.setImageBitmap(mBitmapCache.get(
-											item.getConversation().getName(
-													useSubject), item
-													.getConversation()
-													.getContact(),
-											getActivity()
-													.getApplicationContext()));
-							viewHolder.contact_picture.setAlpha(128);
-							viewHolder.contact_picture.setOnClickListener(new OnClickListener() {
-								
-								@Override
-								public void onClick(View v) {
-									Toast.makeText(getActivity(), R.string.contact_has_read_up_to_this_point, Toast.LENGTH_SHORT).show();	
-								}
-							});
-
-						}
-						break;
-					default:
-						viewHolder = null;
-						break;
-					}
-				} else {
-					viewHolder = (ViewHolder) view.getTag();
-				}
-
-				if (type == STATUS) {
-					return view;
-				}
-
-				if (type == RECIEVED) {
-					if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
-						viewHolder.contact_picture.setImageBitmap(mBitmapCache
-								.get(item.getCounterpart(), null, getActivity()
-										.getApplicationContext()));
-						viewHolder.contact_picture
-								.setOnClickListener(new OnClickListener() {
-
-									@Override
-									public void onClick(View v) {
-										highlightInConference(item
-												.getCounterpart());
-									}
-								});
-					}
-				}
-
-				if (item.getType() == Message.TYPE_IMAGE) {
-					if (item.getStatus() == Message.STATUS_RECIEVING) {
-						displayInfoMessage(viewHolder, R.string.receiving_image);
-					} else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
-						viewHolder.image.setVisibility(View.GONE);
-						viewHolder.messageBody.setVisibility(View.GONE);
-						viewHolder.download_button.setVisibility(View.VISIBLE);
-						viewHolder.download_button
-								.setOnClickListener(new OnClickListener() {
-
-									@Override
-									public void onClick(View v) {
-										JingleConnection connection = item
-												.getJingleConnection();
-										if (connection != null) {
-											connection.accept();
-										}
-									}
-								});
-					} else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
-							|| (item.getEncryption() == Message.ENCRYPTION_NONE)
-							|| (item.getEncryption() == Message.ENCRYPTION_OTR)) {
-						displayImageMessage(viewHolder, item);
-					} else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
-						displayInfoMessage(viewHolder,
-								R.string.encrypted_message);
-					} else {
-						displayDecryptionFailed(viewHolder);
-					}
-				} else {
-					if (item.getEncryption() == Message.ENCRYPTION_PGP) {
-						if (activity.hasPgp()) {
-							displayInfoMessage(viewHolder,
-									R.string.encrypted_message);
-						} else {
-							displayInfoMessage(viewHolder,
-									R.string.install_openkeychain);
-							viewHolder.message_box
-									.setOnClickListener(new OnClickListener() {
-
-										@Override
-										public void onClick(View v) {
-											activity.showInstallPgpDialog();
-										}
-									});
-						}
-					} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
-						displayDecryptionFailed(viewHolder);
-					} else {
-						displayTextMessage(viewHolder, item.getBody());
-					}
-				}
-
-				displayStatus(viewHolder, item);
-
-				return view;
-			}
-		};
+		});
 		messagesView.setAdapter(messageListAdapter);
 
 		return view;
@@ -608,17 +218,6 @@ public class ConversationFragment extends Fragment {
 		Selection.setSelection(etext, position);
 	}
 
-	protected Bitmap findSelfPicture() {
-		SharedPreferences sharedPref = PreferenceManager
-				.getDefaultSharedPreferences(getActivity()
-						.getApplicationContext());
-		boolean showPhoneSelfContactPicture = sharedPref.getBoolean(
-				"show_phone_selfcontact_picture", true);
-
-		return UIHelper.getSelfContactPicture(conversation.getAccount(), 48,
-				showPhoneSelfContactPicture, getActivity());
-	}
-
 	@Override
 	public void onStart() {
 		super.onStart();
@@ -659,7 +258,6 @@ public class ConversationFragment extends Fragment {
 		int position = chatMsg.length();
 		Editable etext = chatMsg.getText();
 		Selection.setSelection(etext, position);
-		this.selfBitmap = findSelfPicture();
 		updateMessages();
 		if (activity.getSlidingPaneLayout().isSlideable()) {
 			if (!activity.shouldPaneBeOpen()) {
@@ -957,38 +555,6 @@ public class ConversationFragment extends Fragment {
 		}
 	}
 
-	private static class ViewHolder {
-
-		protected LinearLayout message_box;
-		protected Button download_button;
-		protected ImageView image;
-		protected ImageView indicator;
-		protected TextView time;
-		protected TextView messageBody;
-		protected ImageView contact_picture;
-
-	}
-
-	private class BitmapCache {
-		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
-
-		public Bitmap get(String name, Contact contact, Context context) {
-			if (bitmaps.containsKey(name)) {
-				return bitmaps.get(name);
-			} else {
-				Bitmap bm;
-				if (contact != null) {
-					bm = UIHelper
-							.getContactPicture(contact, 48, context, false);
-				} else {
-					bm = UIHelper.getContactPicture(name, 48, context, false);
-				}
-				bitmaps.put(name, bm);
-				return bm;
-			}
-		}
-	}
-
 	public void setText(String text) {
 		this.pastedText = text;
 	}

src/eu/siacs/conversations/ui/XmppActivity.java 🔗

@@ -40,6 +40,9 @@ public abstract class XmppActivity extends Activity {
 	public boolean xmppConnectionServiceBound = false;
 	protected boolean handledViewIntent = false;
 	
+	protected int mPrimaryTextColor;
+	protected int mSecondaryTextColor;
+	
 	protected interface OnValueEdited {
 		public void onValueEdited(String value);
 	}
@@ -157,6 +160,8 @@ public abstract class XmppActivity extends Activity {
 	protected void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 		ExceptionHelper.init(getApplicationContext());
+		mPrimaryTextColor = getResources().getColor(R.color.primarytext);
+		mSecondaryTextColor = getResources().getColor(R.color.secondarytext);
 	}
 
 	public void switchToConversation(Conversation conversation) {
@@ -355,4 +360,12 @@ public abstract class XmppActivity extends Activity {
 			Log.d("xmppService","inviting "+contactJid+" to "+conversation.getName(true));
 		}
 	}
+	
+	public int getSecondaryTextColor() {
+		return this.mSecondaryTextColor;
+	}
+	
+	public int getPrimaryTextColor() {
+		return this.mPrimaryTextColor;
+	}
 }

src/eu/siacs/conversations/ui/adapter/MessageAdapter.java 🔗

@@ -0,0 +1,474 @@
+package eu.siacs.conversations.ui.adapter;
+
+import java.util.HashMap;
+import java.util.List;
+
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.Contact;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.ImageProvider;
+import eu.siacs.conversations.ui.ConversationActivity;
+import eu.siacs.conversations.utils.UIHelper;
+import eu.siacs.conversations.xmpp.jingle.JingleConnection;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.graphics.Bitmap;
+import android.graphics.Typeface;
+import android.preference.PreferenceManager;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class MessageAdapter extends ArrayAdapter<Message> {
+
+	private static final int SENT = 0;
+	private static final int RECIEVED = 1;
+	private static final int STATUS = 2;
+
+	private ConversationActivity activity;
+
+	private Bitmap selfBitmap2;
+
+	private BitmapCache mBitmapCache = new BitmapCache();
+	private DisplayMetrics metrics;
+
+	private boolean useSubject = true;
+
+	private OnContactPictureClicked mOnContactPictureClickedListener;
+
+	public MessageAdapter(ConversationActivity activity, List<Message> messages) {
+		super(activity, 0, messages);
+		this.activity = activity;
+		metrics = getContext().getResources().getDisplayMetrics();
+		SharedPreferences preferences = PreferenceManager
+				.getDefaultSharedPreferences(getContext());
+		useSubject = preferences.getBoolean("use_subject_in_muc", true);
+	}
+
+	private Bitmap getSelfBitmap() {
+		if (this.selfBitmap2 == null) {
+
+			if (getCount() > 0) {
+				SharedPreferences preferences = PreferenceManager
+						.getDefaultSharedPreferences(getContext());
+				boolean showPhoneSelfContactPicture = preferences.getBoolean(
+						"show_phone_selfcontact_picture", true);
+
+				this.selfBitmap2 = UIHelper.getSelfContactPicture(getItem(0)
+						.getConversation().getAccount(), 48,
+						showPhoneSelfContactPicture, getContext());
+			}
+		}
+		return this.selfBitmap2;
+	}
+
+	public void setOnContactPictureClicked(OnContactPictureClicked listener) {
+		this.mOnContactPictureClickedListener = listener;
+	}
+
+	@Override
+	public int getViewTypeCount() {
+		return 3;
+	}
+
+	@Override
+	public int getItemViewType(int position) {
+		if (getItem(position).getType() == Message.TYPE_STATUS) {
+			return STATUS;
+		} else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
+			return RECIEVED;
+		} else {
+			return SENT;
+		}
+	}
+
+	private void displayStatus(ViewHolder viewHolder, Message message) {
+		String filesize = null;
+		String info = null;
+		boolean error = false;
+		boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
+				&& message.getStatus() <= Message.STATUS_RECIEVED;
+		if (message.getType() == Message.TYPE_IMAGE) {
+			String[] fileParams = message.getBody().split(",");
+			try {
+				long size = Long.parseLong(fileParams[0]);
+				filesize = size / 1024 + " KB";
+			} catch (NumberFormatException e) {
+				filesize = "0 KB";
+			}
+		}
+		switch (message.getStatus()) {
+		case Message.STATUS_WAITING:
+			info = getContext().getString(R.string.waiting);
+			break;
+		case Message.STATUS_UNSEND:
+			info = getContext().getString(R.string.sending);
+			break;
+		case Message.STATUS_OFFERED:
+			info = getContext().getString(R.string.offering);
+			break;
+		case Message.STATUS_SEND_FAILED:
+			info = getContext().getString(R.string.send_failed);
+			error = true;
+			break;
+		case Message.STATUS_SEND_REJECTED:
+			info = getContext().getString(R.string.send_rejected);
+			error = true;
+			break;
+		case Message.STATUS_RECEPTION_FAILED:
+			info = getContext().getString(R.string.reception_failed);
+			error = true;
+		default:
+			if (multiReceived) {
+				info = message.getCounterpart();
+			}
+			break;
+		}
+		if (error) {
+			viewHolder.time.setTextColor(0xFFe92727);
+		} else {
+			viewHolder.time.setTextColor(activity.getSecondaryTextColor());
+		}
+		if (message.getEncryption() == Message.ENCRYPTION_NONE) {
+			viewHolder.indicator.setVisibility(View.GONE);
+		} else {
+			viewHolder.indicator.setVisibility(View.VISIBLE);
+		}
+
+		String formatedTime = UIHelper.readableTimeDifference(getContext(),
+				message.getTimeSent());
+		if (message.getStatus() <= Message.STATUS_RECIEVED) {
+			if ((filesize != null) && (info != null)) {
+				viewHolder.time.setText(filesize + " \u00B7 " + info);
+			} else if ((filesize == null) && (info != null)) {
+				viewHolder.time.setText(formatedTime + " \u00B7 " + info);
+			} else if ((filesize != null) && (info == null)) {
+				viewHolder.time.setText(formatedTime + " \u00B7 " + filesize);
+			} else {
+				viewHolder.time.setText(formatedTime);
+			}
+		} else {
+			if ((filesize != null) && (info != null)) {
+				viewHolder.time.setText(filesize + " \u00B7 " + info);
+			} else if ((filesize == null) && (info != null)) {
+				if (error) {
+					viewHolder.time.setText(info + " \u00B7 " + formatedTime);
+				} else {
+					viewHolder.time.setText(info);
+				}
+			} else if ((filesize != null) && (info == null)) {
+				viewHolder.time.setText(filesize + " \u00B7 " + formatedTime);
+			} else {
+				viewHolder.time.setText(formatedTime);
+			}
+		}
+	}
+
+	private void displayInfoMessage(ViewHolder viewHolder, int r) {
+		if (viewHolder.download_button != null) {
+			viewHolder.download_button.setVisibility(View.GONE);
+		}
+		viewHolder.image.setVisibility(View.GONE);
+		viewHolder.messageBody.setVisibility(View.VISIBLE);
+		viewHolder.messageBody.setText(getContext().getString(r));
+		viewHolder.messageBody.setTextColor(0xff33B5E5);
+		viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
+		viewHolder.messageBody.setTextIsSelectable(false);
+	}
+
+	private void displayDecryptionFailed(ViewHolder viewHolder) {
+		if (viewHolder.download_button != null) {
+			viewHolder.download_button.setVisibility(View.GONE);
+		}
+		viewHolder.image.setVisibility(View.GONE);
+		viewHolder.messageBody.setVisibility(View.VISIBLE);
+		viewHolder.messageBody.setText(getContext().getString(
+				R.string.decryption_failed));
+		viewHolder.messageBody.setTextColor(0xFFe92727);
+		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+		viewHolder.messageBody.setTextIsSelectable(false);
+	}
+
+	private void displayTextMessage(ViewHolder viewHolder, String text) {
+		if (viewHolder.download_button != null) {
+			viewHolder.download_button.setVisibility(View.GONE);
+		}
+		viewHolder.image.setVisibility(View.GONE);
+		viewHolder.messageBody.setVisibility(View.VISIBLE);
+		if (text != null) {
+			viewHolder.messageBody.setText(text.trim());
+		} else {
+			viewHolder.messageBody.setText("");
+		}
+		viewHolder.messageBody.setTextColor(activity.getPrimaryTextColor());
+		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
+		viewHolder.messageBody.setTextIsSelectable(true);
+	}
+
+	private void displayImageMessage(ViewHolder viewHolder,
+			final Message message) {
+		if (viewHolder.download_button != null) {
+			viewHolder.download_button.setVisibility(View.GONE);
+		}
+		viewHolder.messageBody.setVisibility(View.GONE);
+		viewHolder.image.setVisibility(View.VISIBLE);
+		String[] fileParams = message.getBody().split(",");
+		if (fileParams.length == 3) {
+			double target = metrics.density * 288;
+			int w = Integer.parseInt(fileParams[1]);
+			int h = Integer.parseInt(fileParams[2]);
+			int scalledW;
+			int scalledH;
+			if (w <= h) {
+				scalledW = (int) (w / ((double) h / target));
+				scalledH = (int) target;
+			} else {
+				scalledW = (int) target;
+				scalledH = (int) (h / ((double) w / target));
+			}
+			viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams(
+					scalledW, scalledH));
+		}
+		activity.loadBitmap(message, viewHolder.image);
+		viewHolder.image.setOnClickListener(new OnClickListener() {
+
+			@Override
+			public void onClick(View v) {
+				Intent intent = new Intent(Intent.ACTION_VIEW);
+				intent.setDataAndType(ImageProvider.getContentUri(message),
+						"image/*");
+				getContext().startActivity(intent);
+			}
+		});
+		viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
+
+			@Override
+			public boolean onLongClick(View v) {
+				Intent shareIntent = new Intent();
+				shareIntent.setAction(Intent.ACTION_SEND);
+				shareIntent.putExtra(Intent.EXTRA_STREAM,
+						ImageProvider.getContentUri(message));
+				shareIntent.setType("image/webp");
+				getContext().startActivity(
+						Intent.createChooser(shareIntent,
+								getContext().getText(R.string.share_with)));
+				return true;
+			}
+		});
+	}
+
+	@Override
+	public View getView(int position, View view, ViewGroup parent) {
+		final Message item = getItem(position);
+		int type = getItemViewType(position);
+		ViewHolder viewHolder;
+		if (view == null) {
+			viewHolder = new ViewHolder();
+			switch (type) {
+			case SENT:
+				view = (View) activity.getLayoutInflater().inflate(
+						R.layout.message_sent, null);
+				viewHolder.message_box = (LinearLayout) view
+						.findViewById(R.id.message_box);
+				viewHolder.contact_picture = (ImageView) view
+						.findViewById(R.id.message_photo);
+				viewHolder.contact_picture.setImageBitmap(getSelfBitmap());
+				viewHolder.indicator = (ImageView) view
+						.findViewById(R.id.security_indicator);
+				viewHolder.image = (ImageView) view
+						.findViewById(R.id.message_image);
+				viewHolder.messageBody = (TextView) view
+						.findViewById(R.id.message_body);
+				viewHolder.time = (TextView) view
+						.findViewById(R.id.message_time);
+				view.setTag(viewHolder);
+				break;
+			case RECIEVED:
+				view = (View) activity.getLayoutInflater().inflate(
+						R.layout.message_recieved, null);
+				viewHolder.message_box = (LinearLayout) view
+						.findViewById(R.id.message_box);
+				viewHolder.contact_picture = (ImageView) view
+						.findViewById(R.id.message_photo);
+
+				viewHolder.download_button = (Button) view
+						.findViewById(R.id.download_button);
+
+				if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+
+					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+							item.getConversation().getName(useSubject), item
+									.getConversation().getContact(),
+							getContext()));
+
+				}
+				viewHolder.indicator = (ImageView) view
+						.findViewById(R.id.security_indicator);
+				viewHolder.image = (ImageView) view
+						.findViewById(R.id.message_image);
+				viewHolder.messageBody = (TextView) view
+						.findViewById(R.id.message_body);
+				viewHolder.time = (TextView) view
+						.findViewById(R.id.message_time);
+				view.setTag(viewHolder);
+				break;
+			case STATUS:
+				view = (View) activity.getLayoutInflater().inflate(
+						R.layout.message_status, null);
+				viewHolder.contact_picture = (ImageView) view
+						.findViewById(R.id.message_photo);
+				if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
+
+					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+							item.getConversation().getName(useSubject), item
+									.getConversation().getContact(),
+							getContext()));
+					viewHolder.contact_picture.setAlpha(128);
+					viewHolder.contact_picture
+							.setOnClickListener(new OnClickListener() {
+
+								@Override
+								public void onClick(View v) {
+									Toast.makeText(
+											getContext(),
+											R.string.contact_has_read_up_to_this_point,
+											Toast.LENGTH_SHORT).show();
+								}
+							});
+
+				}
+				break;
+			default:
+				viewHolder = null;
+				break;
+			}
+		} else {
+			viewHolder = (ViewHolder) view.getTag();
+		}
+
+		if (type == STATUS) {
+			return view;
+		}
+
+		if (type == RECIEVED) {
+			if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
+				viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
+						item.getCounterpart(), null, getContext()));
+				viewHolder.contact_picture
+						.setOnClickListener(new OnClickListener() {
+
+							@Override
+							public void onClick(View v) {
+								if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
+									MessageAdapter.this.mOnContactPictureClickedListener
+											.onContactPictureClicked(item);
+									;
+								}
+
+							}
+						});
+			}
+		}
+
+		if (item.getType() == Message.TYPE_IMAGE) {
+			if (item.getStatus() == Message.STATUS_RECIEVING) {
+				displayInfoMessage(viewHolder, R.string.receiving_image);
+			} else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
+				viewHolder.image.setVisibility(View.GONE);
+				viewHolder.messageBody.setVisibility(View.GONE);
+				viewHolder.download_button.setVisibility(View.VISIBLE);
+				viewHolder.download_button
+						.setOnClickListener(new OnClickListener() {
+
+							@Override
+							public void onClick(View v) {
+								JingleConnection connection = item
+										.getJingleConnection();
+								if (connection != null) {
+									connection.accept();
+								}
+							}
+						});
+			} else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
+					|| (item.getEncryption() == Message.ENCRYPTION_NONE)
+					|| (item.getEncryption() == Message.ENCRYPTION_OTR)) {
+				displayImageMessage(viewHolder, item);
+			} else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+				displayInfoMessage(viewHolder, R.string.encrypted_message);
+			} else {
+				displayDecryptionFailed(viewHolder);
+			}
+		} else {
+			if (item.getEncryption() == Message.ENCRYPTION_PGP) {
+				if (activity.hasPgp()) {
+					displayInfoMessage(viewHolder, R.string.encrypted_message);
+				} else {
+					displayInfoMessage(viewHolder,
+							R.string.install_openkeychain);
+					viewHolder.message_box
+							.setOnClickListener(new OnClickListener() {
+
+								@Override
+								public void onClick(View v) {
+									activity.showInstallPgpDialog();
+								}
+							});
+				}
+			} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
+				displayDecryptionFailed(viewHolder);
+			} else {
+				displayTextMessage(viewHolder, item.getBody());
+			}
+		}
+
+		displayStatus(viewHolder, item);
+
+		return view;
+	}
+
+	private static class ViewHolder {
+
+		protected LinearLayout message_box;
+		protected Button download_button;
+		protected ImageView image;
+		protected ImageView indicator;
+		protected TextView time;
+		protected TextView messageBody;
+		protected ImageView contact_picture;
+
+	}
+
+	private class BitmapCache {
+		private HashMap<String, Bitmap> bitmaps = new HashMap<String, Bitmap>();
+
+		public Bitmap get(String name, Contact contact, Context context) {
+			if (bitmaps.containsKey(name)) {
+				return bitmaps.get(name);
+			} else {
+				Bitmap bm;
+				if (contact != null) {
+					bm = UIHelper
+							.getContactPicture(contact, 48, context, false);
+				} else {
+					bm = UIHelper.getContactPicture(name, 48, context, false);
+				}
+				bitmaps.put(name, bm);
+				return bm;
+			}
+		}
+	}
+
+	public interface OnContactPictureClicked {
+		public void onContactPictureClicked(Message message);
+	}
+}