Use UIL, don't do caching on our own.
Advantages: * Initial setup time for icons is zero * We don't have to deal with it ourselves * We can use the default package icon while we load
This commit is contained in:
parent
0d6ec3a001
commit
017811fb92
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "extern/Universal-Image-Loader"]
|
||||||
|
path = extern/Universal-Image-Loader
|
||||||
|
url = https://github.com/nostra13/Android-Universal-Image-Loader
|
1
extern/Universal-Image-Loader
vendored
Submodule
1
extern/Universal-Image-Loader
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 24ca7dd0dbaee8a011aad6195f33e840793e7df9
|
@ -2,3 +2,4 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.
|
|||||||
|
|
||||||
target=android-18
|
target=android-18
|
||||||
|
|
||||||
|
android.library.reference.1=extern/Universal-Image-Loader/library
|
||||||
|
@ -70,6 +70,8 @@ import android.widget.BaseAdapter;
|
|||||||
|
|
||||||
import org.fdroid.fdroid.compat.PackageManagerCompat;
|
import org.fdroid.fdroid.compat.PackageManagerCompat;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
public class AppDetails extends ListActivity {
|
public class AppDetails extends ListActivity {
|
||||||
|
|
||||||
private static final int REQUEST_INSTALL = 0;
|
private static final int REQUEST_INSTALL = 0;
|
||||||
@ -406,12 +408,7 @@ public class AppDetails extends ListActivity {
|
|||||||
|
|
||||||
// Set the icon...
|
// Set the icon...
|
||||||
ImageView iv = (ImageView) findViewById(R.id.icon);
|
ImageView iv = (ImageView) findViewById(R.id.icon);
|
||||||
File icon = new File(DB.getIconsPath(this), app.icon);
|
ImageLoader.getInstance().displayImage(app.repoAddress+"/icons/"+app.icon, iv);
|
||||||
if (icon.exists()) {
|
|
||||||
iv.setImageDrawable(new BitmapDrawable(icon.getPath()));
|
|
||||||
} else {
|
|
||||||
iv.setImageResource(android.R.drawable.sym_def_app_icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the title and other header details...
|
// Set the title and other header details...
|
||||||
TextView tv = (TextView) findViewById(R.id.title);
|
TextView tv = (TextView) findViewById(R.id.title);
|
||||||
|
@ -125,6 +125,7 @@ public class DB {
|
|||||||
compatible = false;
|
compatible = false;
|
||||||
ignoreUpdates = false;
|
ignoreUpdates = false;
|
||||||
filtered = false;
|
filtered = false;
|
||||||
|
repoAddress = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// True when all the detail fields are populated, False otherwise.
|
// True when all the detail fields are populated, False otherwise.
|
||||||
@ -207,6 +208,8 @@ public class DB {
|
|||||||
// List of apks.
|
// List of apks.
|
||||||
public List<Apk> apks;
|
public List<Apk> apks;
|
||||||
|
|
||||||
|
public String repoAddress;
|
||||||
|
|
||||||
// Get the current version - this will be one of the Apks from 'apks'.
|
// Get the current version - this will be one of the Apks from 'apks'.
|
||||||
// Can return null if there are no available versions.
|
// Can return null if there are no available versions.
|
||||||
// This should be the 'current' version, as in the most recent stable
|
// This should be the 'current' version, as in the most recent stable
|
||||||
@ -558,13 +561,6 @@ public class DB {
|
|||||||
return ContextCompat.create(ctx).getExternalCacheDir();
|
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 Context mContext;
|
||||||
private Apk.CompatibilityChecker compatChecker = null;
|
private Apk.CompatibilityChecker compatChecker = null;
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
@ -30,6 +29,13 @@ import android.util.Log;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
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 {
|
public class FDroidApp extends Application {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -70,6 +76,21 @@ public class FDroidApp extends Application {
|
|||||||
DB.initDB(ctx);
|
DB.initDB(ctx);
|
||||||
UpdateService.schedule(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;
|
Context ctx;
|
||||||
@ -125,6 +146,11 @@ public class FDroidApp extends Application {
|
|||||||
try {
|
try {
|
||||||
DB db = DB.getDB();
|
DB db = DB.getDB();
|
||||||
apps = db.getApps(true);
|
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 {
|
} finally {
|
||||||
DB.releaseDB();
|
DB.releaseDB();
|
||||||
}
|
}
|
||||||
|
@ -255,38 +255,6 @@ public class UpdateService extends IntentService implements ProgressListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
|
||||||
File d = DB.getIconsPath(this);
|
|
||||||
List<DB.App> 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)
|
if (success && changes)
|
||||||
((FDroidApp) getApplication()).invalidateAllApps();
|
((FDroidApp) getApplication()).invalidateAllApps();
|
||||||
|
|
||||||
@ -348,52 +316,6 @@ public class UpdateService extends IntentService implements ProgressListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getIcon(final DB.App app, List<DB.Repo> 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
|
* Received progress event from the RepoXMLHandler. It could be progress
|
||||||
|
@ -17,6 +17,8 @@ import org.fdroid.fdroid.Preferences;
|
|||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.compat.LayoutCompat;
|
import org.fdroid.fdroid.compat.LayoutCompat;
|
||||||
|
|
||||||
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
abstract public class AppListAdapter extends BaseAdapter {
|
abstract public class AppListAdapter extends BaseAdapter {
|
||||||
|
|
||||||
private List<DB.App> items = new ArrayList<DB.App>();
|
private List<DB.App> items = new ArrayList<DB.App>();
|
||||||
@ -77,7 +79,7 @@ abstract public class AppListAdapter extends BaseAdapter {
|
|||||||
summary.setText(app.summary);
|
summary.setText(app.summary);
|
||||||
|
|
||||||
layoutSummary(summary);
|
layoutSummary(summary);
|
||||||
layoutIcon(icon, app);
|
ImageLoader.getInstance().displayImage(app.repoAddress+"/icons/"+app.icon, icon);
|
||||||
|
|
||||||
int visibleOnCompact = compact ? View.VISIBLE : View.GONE;
|
int visibleOnCompact = compact ? View.VISIBLE : View.GONE;
|
||||||
int notVisibleOnCompact = compact ? View.GONE : View.VISIBLE;
|
int notVisibleOnCompact = compact ? View.GONE : View.VISIBLE;
|
||||||
@ -118,22 +120,6 @@ abstract public class AppListAdapter extends BaseAdapter {
|
|||||||
return convertView;
|
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 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
|
* In non-compact view, it sits under the icon, with some padding pushing
|
||||||
|
Loading…
x
Reference in New Issue
Block a user