2011-12-20 10:20:44 -08:00
|
|
|
/**
|
|
|
|
* Copyright (C) 2011 Whisper Systems
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
package org.thoughtcrime.securesms.mms;
|
|
|
|
|
2013-04-26 11:23:43 -07:00
|
|
|
import android.content.Context;
|
2014-12-17 11:47:19 -08:00
|
|
|
import android.graphics.Bitmap;
|
2013-04-26 11:23:43 -07:00
|
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
import android.net.Uri;
|
|
|
|
import android.util.Log;
|
2015-01-29 20:37:01 -10:00
|
|
|
import android.util.Pair;
|
2013-04-26 11:23:43 -07:00
|
|
|
|
|
|
|
import org.thoughtcrime.securesms.R;
|
|
|
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
2013-05-21 10:32:48 -07:00
|
|
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
2013-05-06 12:22:03 -07:00
|
|
|
import org.thoughtcrime.securesms.util.LRUCache;
|
2015-01-29 20:37:01 -10:00
|
|
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
2014-12-30 01:36:51 -08:00
|
|
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
2014-11-03 15:16:04 -08:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2013-04-26 11:23:43 -07:00
|
|
|
|
2011-12-20 10:20:44 -08:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.lang.ref.SoftReference;
|
2013-04-26 11:23:43 -07:00
|
|
|
import java.lang.ref.WeakReference;
|
2013-05-06 12:22:03 -07:00
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Map;
|
2015-01-29 20:37:01 -10:00
|
|
|
import java.util.concurrent.Callable;
|
2011-12-20 10:20:44 -08:00
|
|
|
|
|
|
|
import ws.com.google.android.mms.ContentType;
|
|
|
|
import ws.com.google.android.mms.pdu.PduPart;
|
|
|
|
|
|
|
|
public class ImageSlide extends Slide {
|
2014-12-17 11:47:19 -08:00
|
|
|
private static final String TAG = ImageSlide.class.getSimpleName();
|
2011-12-20 10:20:44 -08:00
|
|
|
|
|
|
|
private static final int MAX_CACHE_SIZE = 10;
|
2013-09-08 18:19:05 -07:00
|
|
|
private static final Map<Uri, SoftReference<Drawable>> thumbnailCache =
|
|
|
|
Collections.synchronizedMap(new LRUCache<Uri, SoftReference<Drawable>>(MAX_CACHE_SIZE));
|
2011-12-20 10:20:44 -08:00
|
|
|
|
|
|
|
public ImageSlide(Context context, MasterSecret masterSecret, PduPart part) {
|
|
|
|
super(context, masterSecret, part);
|
|
|
|
}
|
|
|
|
|
2014-12-22 16:25:51 -08:00
|
|
|
public ImageSlide(Context context, Uri uri) throws IOException, BitmapDecodingException {
|
|
|
|
super(context, constructPartFromUri(uri));
|
2011-12-20 10:20:44 -08:00
|
|
|
}
|
2014-06-28 14:06:15 -07:00
|
|
|
|
2011-12-20 10:20:44 -08:00
|
|
|
@Override
|
2015-01-29 20:37:01 -10:00
|
|
|
public ListenableFutureTask<Pair<Drawable,Boolean>> getThumbnail(Context context) {
|
|
|
|
if (getPart().isPendingPush()) {
|
|
|
|
return new ListenableFutureTask<>(new Pair<>(context.getResources().getDrawable(R.drawable.stat_sys_download), true));
|
2011-12-20 10:20:44 -08:00
|
|
|
}
|
2015-01-18 16:11:30 -10:00
|
|
|
|
2013-09-08 18:19:05 -07:00
|
|
|
Drawable thumbnail = getCachedThumbnail();
|
2013-04-26 11:23:43 -07:00
|
|
|
if (thumbnail != null) {
|
2015-01-29 20:37:01 -10:00
|
|
|
Log.w(TAG, "getThumbnail() returning cached thumbnail");
|
|
|
|
return new ListenableFutureTask<>(new Pair<>(thumbnail, true));
|
2013-04-26 11:23:43 -07:00
|
|
|
}
|
|
|
|
|
2015-01-29 20:37:01 -10:00
|
|
|
Log.w(TAG, "getThumbnail() resolving thumbnail, as it wasn't cached");
|
|
|
|
return resolveThumbnail(context);
|
|
|
|
}
|
2013-04-26 11:23:43 -07:00
|
|
|
|
2015-01-29 20:37:01 -10:00
|
|
|
private ListenableFutureTask<Pair<Drawable,Boolean>> resolveThumbnail(Context context) {
|
|
|
|
final WeakReference<Context> weakContext = new WeakReference<>(context);
|
2013-06-21 11:56:59 -07:00
|
|
|
|
2015-01-29 20:37:01 -10:00
|
|
|
Callable<Pair<Drawable,Boolean>> slideCallable = new Callable<Pair<Drawable, Boolean>>() {
|
2013-04-26 11:23:43 -07:00
|
|
|
@Override
|
2015-01-29 20:37:01 -10:00
|
|
|
public Pair<Drawable, Boolean> call() throws Exception {
|
2015-01-06 12:48:15 +01:00
|
|
|
final Context context = weakContext.get();
|
|
|
|
if (context == null) {
|
|
|
|
Log.w(TAG, "context SoftReference was null, leaving");
|
2015-01-29 20:37:01 -10:00
|
|
|
return null;
|
2015-01-06 12:48:15 +01:00
|
|
|
}
|
|
|
|
|
2015-01-29 20:37:01 -10:00
|
|
|
try {
|
|
|
|
final long startDecode = System.currentTimeMillis();
|
|
|
|
final Bitmap thumbnailBitmap = MediaUtil.getOrGenerateThumbnail(context, masterSecret, part);
|
|
|
|
final Drawable thumbnail = new BitmapDrawable(context.getResources(), thumbnailBitmap);
|
|
|
|
Log.w(TAG, "thumbnail decode/generate time: " + (System.currentTimeMillis() - startDecode) + "ms");
|
|
|
|
|
|
|
|
thumbnailCache.put(part.getDataUri(), new SoftReference<>(thumbnail));
|
|
|
|
return new Pair<>(thumbnail, false);
|
|
|
|
} catch (IOException | BitmapDecodingException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
return new Pair<>(context.getResources().getDrawable(R.drawable.ic_missing_thumbnail_picture), false);
|
2013-04-26 11:23:43 -07:00
|
|
|
}
|
|
|
|
}
|
2015-01-29 20:37:01 -10:00
|
|
|
};
|
|
|
|
ListenableFutureTask<Pair<Drawable,Boolean>> futureTask = new ListenableFutureTask<>(slideCallable);
|
|
|
|
MmsDatabase.slideResolver.execute(futureTask);
|
|
|
|
return futureTask;
|
2011-12-20 10:20:44 -08:00
|
|
|
}
|
2013-04-26 11:23:43 -07:00
|
|
|
|
2013-09-08 18:19:05 -07:00
|
|
|
private Drawable getCachedThumbnail() {
|
2013-04-26 11:23:43 -07:00
|
|
|
synchronized (thumbnailCache) {
|
2013-09-08 18:19:05 -07:00
|
|
|
SoftReference<Drawable> bitmapReference = thumbnailCache.get(part.getDataUri());
|
2013-04-26 11:23:43 -07:00
|
|
|
Log.w("ImageSlide", "Got soft reference: " + bitmapReference);
|
|
|
|
|
|
|
|
if (bitmapReference != null) {
|
2013-09-08 18:19:05 -07:00
|
|
|
Drawable bitmap = bitmapReference.get();
|
2013-04-26 11:23:43 -07:00
|
|
|
Log.w("ImageSlide", "Got cached bitmap: " + bitmap);
|
|
|
|
if (bitmap != null) return bitmap;
|
|
|
|
else thumbnailCache.remove(part.getDataUri());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2011-12-20 10:20:44 -08:00
|
|
|
@Override
|
2013-04-26 11:23:43 -07:00
|
|
|
public boolean hasImage() {
|
2011-12-20 10:20:44 -08:00
|
|
|
return true;
|
|
|
|
}
|
2014-06-28 14:06:15 -07:00
|
|
|
|
2014-12-22 16:25:51 -08:00
|
|
|
private static PduPart constructPartFromUri(Uri uri)
|
2013-05-21 10:32:48 -07:00
|
|
|
throws IOException, BitmapDecodingException
|
|
|
|
{
|
2011-12-20 10:20:44 -08:00
|
|
|
PduPart part = new PduPart();
|
2013-04-26 11:23:43 -07:00
|
|
|
|
2011-12-20 10:20:44 -08:00
|
|
|
part.setDataUri(uri);
|
|
|
|
part.setContentType(ContentType.IMAGE_JPEG.getBytes());
|
|
|
|
part.setContentId((System.currentTimeMillis()+"").getBytes());
|
|
|
|
part.setName(("Image" + System.currentTimeMillis()).getBytes());
|
|
|
|
|
|
|
|
return part;
|
|
|
|
}
|
|
|
|
}
|