diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..5d44084b8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extern/Universal-Image-Loader"] + path = extern/Universal-Image-Loader + url = https://github.com/nostra13/Android-Universal-Image-Loader diff --git a/extern/Universal-Image-Loader b/extern/Universal-Image-Loader new file mode 160000 index 000000000..24ca7dd0d --- /dev/null +++ b/extern/Universal-Image-Loader @@ -0,0 +1 @@ +Subproject commit 24ca7dd0dbaee8a011aad6195f33e840793e7df9 diff --git a/project.properties b/project.properties index aa4c87bb7..9d8db91db 100644 --- a/project.properties +++ b/project.properties @@ -2,3 +2,4 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project. target=android-18 +android.library.reference.1=extern/Universal-Image-Loader/library diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 2d600e3ff..1fd383e51 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -70,6 +70,8 @@ import android.widget.BaseAdapter; import org.fdroid.fdroid.compat.PackageManagerCompat; +import com.nostra13.universalimageloader.core.ImageLoader; + public class AppDetails extends ListActivity { private static final int REQUEST_INSTALL = 0; @@ -406,12 +408,7 @@ public class AppDetails extends ListActivity { // Set the icon... ImageView iv = (ImageView) findViewById(R.id.icon); - File icon = new File(DB.getIconsPath(this), app.icon); - if (icon.exists()) { - iv.setImageDrawable(new BitmapDrawable(icon.getPath())); - } else { - iv.setImageResource(android.R.drawable.sym_def_app_icon); - } + ImageLoader.getInstance().displayImage(app.repoAddress+"/icons/"+app.icon, iv); // Set the title and other header details... TextView tv = (TextView) findViewById(R.id.title); diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index c53f30dc1..886f9e178 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -125,6 +125,7 @@ public class DB { compatible = false; ignoreUpdates = false; filtered = false; + repoAddress = null; } // True when all the detail fields are populated, False otherwise. @@ -207,6 +208,8 @@ public class DB { // List of apks. public List apks; + public String repoAddress; + // Get the current version - this will be one of the Apks from 'apks'. // Can return null if there are no available versions. // This should be the 'current' version, as in the most recent stable @@ -558,13 +561,6 @@ public class DB { return ContextCompat.create(ctx).getExternalCacheDir(); } - public static File getIconsPath(Context ctx) { - File dp = getDataPath(ctx); - if (dp == null) - return null; - return new File(dp, "icons"); - } - private Context mContext; private Apk.CompatibilityChecker compatChecker = null; diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java index 1709ff66f..58a97244c 100644 --- a/src/org/fdroid/fdroid/FDroidApp.java +++ b/src/org/fdroid/fdroid/FDroidApp.java @@ -19,7 +19,6 @@ package org.fdroid.fdroid; import java.io.File; -import java.io.FilenameFilter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Semaphore; @@ -30,6 +29,13 @@ import android.util.Log; import android.content.Context; import android.content.SharedPreferences; +import com.nostra13.universalimageloader.utils.StorageUtils; +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; +import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; + public class FDroidApp extends Application { @Override @@ -69,7 +75,22 @@ public class FDroidApp extends Application { ctx = getApplicationContext(); DB.initDB(ctx); UpdateService.schedule(ctx); - + + File cacheDir = new File(StorageUtils.getCacheDirectory(ctx), "icons"); + DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() + .cacheInMemory(true) + .cacheOnDisc(true) + .showImageOnLoading(android.R.drawable.sym_def_app_icon) + .showImageForEmptyUri(android.R.drawable.sym_def_app_icon) + .build(); + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(ctx) + .discCache(new UnlimitedDiscCache(cacheDir, new FileNameGenerator() { + public String generate(String imageUri) { + return imageUri.substring(imageUri.lastIndexOf('/') + 1); + } } )) + .defaultDisplayImageOptions(defaultOptions) + .build(); + ImageLoader.getInstance().init(config); } Context ctx; @@ -125,6 +146,11 @@ public class FDroidApp extends Application { try { DB db = DB.getDB(); apps = db.getApps(true); + for (DB.Repo repo : db.getRepos()) + for (DB.App app : apps) + if (repo.id == app.apks.get(0).repo) + app.repoAddress = repo.address; + } finally { DB.releaseDB(); } diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index b84e25ce5..d53aaa2d8 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -255,38 +255,6 @@ public class UpdateService extends IntentService implements ProgressListener { } - if (success) { - File d = DB.getIconsPath(this); - List toDownloadIcons = null; - if (!d.exists()) { - Log.d("FDroid", "Icons were wiped. Re-downloading all of them."); - d.mkdirs(); - toDownloadIcons = ((FDroidApp) getApplication()).getApps(); - } else if (changes) { - toDownloadIcons = acceptedapps; - } - if (toDownloadIcons != null) { - - // Create a .nomedia file in the icons directory. For - // recent Android versions this isn't necessary, because - // they recognise the cache location. Older versions don't - // though. - File f = new File(d, ".nomedia"); - if (!f.exists()) { - try { - f.createNewFile(); - } catch (Exception e) { - Log.d("FDroid", "Failed to create .nomedia"); - } - } - - sendStatus(STATUS_INFO, - getString(R.string.status_downloading_icons)); - for (DB.App app : toDownloadIcons) - getIcon(app, repos); - } - } - if (success && changes) ((FDroidApp) getApplication()).invalidateAllApps(); @@ -348,52 +316,6 @@ public class UpdateService extends IntentService implements ProgressListener { } } - private void getIcon(final DB.App app, List repos) { - InputStream input = null; - OutputStream output = null; - try { - - File f = new File(DB.getIconsPath(this), app.icon); - if (f.exists()) - return; - - if (app.apks.size() == 0) - return; - String server = null; - for (DB.Repo repo : repos) - if (repo.id == app.apks.get(0).repo) - server = repo.address; - if (server == null) - return; - - // Get it from the server... - URL u = new URL(server + "/icons/" + app.icon); - HttpURLConnection uc = (HttpURLConnection) u.openConnection(); - if (uc.getResponseCode() == 200) { - - // Delete all other icons for the same app - final File[] files = DB.getIconsPath(this).listFiles( - new FilenameFilter() { - @Override - public boolean accept(final File d, final String n) { - return n.matches(app.id+"\\.[0-9]+\\.png"); - } - } ); - for (final File file : files) { - if (!file.delete()) - Log.e("FDroid", "Cannot remove icon file " + file.getAbsolutePath()); - } - - input = uc.getInputStream(); - output = new FileOutputStream(f); - Utils.copy(input, output); - } - } catch (Exception e) { - } finally { - Utils.closeQuietly(output); - Utils.closeQuietly(input); - } - } /** * Received progress event from the RepoXMLHandler. It could be progress diff --git a/src/org/fdroid/fdroid/views/AppListAdapter.java b/src/org/fdroid/fdroid/views/AppListAdapter.java index d7ac6bb55..cbe461500 100644 --- a/src/org/fdroid/fdroid/views/AppListAdapter.java +++ b/src/org/fdroid/fdroid/views/AppListAdapter.java @@ -17,6 +17,8 @@ import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.R; import org.fdroid.fdroid.compat.LayoutCompat; +import com.nostra13.universalimageloader.core.ImageLoader; + abstract public class AppListAdapter extends BaseAdapter { private List items = new ArrayList(); @@ -77,7 +79,7 @@ abstract public class AppListAdapter extends BaseAdapter { summary.setText(app.summary); layoutSummary(summary); - layoutIcon(icon, app); + ImageLoader.getInstance().displayImage(app.repoAddress+"/icons/"+app.icon, icon); int visibleOnCompact = compact ? View.VISIBLE : View.GONE; int notVisibleOnCompact = compact ? View.GONE : View.VISIBLE; @@ -118,22 +120,6 @@ abstract public class AppListAdapter extends BaseAdapter { return convertView; } - /** - * If an icon exists on disc, we'll use that, otherwise default to the - * plain android app icon. - */ - private void layoutIcon(ImageView iconView, DB.App app) { - - File icn = new File(DB.getIconsPath(mContext), app.icon); - if (icn.exists() && icn.length() > 0) { - new Uri.Builder().build(); - iconView.setImageURI(Uri.parse(icn.getPath())); - } else { - iconView.setImageResource(android.R.drawable.sym_def_app_icon); - } - - } - /** * In compact view, the summary sites next to the icon, below the name. * In non-compact view, it sits under the icon, with some padding pushing