MessageAdapter.java

  1package eu.siacs.conversations.ui.adapter;
  2
  3import java.util.HashMap;
  4import java.util.List;
  5
  6import eu.siacs.conversations.R;
  7import eu.siacs.conversations.entities.Contact;
  8import eu.siacs.conversations.entities.Conversation;
  9import eu.siacs.conversations.entities.Message;
 10import eu.siacs.conversations.services.ImageProvider;
 11import eu.siacs.conversations.ui.ConversationActivity;
 12import eu.siacs.conversations.utils.UIHelper;
 13import eu.siacs.conversations.xmpp.jingle.JingleConnection;
 14import android.content.Context;
 15import android.content.Intent;
 16import android.content.SharedPreferences;
 17import android.graphics.Bitmap;
 18import android.graphics.Typeface;
 19import android.preference.PreferenceManager;
 20import android.util.DisplayMetrics;
 21import android.view.View;
 22import android.view.ViewGroup;
 23import android.view.View.OnClickListener;
 24import android.view.View.OnLongClickListener;
 25import android.widget.ArrayAdapter;
 26import android.widget.Button;
 27import android.widget.ImageView;
 28import android.widget.LinearLayout;
 29import android.widget.TextView;
 30import android.widget.Toast;
 31
 32public class MessageAdapter extends ArrayAdapter<Message> {
 33
 34	private static final int SENT = 0;
 35	private static final int RECIEVED = 1;
 36	private static final int STATUS = 2;
 37
 38	private ConversationActivity activity;
 39
 40	private Bitmap selfBitmap2;
 41
 42	private BitmapCache mBitmapCache = new BitmapCache();
 43	private DisplayMetrics metrics;
 44
 45	private OnContactPictureClicked mOnContactPictureClickedListener;
 46
 47	public MessageAdapter(ConversationActivity activity, List<Message> messages) {
 48		super(activity, 0, messages);
 49		this.activity = activity;
 50		metrics = getContext().getResources().getDisplayMetrics();
 51	}
 52
 53	private Bitmap getSelfBitmap() {
 54		if (this.selfBitmap2 == null) {
 55
 56			if (getCount() > 0) {
 57				SharedPreferences preferences = PreferenceManager
 58						.getDefaultSharedPreferences(getContext());
 59				boolean showPhoneSelfContactPicture = preferences.getBoolean(
 60						"show_phone_selfcontact_picture", true);
 61
 62				this.selfBitmap2 = UIHelper.getSelfContactPicture(getItem(0)
 63						.getConversation().getAccount(), 48,
 64						showPhoneSelfContactPicture, getContext());
 65			}
 66		}
 67		return this.selfBitmap2;
 68	}
 69
 70	public void setOnContactPictureClicked(OnContactPictureClicked listener) {
 71		this.mOnContactPictureClickedListener = listener;
 72	}
 73
 74	@Override
 75	public int getViewTypeCount() {
 76		return 3;
 77	}
 78
 79	@Override
 80	public int getItemViewType(int position) {
 81		if (getItem(position).getType() == Message.TYPE_STATUS) {
 82			return STATUS;
 83		} else if (getItem(position).getStatus() <= Message.STATUS_RECIEVED) {
 84			return RECIEVED;
 85		} else {
 86			return SENT;
 87		}
 88	}
 89
 90	private void displayStatus(ViewHolder viewHolder, Message message) {
 91		String filesize = null;
 92		String info = null;
 93		boolean error = false;
 94		boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI
 95				&& message.getStatus() <= Message.STATUS_RECIEVED;
 96		if (message.getType() == Message.TYPE_IMAGE) {
 97			String[] fileParams = message.getBody().split(",");
 98			try {
 99				long size = Long.parseLong(fileParams[0]);
100				filesize = size / 1024 + " KB";
101			} catch (NumberFormatException e) {
102				filesize = "0 KB";
103			}
104		}
105		switch (message.getStatus()) {
106		case Message.STATUS_WAITING:
107			info = getContext().getString(R.string.waiting);
108			break;
109		case Message.STATUS_UNSEND:
110			info = getContext().getString(R.string.sending);
111			break;
112		case Message.STATUS_OFFERED:
113			info = getContext().getString(R.string.offering);
114			break;
115		case Message.STATUS_SEND_FAILED:
116			info = getContext().getString(R.string.send_failed);
117			error = true;
118			break;
119		case Message.STATUS_SEND_REJECTED:
120			info = getContext().getString(R.string.send_rejected);
121			error = true;
122			break;
123		case Message.STATUS_RECEPTION_FAILED:
124			info = getContext().getString(R.string.reception_failed);
125			error = true;
126		default:
127			if (multiReceived) {
128				Contact contact = message.getContact();
129				if (contact != null) {
130					info = contact.getDisplayName();
131				} else {
132					info = message.getCounterpart();
133				}
134			}
135			break;
136		}
137		if (error) {
138			viewHolder.time.setTextColor(0xFFe92727);
139		} else {
140			viewHolder.time.setTextColor(activity.getSecondaryTextColor());
141		}
142		if (message.getEncryption() == Message.ENCRYPTION_NONE) {
143			viewHolder.indicator.setVisibility(View.GONE);
144		} else {
145			viewHolder.indicator.setVisibility(View.VISIBLE);
146		}
147
148		String formatedTime = UIHelper.readableTimeDifference(getContext(),
149				message.getTimeSent());
150		if (message.getStatus() <= Message.STATUS_RECIEVED) {
151			if ((filesize != null) && (info != null)) {
152				viewHolder.time.setText(filesize + " \u00B7 " + info);
153			} else if ((filesize == null) && (info != null)) {
154				viewHolder.time.setText(formatedTime + " \u00B7 " + info);
155			} else if ((filesize != null) && (info == null)) {
156				viewHolder.time.setText(formatedTime + " \u00B7 " + filesize);
157			} else {
158				viewHolder.time.setText(formatedTime);
159			}
160		} else {
161			if ((filesize != null) && (info != null)) {
162				viewHolder.time.setText(filesize + " \u00B7 " + info);
163			} else if ((filesize == null) && (info != null)) {
164				if (error) {
165					viewHolder.time.setText(info + " \u00B7 " + formatedTime);
166				} else {
167					viewHolder.time.setText(info);
168				}
169			} else if ((filesize != null) && (info == null)) {
170				viewHolder.time.setText(filesize + " \u00B7 " + formatedTime);
171			} else {
172				viewHolder.time.setText(formatedTime);
173			}
174		}
175	}
176
177	private void displayInfoMessage(ViewHolder viewHolder, int r) {
178		if (viewHolder.download_button != null) {
179			viewHolder.download_button.setVisibility(View.GONE);
180		}
181		viewHolder.image.setVisibility(View.GONE);
182		viewHolder.messageBody.setVisibility(View.VISIBLE);
183		viewHolder.messageBody.setText(getContext().getString(r));
184		viewHolder.messageBody.setTextColor(0xff33B5E5);
185		viewHolder.messageBody.setTypeface(null, Typeface.ITALIC);
186		viewHolder.messageBody.setTextIsSelectable(false);
187	}
188
189	private void displayDecryptionFailed(ViewHolder viewHolder) {
190		if (viewHolder.download_button != null) {
191			viewHolder.download_button.setVisibility(View.GONE);
192		}
193		viewHolder.image.setVisibility(View.GONE);
194		viewHolder.messageBody.setVisibility(View.VISIBLE);
195		viewHolder.messageBody.setText(getContext().getString(
196				R.string.decryption_failed));
197		viewHolder.messageBody.setTextColor(0xFFe92727);
198		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
199		viewHolder.messageBody.setTextIsSelectable(false);
200	}
201
202	private void displayTextMessage(ViewHolder viewHolder, String text) {
203		if (viewHolder.download_button != null) {
204			viewHolder.download_button.setVisibility(View.GONE);
205		}
206		viewHolder.image.setVisibility(View.GONE);
207		viewHolder.messageBody.setVisibility(View.VISIBLE);
208		if (text != null) {
209			viewHolder.messageBody.setText(text.trim());
210		} else {
211			viewHolder.messageBody.setText("");
212		}
213		viewHolder.messageBody.setTextColor(activity.getPrimaryTextColor());
214		viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
215		viewHolder.messageBody.setTextIsSelectable(true);
216	}
217
218	private void displayImageMessage(ViewHolder viewHolder,
219			final Message message) {
220		if (viewHolder.download_button != null) {
221			viewHolder.download_button.setVisibility(View.GONE);
222		}
223		viewHolder.messageBody.setVisibility(View.GONE);
224		viewHolder.image.setVisibility(View.VISIBLE);
225		String[] fileParams = message.getBody().split(",");
226		if (fileParams.length == 3) {
227			double target = metrics.density * 288;
228			int w = Integer.parseInt(fileParams[1]);
229			int h = Integer.parseInt(fileParams[2]);
230			int scalledW;
231			int scalledH;
232			if (w <= h) {
233				scalledW = (int) (w / ((double) h / target));
234				scalledH = (int) target;
235			} else {
236				scalledW = (int) target;
237				scalledH = (int) (h / ((double) w / target));
238			}
239			viewHolder.image.setLayoutParams(new LinearLayout.LayoutParams(
240					scalledW, scalledH));
241		}
242		activity.loadBitmap(message, viewHolder.image);
243		viewHolder.image.setOnClickListener(new OnClickListener() {
244
245			@Override
246			public void onClick(View v) {
247				Intent intent = new Intent(Intent.ACTION_VIEW);
248				intent.setDataAndType(ImageProvider.getContentUri(message),
249						"image/*");
250				getContext().startActivity(intent);
251			}
252		});
253		viewHolder.image.setOnLongClickListener(new OnLongClickListener() {
254
255			@Override
256			public boolean onLongClick(View v) {
257				Intent shareIntent = new Intent();
258				shareIntent.setAction(Intent.ACTION_SEND);
259				shareIntent.putExtra(Intent.EXTRA_STREAM,
260						ImageProvider.getContentUri(message));
261				shareIntent.setType("image/webp");
262				getContext().startActivity(
263						Intent.createChooser(shareIntent,
264								getContext().getText(R.string.share_with)));
265				return true;
266			}
267		});
268	}
269
270	@Override
271	public View getView(int position, View view, ViewGroup parent) {
272		final Message item = getItem(position);
273		int type = getItemViewType(position);
274		ViewHolder viewHolder;
275		if (view == null) {
276			viewHolder = new ViewHolder();
277			switch (type) {
278			case SENT:
279				view = (View) activity.getLayoutInflater().inflate(
280						R.layout.message_sent, parent,false);
281				viewHolder.message_box = (LinearLayout) view
282						.findViewById(R.id.message_box);
283				viewHolder.contact_picture = (ImageView) view
284						.findViewById(R.id.message_photo);
285				viewHolder.contact_picture.setImageBitmap(getSelfBitmap());
286				viewHolder.indicator = (ImageView) view
287						.findViewById(R.id.security_indicator);
288				viewHolder.image = (ImageView) view
289						.findViewById(R.id.message_image);
290				viewHolder.messageBody = (TextView) view
291						.findViewById(R.id.message_body);
292				viewHolder.time = (TextView) view
293						.findViewById(R.id.message_time);
294				view.setTag(viewHolder);
295				break;
296			case RECIEVED:
297				view = (View) activity.getLayoutInflater().inflate(
298						R.layout.message_recieved, parent,false);
299				viewHolder.message_box = (LinearLayout) view
300						.findViewById(R.id.message_box);
301				viewHolder.contact_picture = (ImageView) view
302						.findViewById(R.id.message_photo);
303
304				viewHolder.download_button = (Button) view
305						.findViewById(R.id.download_button);
306
307				if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
308
309					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
310							item.getConversation().getContact(), getContext()));
311
312				}
313				viewHolder.indicator = (ImageView) view
314						.findViewById(R.id.security_indicator);
315				viewHolder.image = (ImageView) view
316						.findViewById(R.id.message_image);
317				viewHolder.messageBody = (TextView) view
318						.findViewById(R.id.message_body);
319				viewHolder.time = (TextView) view
320						.findViewById(R.id.message_time);
321				view.setTag(viewHolder);
322				break;
323			case STATUS:
324				view = (View) activity.getLayoutInflater().inflate(
325						R.layout.message_status, parent,false);
326				viewHolder.contact_picture = (ImageView) view
327						.findViewById(R.id.message_photo);
328				if (item.getConversation().getMode() == Conversation.MODE_SINGLE) {
329
330					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
331							item.getConversation().getContact(), getContext()));
332					viewHolder.contact_picture.setAlpha(128);
333					viewHolder.contact_picture
334							.setOnClickListener(new OnClickListener() {
335
336								@Override
337								public void onClick(View v) {
338									String name = item.getConversation()
339											.getName(true);
340									String read = getContext()
341											.getString(
342													R.string.contact_has_read_up_to_this_point,
343													name);
344									Toast.makeText(getContext(), read,
345											Toast.LENGTH_SHORT).show();
346								}
347							});
348
349				}
350				break;
351			default:
352				viewHolder = null;
353				break;
354			}
355		} else {
356			viewHolder = (ViewHolder) view.getTag();
357		}
358
359		if (type == STATUS) {
360			return view;
361		}
362
363		if (type == RECIEVED) {
364			if (item.getConversation().getMode() == Conversation.MODE_MULTI) {
365				Contact contact = item.getContact();
366				if (contact != null) {
367					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
368							contact, getContext()));
369				} else {
370					viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(
371							item.getCounterpart(), getContext()));
372				}
373				viewHolder.contact_picture
374						.setOnClickListener(new OnClickListener() {
375
376							@Override
377							public void onClick(View v) {
378								if (MessageAdapter.this.mOnContactPictureClickedListener != null) {
379									MessageAdapter.this.mOnContactPictureClickedListener
380											.onContactPictureClicked(item);
381									;
382								}
383
384							}
385						});
386			}
387		}
388
389		if (item.getType() == Message.TYPE_IMAGE) {
390			if (item.getStatus() == Message.STATUS_RECIEVING) {
391				displayInfoMessage(viewHolder, R.string.receiving_image);
392			} else if (item.getStatus() == Message.STATUS_RECEIVED_OFFER) {
393				viewHolder.image.setVisibility(View.GONE);
394				viewHolder.messageBody.setVisibility(View.GONE);
395				viewHolder.download_button.setVisibility(View.VISIBLE);
396				viewHolder.download_button
397						.setOnClickListener(new OnClickListener() {
398
399							@Override
400							public void onClick(View v) {
401								JingleConnection connection = item
402										.getJingleConnection();
403								if (connection != null) {
404									connection.accept();
405								}
406							}
407						});
408			} else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED)
409					|| (item.getEncryption() == Message.ENCRYPTION_NONE)
410					|| (item.getEncryption() == Message.ENCRYPTION_OTR)) {
411				displayImageMessage(viewHolder, item);
412			} else if (item.getEncryption() == Message.ENCRYPTION_PGP) {
413				displayInfoMessage(viewHolder, R.string.encrypted_message);
414			} else {
415				displayDecryptionFailed(viewHolder);
416			}
417		} else {
418			if (item.getEncryption() == Message.ENCRYPTION_PGP) {
419				if (activity.hasPgp()) {
420					displayInfoMessage(viewHolder, R.string.encrypted_message);
421				} else {
422					displayInfoMessage(viewHolder,
423							R.string.install_openkeychain);
424					viewHolder.message_box
425							.setOnClickListener(new OnClickListener() {
426
427								@Override
428								public void onClick(View v) {
429									activity.showInstallPgpDialog();
430								}
431							});
432				}
433			} else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) {
434				displayDecryptionFailed(viewHolder);
435			} else {
436				displayTextMessage(viewHolder, item.getBody());
437			}
438		}
439
440		displayStatus(viewHolder, item);
441
442		return view;
443	}
444
445	private static class ViewHolder {
446
447		protected LinearLayout message_box;
448		protected Button download_button;
449		protected ImageView image;
450		protected ImageView indicator;
451		protected TextView time;
452		protected TextView messageBody;
453		protected ImageView contact_picture;
454
455	}
456
457	private class BitmapCache {
458		private HashMap<String, Bitmap> contactBitmaps = new HashMap<String, Bitmap>();
459		private HashMap<String, Bitmap> unknownBitmaps = new HashMap<String, Bitmap>();
460
461		public Bitmap get(Contact contact, Context context) {
462			if (contactBitmaps.containsKey(contact.getJid())) {
463				return contactBitmaps.get(contact.getJid());
464			} else {
465				Bitmap bm = UIHelper.getContactPicture(contact, 48, context,
466						false);
467				contactBitmaps.put(contact.getJid(), bm);
468				return bm;
469			}
470		}
471
472		public Bitmap get(String name, Context context) {
473			if (unknownBitmaps.containsKey(name)) {
474				return unknownBitmaps.get(name);
475			} else {
476				Bitmap bm = UIHelper
477						.getContactPicture(name, 48, context, false);
478				unknownBitmaps.put(name, bm);
479				return bm;
480			}
481		}
482	}
483
484	public interface OnContactPictureClicked {
485		public void onContactPictureClicked(Message message);
486	}
487}