Added back bitmap handling classes & methods
This commit is contained in:
parent
53d83a49f8
commit
d2f3ed7e43
2 changed files with 204 additions and 5 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
GroupChatFragment.java
|
||||
ChatEventsAdapter.java
|
||||
Copyright (C) 2017 Belledonne Communications, Grenoble, France
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
|
@ -20,12 +20,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
package org.linphone.chat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.ExifInterface;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import org.linphone.LinphoneManager;
|
||||
|
@ -39,21 +54,31 @@ import org.linphone.core.Address;
|
|||
import org.linphone.core.ChatMessage;
|
||||
import org.linphone.core.Core;
|
||||
import org.linphone.core.EventLog;
|
||||
import org.linphone.mediastream.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
|
||||
|
||||
public class ChatEventsAdapter extends BaseAdapter {
|
||||
private Context mContext;
|
||||
GroupChatFragment mFragment;
|
||||
private List<EventLog> mHistory;
|
||||
private List<LinphoneContact> mParticipants;
|
||||
private LayoutInflater mLayoutInflater;
|
||||
private Bitmap mDefaultBitmap;
|
||||
|
||||
public ChatEventsAdapter(Context context, LayoutInflater inflater, EventLog[] history, List<LinphoneContact> participants) {
|
||||
public ChatEventsAdapter(Context context, GroupChatFragment fragment, LayoutInflater inflater, EventLog[] history, List<LinphoneContact> participants) {
|
||||
mContext = context;
|
||||
mFragment = fragment;
|
||||
mLayoutInflater = inflater;
|
||||
mHistory = Arrays.asList(history);
|
||||
mParticipants = participants;
|
||||
|
@ -288,4 +313,176 @@ public class ChatEventsAdapter extends BaseAdapter {
|
|||
|
||||
return Compatibility.fromHtml(text);
|
||||
}
|
||||
|
||||
public void loadBitmap(String path, ImageView imageView) {
|
||||
if (cancelPotentialWork(path, imageView)) {
|
||||
if (LinphoneUtils.isExtensionImage(path)) {
|
||||
mDefaultBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_attachment_over);
|
||||
} else {
|
||||
mDefaultBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.chat_attachment);
|
||||
}
|
||||
|
||||
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
|
||||
final AsyncBitmap asyncBitmap = new AsyncBitmap(mContext.getResources(), mDefaultBitmap, task);
|
||||
imageView.setImageDrawable(asyncBitmap);
|
||||
task.execute(path);
|
||||
}
|
||||
}
|
||||
|
||||
private class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
|
||||
private static final int SIZE_SMALL = 500;
|
||||
private final WeakReference<ImageView> imageViewReference;
|
||||
public String path;
|
||||
|
||||
public BitmapWorkerTask(ImageView imageView) {
|
||||
path = null;
|
||||
// Use a WeakReference to ensure the ImageView can be garbage collected
|
||||
imageViewReference = new WeakReference<ImageView>(imageView);
|
||||
}
|
||||
|
||||
// Decode image in background.
|
||||
@Override
|
||||
protected Bitmap doInBackground(String... params) {
|
||||
path = params[0];
|
||||
Bitmap bm = null;
|
||||
Bitmap thumbnail = null;
|
||||
if(LinphoneUtils.isExtensionImage(path)) {
|
||||
if (path.startsWith("content")) {
|
||||
try {
|
||||
bm = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), Uri.parse(path));
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.e(e);
|
||||
} catch (IOException e) {
|
||||
Log.e(e);
|
||||
}
|
||||
} else {
|
||||
bm = BitmapFactory.decodeFile(path);
|
||||
}
|
||||
|
||||
// Rotate the bitmap if possible/needed, using EXIF data
|
||||
try {
|
||||
Bitmap bm_tmp;
|
||||
ExifInterface exif = new ExifInterface(path);
|
||||
int pictureOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
|
||||
Matrix matrix = new Matrix();
|
||||
if (pictureOrientation == 6) {
|
||||
matrix.postRotate(90);
|
||||
} else if (pictureOrientation == 3) {
|
||||
matrix.postRotate(180);
|
||||
} else if (pictureOrientation == 8) {
|
||||
matrix.postRotate(270);
|
||||
}
|
||||
bm_tmp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
|
||||
if (bm_tmp != bm) {
|
||||
bm.recycle();
|
||||
bm = bm_tmp;
|
||||
} else {
|
||||
bm_tmp = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
}
|
||||
|
||||
if (bm != null) {
|
||||
thumbnail = ThumbnailUtils.extractThumbnail(bm, SIZE_SMALL, SIZE_SMALL);
|
||||
bm.recycle();
|
||||
}
|
||||
return thumbnail;
|
||||
}else
|
||||
return mDefaultBitmap;
|
||||
}
|
||||
|
||||
// Once complete, see if ImageView is still around and set bitmap.
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
if (isCancelled()) {
|
||||
bitmap = null;
|
||||
}
|
||||
if (imageViewReference != null && bitmap != null) {
|
||||
final ImageView imageView = imageViewReference.get();
|
||||
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
||||
if (this == bitmapWorkerTask && imageView != null) {
|
||||
imageView.setImageBitmap(bitmap);
|
||||
|
||||
//Force scroll too bottom with setSelection() after image loaded and last messages
|
||||
mFragment.scrollToBottom();
|
||||
|
||||
imageView.setTag(path);
|
||||
imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
File file = null;
|
||||
Uri contentUri = null;
|
||||
String imageUri = (String)v.getTag();
|
||||
if (imageUri.startsWith("file://")) {
|
||||
imageUri = imageUri.substring("file://".length());
|
||||
file = new File(imageUri);
|
||||
contentUri = FileProvider.getUriForFile(mContext, "org.linphone.provider", file);
|
||||
} else if (imageUri.startsWith("content://")) {
|
||||
contentUri = Uri.parse(imageUri);
|
||||
} else {
|
||||
file = new File(imageUri);
|
||||
contentUri = FileProvider.getUriForFile(mContext, "org.linphone.provider", file);
|
||||
}
|
||||
String type = null;
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(contentUri.toString());
|
||||
if (extension != null) {
|
||||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
if(type != null) {
|
||||
intent.setDataAndType(contentUri, type);
|
||||
}else {
|
||||
intent.setDataAndType(contentUri, "*/*");
|
||||
}
|
||||
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncBitmap extends BitmapDrawable {
|
||||
private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
|
||||
|
||||
public AsyncBitmap(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
|
||||
super(res, bitmap);
|
||||
bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
|
||||
}
|
||||
|
||||
public BitmapWorkerTask getBitmapWorkerTask() {
|
||||
return bitmapWorkerTaskReference.get();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean cancelPotentialWork(String path, ImageView imageView) {
|
||||
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
|
||||
|
||||
if (bitmapWorkerTask != null) {
|
||||
final String bitmapData = bitmapWorkerTask.path;
|
||||
// If bitmapData is not yet set or it differs from the new data
|
||||
if (bitmapData == null || bitmapData != path) {
|
||||
// Cancel previous task
|
||||
bitmapWorkerTask.cancel(true);
|
||||
} else {
|
||||
// The same work is already in progress
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// No task associated with the ImageView, or an existing task was cancelled
|
||||
return true;
|
||||
}
|
||||
|
||||
private BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
|
||||
if (imageView != null) {
|
||||
final Drawable drawable = imageView.getDrawable();
|
||||
if (drawable instanceof AsyncBitmap) {
|
||||
final AsyncBitmap asyncDrawable = (AsyncBitmap) drawable;
|
||||
return asyncDrawable.getBitmapWorkerTask();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -456,7 +456,7 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con
|
|||
|
||||
private void displayChatRoomHistory() {
|
||||
if (mChatRoom == null) return;
|
||||
mMessagesAdapter = new ChatEventsAdapter(getActivity(), mInflater, mChatRoom.getHistoryEvents(0), mParticipants);
|
||||
mMessagesAdapter = new ChatEventsAdapter(getActivity(), this, mInflater, mChatRoom.getHistoryEvents(0), mParticipants);
|
||||
mChatEventsList.setAdapter(mMessagesAdapter);
|
||||
}
|
||||
|
||||
|
@ -574,8 +574,10 @@ public class GroupChatFragment extends Fragment implements ChatRoomListener, Con
|
|||
mMessageTextToSend.setText("");
|
||||
}
|
||||
|
||||
private void scrollToBottom() {
|
||||
mChatEventsList.setSelection(mMessagesAdapter.getCount() - 1);
|
||||
public void scrollToBottom() {
|
||||
if (((mChatEventsList.getLastVisiblePosition() >= (mMessagesAdapter.getCount() - 1)) && (mChatEventsList.getFirstVisiblePosition() <= (mMessagesAdapter.getCount() - 1)))) {
|
||||
mChatEventsList.setSelection(mMessagesAdapter.getCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue