diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7cc2748d8..848ad8b0c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -82,5 +82,12 @@ + + + + + diff --git a/res/drawable-hdpi/paypal_donate.png b/res/drawable-hdpi/paypal_donate.png new file mode 100644 index 000000000..5ba389b66 Binary files /dev/null and b/res/drawable-hdpi/paypal_donate.png differ diff --git a/res/drawable-hdpi/twitter_birdy.png b/res/drawable-hdpi/twitter_birdy.png new file mode 100644 index 000000000..78cf72055 Binary files /dev/null and b/res/drawable-hdpi/twitter_birdy.png differ diff --git a/res/drawable-mdpi/paypal_donate.png b/res/drawable-mdpi/paypal_donate.png new file mode 100644 index 000000000..dffd01b5d Binary files /dev/null and b/res/drawable-mdpi/paypal_donate.png differ diff --git a/res/drawable-mdpi/twitter_birdy.png b/res/drawable-mdpi/twitter_birdy.png new file mode 100644 index 000000000..fb2c9d82e Binary files /dev/null and b/res/drawable-mdpi/twitter_birdy.png differ diff --git a/res/layout/dev_card.xml b/res/layout/dev_card.xml new file mode 100644 index 000000000..897f92731 --- /dev/null +++ b/res/layout/dev_card.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/developer_preference.xml b/res/layout/developer_preference.xml deleted file mode 100644 index b0f45eda5..000000000 --- a/res/layout/developer_preference.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 4c8303544..c334b4ee8 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -7,6 +7,7 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index 05a4849b3..78ac8de8a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4,6 +4,7 @@ ROM Control + User Interface Cancel OK Blank! @@ -39,7 +40,7 @@ Applications - Developers + The Crew Android Open Kang Project AOKP Website www.aokp.co - Find all newest releases here. @@ -57,7 +58,16 @@ https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YJTUMSBC2TRHS http://nyan.cat https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5R4DYJLDYDRAU - + http://goo.gl/fRj57 + https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=HGAN9G5ZJ2AAS&lc=US&item_name=kwes1020&currency_code=USD&bn=PP%%2dDonationsBF%%3abtn_donateCC_LG%2egif%%3aNonHosted + https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=U27ZAWB8995TS + http://bit.ly/t7YC5Z + https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7FN44KF8XZXFW + https://www.paypal.com/cgi-bin/webscr?cmd=_flow&SESSION=U3KYhTz6itHx8bKvx-F79EFVY5sQKKQu9f1ftkJ1pevFN6wdaJLu8yz3Y3e&dispatch=5885d80a13c0db1f8e263663d3faee8d1e83f46a36995b3856cef1e18897ad75 + https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WEZKU46DAFMSW + https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6SY3WH7AZNR7Y + https://support.woundedwarriorproject.org/Default.aspx?tsid=66&campaignSource=WEBSITE + Enable Volume Panel Show notification count @@ -133,8 +143,8 @@ How and when do you want the menu buttons to appear? Navigation button quantity Choose the number of navigation buttons - Nav button transparency Button %1$s action & icon + Nav button transparency Button %1$s longpress action Home Back diff --git a/res/xml/preference_headers.xml b/res/xml/preference_headers.xml index 607a66da2..ed13cc03d 100644 --- a/res/xml/preference_headers.xml +++ b/res/xml/preference_headers.xml @@ -1,4 +1,13 @@ + +
+ +
+
+ + - - - + + + + + + + + + + + + + + + + + diff --git a/src/com/aokp/romcontrol/fragments/About.java b/src/com/aokp/romcontrol/fragments/About.java index 28f5f9c57..6c3df2f35 100644 --- a/src/com/aokp/romcontrol/fragments/About.java +++ b/src/com/aokp/romcontrol/fragments/About.java @@ -5,11 +5,16 @@ import android.net.Uri; import android.os.Bundle; import android.preference.Preference; +import android.preference.PreferenceGroup; import android.preference.PreferenceScreen; import com.aokp.romcontrol.AOKPPreferenceFragment; import com.aokp.romcontrol.R; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + public class About extends AOKPPreferenceFragment { public static final String TAG = "About"; @@ -29,6 +34,20 @@ public void onCreate(Bundle savedInstanceState) { mReviewUrl = findPreference("aokp_review"); mIrcUrl = findPreference("aokp_irc"); + PreferenceGroup devsGroup = (PreferenceGroup) findPreference("devs"); + ArrayList devs = new ArrayList(); + for (int i = 0; i < devsGroup.getPreferenceCount(); i++) { + devs.add(devsGroup.getPreference(i)); + } + devsGroup.removeAll(); + devsGroup.setOrderingAsAdded(false); + Collections.shuffle(devs); + for(int i = 0; i < devs.size(); i++) { + Preference p = devs.get(i); + p.setOrder(i); + + devsGroup.addPreference(p); + } } @Override @@ -37,7 +56,7 @@ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preferen launchUrl("http://aokp.co/"); } else if (preference == mSourceUrl) { launchUrl("http://github.com/aokp"); - } else if (preference == mReviewUrl) { + } else if (preference == mReviewUrl) { launchUrl("http://gerrit.aokp.co"); } else if (preference == mIrcUrl) { launchUrl("http://webchat.freenode.net/?channels=teamkang"); diff --git a/src/com/aokp/romcontrol/widgets/DeveloperPreference.java b/src/com/aokp/romcontrol/widgets/DeveloperPreference.java index f75ed75d1..ca61c1d88 100644 --- a/src/com/aokp/romcontrol/widgets/DeveloperPreference.java +++ b/src/com/aokp/romcontrol/widgets/DeveloperPreference.java @@ -4,51 +4,69 @@ import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; +import android.net.http.AndroidHttpClient; +import android.os.AsyncTask; import android.preference.Preference; import android.util.AttributeSet; +import android.util.Log; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import com.aokp.romcontrol.R; +import com.koushikdutta.urlimageviewhelper.UrlImageViewCallback; +import com.koushikdutta.urlimageviewhelper.UrlImageViewHelper; + +import java.io.InputStream; +import java.net.HttpURLConnection; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.params.HttpClientParams; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; public class DeveloperPreference extends Preference { - TextView mName; - TextView twitter; - TextView donateText; - ImageView icon; - LinearLayout twitterLayout; - LinearLayout donateLayout; - ImageView donateButton; + private static final String TAG = "DeveloperPreference"; - String twitterHandle; - String donateLink; - String name; + private ImageView twitterButton; + private ImageView donateButton; + private ImageView photoView; + + private TextView devName; + + private String nameDev; + private String twitterName; + private String donateLink; public DeveloperPreference(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeveloperPreference); - twitterHandle = a.getString(R.styleable.DeveloperPreference_twitterHandle); + nameDev = a.getString(R.styleable.DeveloperPreference_nameDev); + twitterName = a.getString(R.styleable.DeveloperPreference_twitterHandle); donateLink = a.getString(R.styleable.DeveloperPreference_donateLink); a.recycle(); - } @Override protected View onCreateView(ViewGroup parent) { + super.onCreateView(parent); - View layout = View.inflate(getContext(), R.layout.developer_preference, null); + View layout = View.inflate(getContext(), R.layout.dev_card, null); - mName = (TextView) layout.findViewById(com.android.internal.R.id.title); - twitter = (TextView) layout.findViewById(R.id.twitter_handle); + twitterButton = (ImageView) layout.findViewById(R.id.twitter_button); donateButton = (ImageView) layout.findViewById(R.id.donate_button); - twitterLayout = (LinearLayout) layout.findViewById(R.id.twitter_layout); - icon = (ImageView) layout.findViewById(R.id.twitter_icon); + devName = (TextView) layout.findViewById(R.id.name); + photoView = (ImageView) layout.findViewById(R.id.photo); return layout; } @@ -57,33 +75,48 @@ protected View onCreateView(ViewGroup parent) { protected void onBindView(View view) { super.onBindView(view); - twitter.setText(twitterHandle); - icon.setImageResource(R.drawable.twitter_bird); - - if (twitterHandle == null) { - twitterLayout.setVisibility(View.GONE); - } else - this.setOnPreferenceClickListener(new OnPreferenceClickListener() { + if (donateLink != null) { + final OnClickListener openDonate = new OnClickListener() { @Override - public boolean onPreferenceClick(Preference preference) { - Uri uriUrl = Uri.parse("http://twitter.com/#!/" + twitterHandle); - Intent twitter = new Intent(Intent.ACTION_VIEW, uriUrl); - getContext().startActivity(twitter); - return true; + public void onClick(View v) { + Uri donateURL = Uri.parse(donateLink); + final Intent intent = new Intent(Intent.ACTION_VIEW, donateURL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + getContext().startActivity(intent); } - }); + }; - if (donateLink == null) + donateButton.setOnClickListener(openDonate); + } else { donateButton.setVisibility(View.GONE); - else - donateButton.setOnClickListener(new View.OnClickListener() { + } + + if (twitterName != null) { + final OnPreferenceClickListener openTwitter = new OnPreferenceClickListener() { @Override - public void onClick(View v) { - Uri uriUrl = Uri.parse(donateLink); - Intent donate = new Intent(Intent.ACTION_VIEW, uriUrl); - getContext().startActivity(donate); + public boolean onPreferenceClick(Preference preference) { + Uri twitterURL = Uri.parse("http://twitter.com/#!/" + twitterName); + final Intent intent = new Intent(Intent.ACTION_VIEW, twitterURL); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + getContext().startActivity(intent); + return true; } - }); + }; + + // changed to clicking the preference to open twitter + // it was a hit or miss to click the twitter bird + // twitterButton.setOnClickListener(openTwitter); + this.setOnPreferenceClickListener(openTwitter); + final String url = "http://api.twitter.com/1/users/profile_image/" + twitterName + + "?size=original"; + UrlImageViewHelper.setUrlDrawable(this.photoView, url, R.drawable.ic_null, + UrlImageViewHelper.CACHE_DURATION_ONE_WEEK); + } else { + twitterButton.setVisibility(View.INVISIBLE); + photoView.setVisibility(View.GONE); + } + + devName.setText(nameDev); } } diff --git a/src/com/koushikdutta/urlimageviewhelper/SoftReferenceHashTable.java b/src/com/koushikdutta/urlimageviewhelper/SoftReferenceHashTable.java new file mode 100644 index 000000000..348346afc --- /dev/null +++ b/src/com/koushikdutta/urlimageviewhelper/SoftReferenceHashTable.java @@ -0,0 +1,25 @@ +package com.koushikdutta.urlimageviewhelper; + +import java.lang.ref.SoftReference; +import java.util.Hashtable; + +public class SoftReferenceHashTable { + Hashtable> mTable = new Hashtable>(); + + public V put(K key, V value) { + SoftReference old = mTable.put(key, new SoftReference(value)); + if (old == null) + return null; + return old.get(); + } + + public V get(K key) { + SoftReference val = mTable.get(key); + if (val == null) + return null; + V ret = val.get(); + if (ret == null) + mTable.remove(key); + return ret; + } +} diff --git a/src/com/koushikdutta/urlimageviewhelper/UrlImageCache.java b/src/com/koushikdutta/urlimageviewhelper/UrlImageCache.java new file mode 100644 index 000000000..e2aeb869f --- /dev/null +++ b/src/com/koushikdutta/urlimageviewhelper/UrlImageCache.java @@ -0,0 +1,14 @@ +package com.koushikdutta.urlimageviewhelper; + +import android.graphics.drawable.Drawable; + +public final class UrlImageCache extends SoftReferenceHashTable { + private static UrlImageCache mInstance = new UrlImageCache(); + + public static UrlImageCache getInstance() { + return mInstance; + } + + private UrlImageCache() { + } +} diff --git a/src/com/koushikdutta/urlimageviewhelper/UrlImageViewCallback.java b/src/com/koushikdutta/urlimageviewhelper/UrlImageViewCallback.java new file mode 100644 index 000000000..39f66615f --- /dev/null +++ b/src/com/koushikdutta/urlimageviewhelper/UrlImageViewCallback.java @@ -0,0 +1,8 @@ +package com.koushikdutta.urlimageviewhelper; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +public interface UrlImageViewCallback { + void onLoaded(ImageView imageView, Drawable loadedDrawable, String url, boolean loadedFromCache); +} diff --git a/src/com/koushikdutta/urlimageviewhelper/UrlImageViewHelper.java b/src/com/koushikdutta/urlimageviewhelper/UrlImageViewHelper.java new file mode 100644 index 000000000..97119f6e2 --- /dev/null +++ b/src/com/koushikdutta/urlimageviewhelper/UrlImageViewHelper.java @@ -0,0 +1,319 @@ +package com.koushikdutta.urlimageviewhelper; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.util.ArrayList; +import java.util.Hashtable; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.params.HttpClientParams; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; + +import android.app.Activity; +import android.content.Context; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.net.http.AndroidHttpClient; +import android.os.AsyncTask; +import android.util.DisplayMetrics; +import android.util.Log; +import android.widget.ImageView; + +public final class UrlImageViewHelper { + private static final String LOGTAG = "UrlImageViewHelper"; + public static int copyStream(InputStream input, OutputStream output) throws IOException + { + byte[] stuff = new byte[1024]; + int read = 0; + int total = 0; + while ((read = input.read(stuff)) != -1) + { + output.write(stuff, 0, read); + total += read; + } + return total; + } + + static Resources mResources; + static DisplayMetrics mMetrics; + private static void prepareResources(Context context) { + if (mMetrics != null) + return; + mMetrics = new DisplayMetrics(); + Activity act = (Activity)context; + act.getWindowManager().getDefaultDisplay().getMetrics(mMetrics); + AssetManager mgr = context.getAssets(); + mResources = new Resources(mgr, mMetrics, context.getResources().getConfiguration()); + } + + private static BitmapDrawable loadDrawableFromStream(Context context, InputStream stream) { + prepareResources(context); + final Bitmap bitmap = BitmapFactory.decodeStream(stream); + //Log.i(LOGTAG, String.format("Loaded bitmap (%dx%d).", bitmap.getWidth(), bitmap.getHeight())); + return new BitmapDrawable(mResources, bitmap); + } + + public static final int CACHE_DURATION_INFINITE = Integer.MAX_VALUE; + public static final int CACHE_DURATION_ONE_DAY = 1000 * 60 * 60 * 24; + public static final int CACHE_DURATION_TWO_DAYS = CACHE_DURATION_ONE_DAY * 2; + public static final int CACHE_DURATION_THREE_DAYS = CACHE_DURATION_ONE_DAY * 3; + public static final int CACHE_DURATION_FOUR_DAYS = CACHE_DURATION_ONE_DAY * 4; + public static final int CACHE_DURATION_FIVE_DAYS = CACHE_DURATION_ONE_DAY * 5; + public static final int CACHE_DURATION_SIX_DAYS = CACHE_DURATION_ONE_DAY * 6; + public static final int CACHE_DURATION_ONE_WEEK = CACHE_DURATION_ONE_DAY * 7; + + public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, CACHE_DURATION_THREE_DAYS); + } + + public static void setUrlDrawable(final ImageView imageView, final String url) { + setUrlDrawable(imageView.getContext(), imageView, url, null, CACHE_DURATION_THREE_DAYS, null); + } + + public static void loadUrlDrawable(final Context context, final String url) { + setUrlDrawable(context, null, url, null, CACHE_DURATION_THREE_DAYS, null); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, CACHE_DURATION_THREE_DAYS, null); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource, long cacheDurationMs) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, cacheDurationMs); + } + + public static void loadUrlDrawable(final Context context, final String url, long cacheDurationMs) { + setUrlDrawable(context, null, url, null, cacheDurationMs, null); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable, long cacheDurationMs) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, cacheDurationMs, null); + } + + private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, int defaultResource, long cacheDurationMs) { + Drawable d = null; + if (defaultResource != 0) + d = imageView.getResources().getDrawable(defaultResource); + setUrlDrawable(context, imageView, url, d, cacheDurationMs, null); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource, UrlImageViewCallback callback) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, CACHE_DURATION_THREE_DAYS, callback); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, UrlImageViewCallback callback) { + setUrlDrawable(imageView.getContext(), imageView, url, null, CACHE_DURATION_THREE_DAYS, callback); + } + + public static void loadUrlDrawable(final Context context, final String url, UrlImageViewCallback callback) { + setUrlDrawable(context, null, url, null, CACHE_DURATION_THREE_DAYS, callback); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable, UrlImageViewCallback callback) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, CACHE_DURATION_THREE_DAYS, callback); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource, long cacheDurationMs, UrlImageViewCallback callback) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultResource, cacheDurationMs, callback); + } + + public static void loadUrlDrawable(final Context context, final String url, long cacheDurationMs, UrlImageViewCallback callback) { + setUrlDrawable(context, null, url, null, cacheDurationMs, callback); + } + + public static void setUrlDrawable(final ImageView imageView, final String url, Drawable defaultDrawable, long cacheDurationMs, UrlImageViewCallback callback) { + setUrlDrawable(imageView.getContext(), imageView, url, defaultDrawable, cacheDurationMs, callback); + } + + private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, int defaultResource, long cacheDurationMs, UrlImageViewCallback callback) { + Drawable d = null; + if (defaultResource != 0) + d = imageView.getResources().getDrawable(defaultResource); + setUrlDrawable(context, imageView, url, d, cacheDurationMs, callback); + } + + private static boolean isNullOrEmpty(CharSequence s) { + return (s == null || s.equals("") || s.equals("null") || s.equals("NULL")); + } + + private static boolean mHasCleaned = false; + + public static String getFilenameForUrl(String url) { + return "" + url.hashCode() + ".urlimage"; + } + + private static void cleanup(Context context) { + if (mHasCleaned) + return; + mHasCleaned = true; + try { + // purge any *.urlimage files over a week old + String[] files = context.getFilesDir().list(); + if (files == null) + return; + for (String file : files) { + if (!file.endsWith(".urlimage")) + continue; + + File f = new File(context.getFilesDir().getAbsolutePath() + '/' + file); + if (System.currentTimeMillis() > f.lastModified() + CACHE_DURATION_ONE_WEEK) + f.delete(); + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void setUrlDrawable(final Context context, final ImageView imageView, final String url, final Drawable defaultDrawable, long cacheDurationMs, final UrlImageViewCallback callback) { + cleanup(context); + // disassociate this ImageView from any pending downloads + if (imageView != null) + mPendingViews.remove(imageView); + + if (isNullOrEmpty(url)) { + if (imageView != null) + imageView.setImageDrawable(defaultDrawable); + return; + } + + final UrlImageCache cache = UrlImageCache.getInstance(); + Drawable drawable = cache.get(url); + if (drawable != null) { + //Log.i(LOGTAG, "Cache hit on: " + url); + if (imageView != null) + imageView.setImageDrawable(drawable); + if (callback != null) + callback.onLoaded(imageView, drawable, url, true); + return; + } + + final String filename = getFilenameForUrl(url); + + File file = context.getFileStreamPath(filename); + if (file.exists()) { + try { + if (cacheDurationMs == CACHE_DURATION_INFINITE || System.currentTimeMillis() < file.lastModified() + cacheDurationMs) { + //Log.i(LOGTAG, "File Cache hit on: " + url + ". " + (System.currentTimeMillis() - file.lastModified()) + "ms old."); + FileInputStream fis = context.openFileInput(filename); + drawable = loadDrawableFromStream(context, fis); + fis.close(); + if (imageView != null) + imageView.setImageDrawable(drawable); + cache.put(url, drawable); + if (callback != null) + callback.onLoaded(imageView, drawable, url, true); + return; + } + else { + //Log.i(LOGTAG, "File cache has expired. Refreshing."); + } + } + catch (Exception ex) { + } + } + + // null it while it is downloading + if (imageView != null) + imageView.setImageDrawable(defaultDrawable); + + // since listviews reuse their views, we need to + // take note of which url this view is waiting for. + // This may change rapidly as the list scrolls or is filtered, etc. + //Log.i(LOGTAG, "Waiting for " + url); + if (imageView != null) + mPendingViews.put(imageView, url); + + ArrayList currentDownload = mPendingDownloads.get(url); + if (currentDownload != null) { + // Also, multiple vies may be waiting for this url. + // So, let's maintain a list of these views. + // When the url is downloaded, it sets the imagedrawable for + // every view in the list. It needs to also validate that + // the imageview is still waiting for this url. + if (imageView != null) + currentDownload.add(imageView); + return; + } + + final ArrayList downloads = new ArrayList(); + if (imageView != null) + downloads.add(imageView); + mPendingDownloads.put(url, downloads); + + AsyncTask downloader = new AsyncTask() { + @Override + protected BitmapDrawable doInBackground(Void... params) { + AndroidHttpClient client = AndroidHttpClient.newInstance(context.getPackageName()); + try { + HttpGet get = new HttpGet(url); + final HttpParams httpParams = new BasicHttpParams(); + HttpClientParams.setRedirecting(httpParams, true); + get.setParams(httpParams); + HttpResponse resp = client.execute(get); + int status = resp.getStatusLine().getStatusCode(); + if(status != HttpURLConnection.HTTP_OK){ +// Log.i(LOGTAG, "Couldn't download image from Server: " + url + " Reason: " + resp.getStatusLine().getReasonPhrase() + " / " + status); + return null; + } + HttpEntity entity = resp.getEntity(); +// Log.i(LOGTAG, url + " Image Content Length: " + entity.getContentLength()); + InputStream is = entity.getContent(); + FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE); + copyStream(is, fos); + fos.close(); + is.close(); + FileInputStream fis = context.openFileInput(filename); + return loadDrawableFromStream(context, fis); + } + catch (Exception ex) { +// Log.e(LOGTAG, "Exception during Image download of " + url, ex); + return null; + } + finally { + client.close(); + } + } + + protected void onPostExecute(BitmapDrawable result) { + Drawable usableResult = result; + if (usableResult == null) + usableResult = defaultDrawable; + mPendingDownloads.remove(url); + cache.put(url, usableResult); + for (ImageView iv: downloads) { + // validate the url it is waiting for + String pendingUrl = mPendingViews.get(iv); + if (!url.equals(pendingUrl)) { + //Log.i(LOGTAG, "Ignoring out of date request to update view for " + url); + continue; + } + mPendingViews.remove(iv); + if (usableResult != null) { + final Drawable newImage = usableResult; + final ImageView imageView = iv; + imageView.setImageDrawable(newImage); + if (callback != null) + callback.onLoaded(imageView, result, url, false); + } + } + } + }; + downloader.execute(); + } + + private static Hashtable mPendingViews = new Hashtable(); + private static Hashtable> mPendingDownloads = new Hashtable>(); +}