package akechi.projectl.async; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.support.v4.util.LruCache; import android.support.v4.util.Pair; import android.text.BoringLayout; import android.text.Spannable; import android.text.Spanned; import android.text.style.ImageSpan; import android.text.style.URLSpan; import android.util.DisplayMetrics; import android.util.Log; import android.widget.TextView; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpRequestFactory; import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpTransport; import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import java.io.IOException; import java.util.Collections; import java.util.WeakHashMap; public class InlineImageHandler extends AsyncTask<URLSpan, Void, Iterable<Pair<URLSpan, Bitmap>>> { public InlineImageHandler(TextView view) { this.view= view; this.execute(this.view.getUrls()); } @Override protected void onPostExecute(Iterable<Pair<URLSpan, Bitmap>> pairs) { if(!(this.view.getText() instanceof Spannable)) { return; } for(final Pair<URLSpan, Bitmap> pair : pairs) { final URLSpan url= pair.first; final Bitmap bitmap= pair.second; if(url == null || bitmap == null) { continue; } final Spannable text= (Spannable)this.view.getText(); final int start= text.getSpanStart(url); final int end= text.getSpanEnd(url); if(start == -1 || end == -1) { continue; } final ImageSpan imageSpan; if(bitmap.getWidth() <= this.view.getWidth()) { imageSpan= new ImageSpan(this.view.getContext(), bitmap); } else { final Matrix mat= new Matrix(); final float scale= this.view.getWidth() / (float)bitmap.getWidth(); mat.postScale(scale, scale); final Bitmap scaled= Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true); imageSpan= new ImageSpan(this.view.getContext(), scaled); } text.setSpan(imageSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } @Override protected Iterable<Pair<URLSpan, Bitmap>> doInBackground(URLSpan... params) { if(params.length == 0) { return Collections.emptyList(); } final ImmutableList.Builder<Pair<URLSpan, Bitmap>> builder= ImmutableList.builder(); for(final URLSpan span : params) { final GenericUrl url= new GenericUrl(span.getURL()); try { if(!this.isImageType(url)) { continue; } final Bitmap bitmap= this.loadBitmap(url); bitmapCache.put(span.getURL(), (bitmap != null) ? bitmap : BitmapFactory.decodeResource(this.view.getContext().getResources(), android.R.drawable.ic_delete) ); builder.add(Pair.create(span, bitmap)); } catch(IOException e) { Log.e("InlineImageHandler", "url: " + url); Log.e("InlineImageHandler", "Error", e); return Collections.emptyList(); } } return builder.build(); } private Bitmap loadBitmap(GenericUrl url) { { final Bitmap bitmap= bitmapCache.get(url.toString()); if(bitmap != null) { return bitmap; } } HttpResponse response= null; try { final HttpRequestFactory factory= transport.createRequestFactory(); final HttpRequest request= factory.buildGetRequest(url); response= request.execute(); return BitmapFactory.decodeStream(response.getContent()); } catch(IOException e) { Log.e("InlineImageHandler", "Network error", e); return null; } finally { if(response != null) { try { response.disconnect(); } catch(IOException e) { Log.e("InlineImageHandler", "Error closing", e); } } } } private boolean isImageType(GenericUrl url) throws IOException { { final String contentType= mimeCache.get(url.toString()); if(contentType != null) { return contentType.startsWith("image"); } } final HttpRequestFactory factory= transport.createRequestFactory(); HttpResponse response= null; try { final HttpRequest request= factory.buildHeadRequest(url); response= request.execute(); final String contentType= Strings.nullToEmpty(response.getHeaders().getContentType()); mimeCache.put(url.toString(), contentType); return contentType.startsWith("image"); } finally { if(response != null) { response.disconnect(); } } } private static final HttpTransport transport= AndroidHttp.newCompatibleTransport(); private static final LruCache<String, String> mimeCache= new LruCache<>(1024); private static final LruCache<String, Bitmap> bitmapCache= new LruCache<String, Bitmap>(8 * 1024 * 1024){ @Override protected int sizeOf(String key, Bitmap value) { if(value == null) { return 1; } return value.getRowBytes() * value.getHeight(); } }; private final TextView view; }