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}