package akechi.projectl.component;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
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 java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import akechi.projectl.AppContext;
import akechi.projectl.R;
public class CachedImageView
extends ImageView
{
public CachedImageView(Context context) {
super(context);
}
public CachedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CachedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setImageURI(Uri uri) {
if(uri.equals(this.shownUri))
{
return;
}
this.shownUri= uri;
final String scheme= uri.getScheme();
if("http".equals(scheme) || "https".equals(scheme))
{
this.setVisibility(View.INVISIBLE);
final AppContext appContext= (AppContext)this.getContext().getApplicationContext();
if(appContext.isIconCacheEnabled())
{
new CacheableImageLoader(this, uri).executeOnExecutor(executor);
}
else
{
new NoCacheImageLoader(this, uri).executeOnExecutor(executor);
}
}
else
{
super.setImageURI(uri);
}
}
private static final class CacheableImageLoader
extends AsyncTask<Void, Void, Bitmap>
{
public CacheableImageLoader(ImageView view, Uri uri)
{
this.view= view;
this.uri= uri;
}
@Override
protected Bitmap doInBackground(Void... params) {
final URL url;
try{
url= new URL(this.uri.toString());
}
catch(MalformedURLException e)
{
return null;
}
final AppContext appContext= (AppContext)this.view.getContext().getApplicationContext();
final File cacheDir= appContext.getIconCacheDir();
if(!cacheDir.isDirectory())
{
if(!cacheDir.mkdirs())
{
throw new RuntimeException("Couldn't create directories " + cacheDir.getAbsolutePath());
}
}
final File cacheFile= new File(cacheDir, escape(url));
if(cacheFile.exists())
{
try
{
return BitmapFactory.decodeFile(cacheFile.getAbsolutePath());
}
catch(Exception e)
{
Log.e("CachedImageView", "Illegal icon cache?", e);
}
}
// ensure load once
final boolean loading;
synchronized(lock)
{
loading= loadingUris.contains(this.uri);
if(!loading)
{
loadingUris.add(this.uri);
}
}
if(loading) {
while (loadingUris.contains(this.uri)) {
Log.i(LOG_TAG, "Loading " + this.uri + ", wait it");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break;
}
}
// expects it was cached
return this.doInBackground();
}
InputStream in= null;
try
{
final HttpRequestFactory requestFactory= transport.createRequestFactory();
final HttpRequest request= requestFactory.buildGetRequest(new GenericUrl(url));
final HttpResponse response= request.execute();
in= response.getContent();
final Bitmap bitmap= BitmapFactory.decodeStream(in);
if(bitmap == null)
{
return null;
}
OutputStream out= null;
try
{
out= new FileOutputStream(cacheFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
}
catch(IOException e)
{
Log.e(LOG_TAG, "Couldn't write cache image to " + cacheFile, e);
}
finally
{
if(out != null)
{
try
{
out.close();
}
catch(IOException e)
{
Log.e(LOG_TAG, "Couldn't close " + cacheFile, e);
}
}
}
return bitmap;
}
catch(IOException e) {
Log.e(LOG_TAG, "Couldn't retrieve image content from url " + url, e);
return null;
}
finally
{
if(in != null)
{
try
{
in.close();
}
catch (IOException e) {
Log.e(LOG_TAG, "Couldn't close stream of " + url, e);
}
}
synchronized(lock)
{
loadingUris.remove(this.uri);
}
}
}
@Override
protected void onPostExecute(Bitmap bitmap) {
this.view.setImageBitmap(bitmap);
this.view.setVisibility(View.VISIBLE);
}
private static String escape(URL url)
{
try {
return URLEncoder.encode(url.toString(), "UTF-8");
}
catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}
}
private static final Object lock= new Object();
private static final Set<Uri> loadingUris= new HashSet<>();
private final ImageView view;
private Uri uri;
}
private static final class NoCacheImageLoader
extends AsyncTask<Void, Void, Bitmap>
{
public NoCacheImageLoader(ImageView view, Uri uri)
{
this.view= view;
this.uri= uri;
}
@Override
protected Bitmap doInBackground(Void... params) {
InputStream in= null;
try
{
Log.i("NoCacheImageLoader", "uri = " + this.uri);
final HttpRequestFactory requestFactory= transport.createRequestFactory();
final HttpRequest request= requestFactory.buildGetRequest(new GenericUrl(this.uri.toString()));
final HttpResponse response= request.execute();
Log.i("NoCacheImageLoader", "status code = " + response.getStatusCode());
in= response.getContent();
return BitmapFactory.decodeStream(in);
}
catch(IOException e) {
Log.e(LOG_TAG, "Couldn't retrieve image content from url " + this.uri, e);
return null;
}
finally
{
if(in != null)
{
try
{
in.close();
}
catch (IOException e) {
Log.e(LOG_TAG, "Couldn't close stream of " + this.uri, e);
}
}
}
}
@Override
protected void onPostExecute(Bitmap bitmap) {
this.view.setImageBitmap(bitmap);
this.view.setVisibility(View.VISIBLE);
}
private final ImageView view;
private Uri uri;
}
private static final String LOG_TAG= CachedImageView.class.getSimpleName();
private static final HttpTransport transport= AndroidHttp.newCompatibleTransport();
private static final Executor executor= Executors.newCachedThreadPool();
private Uri shownUri;
}