Merge remote-tracking branch 'upstream/master' into improvement/16/manage-repos

Conflicts:
	res/values/strings.xml
	src/org/fdroid/fdroid/DB.java
	src/org/fdroid/fdroid/ManageRepo.java
	src/org/fdroid/fdroid/RepoXMLHandler.java
	src/org/fdroid/fdroid/Utils.java
This commit is contained in:
Peter Serwylo 2014-01-04 20:45:52 +11:00
commit 3731ed8f23
14 changed files with 251 additions and 156 deletions

2
.gitignore vendored
View File

@ -1,11 +1,9 @@
/local.properties
/build.properties
.classpath
/bin/
/gen/
/build
/.gradle
/proguard.cfg
/build.xml
*~
.idea

View File

@ -18,6 +18,14 @@
android:layout_marginRight="4dp"
android:orientation="vertical" >
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="false"
android:textSize="18sp"
android:textStyle="bold" />
<RelativeLayout
android:id="@+id/header"
android:layout_width="fill_parent"
@ -25,41 +33,48 @@
android:layout_marginBottom="4dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginBottom="4dp"
android:singleLine="false"
android:textSize="18sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_below="@id/title"
android:layout_marginRight="6dp"
android:layout_width="56dp"
android:layout_height="56dp"
android:padding="4dp"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/license"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_toRightOf="@id/icon"
android:textSize="13sp" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="4dp"
android:layout_toRightOf="@id/icon"
android:orientation="vertical" >
<TextView
android:id="@+id/license"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textSize="13sp" />
<TextView
android:id="@+id/categories"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/license"
android:layout_above="@id/status"
android:layout_centerVertical="true"
android:textSize="13sp" />
<TextView
android:id="@+id/status"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="13sp" />
</RelativeLayout>
<TextView
android:id="@+id/status"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/license"
android:layout_toRightOf="@id/icon"
android:textSize="13sp" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
<ListView

View File

@ -15,7 +15,7 @@
android:textSize="18sp" />
<TextView android:id="@+id/status"
android:textSize="12sp"
android:textSize="13sp"
android:maxLines="2"
android:ellipsize="end"
android:layout_below="@id/version"
@ -23,28 +23,36 @@
android:layout_width="wrap_content" />
<TextView android:id="@+id/added"
android:textSize="12sp"
android:textSize="13sp"
android:layout_below="@id/status"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView android:id="@+id/buildtype"
android:textSize="12sp"
android:textSize="13sp"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginBottom="4sp" />
<TextView android:id="@+id/size"
android:textSize="12sp"
android:textSize="13sp"
android:layout_below="@id/buildtype"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginBottom="4sp" />
<TextView android:id="@+id/api"
android:textSize="13sp"
android:layout_below="@id/buildtype"
android:layout_toLeftOf="@id/size"
android:layout_marginRight="16sp"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView android:id="@+id/nativecode"
android:textSize="12sp"
android:textSize="13sp"
android:layout_below="@id/size"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"

View File

@ -22,9 +22,8 @@
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_height="56dp"
android:padding="6dp"
android:layout_centerVertical="true"
android:orientation="vertical" >
<TextView
@ -33,9 +32,9 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:paddingTop="2sp"
android:paddingBottom="2sp"
android:layout_marginLeft="8dp"
android:paddingTop="3sp"
android:paddingBottom="3sp"
android:layout_marginLeft="8sp"
android:textSize="13sp" />
<TextView
@ -44,7 +43,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginLeft="8dp"
android:layout_marginLeft="8sp"
android:textSize="13sp" />
<TextView

View File

@ -27,11 +27,11 @@
<TextView android:id="@+id/status"
android:singleLine="true"
android:ellipsize="end"
android:paddingTop="2sp"
android:paddingBottom="2sp"
android:paddingTop="3sp"
android:paddingBottom="3sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginLeft="10sp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true" />
@ -41,7 +41,7 @@
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginLeft="10sp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true" />

View File

@ -194,5 +194,6 @@
<string name="repo_disabled_notification">Disabled "%1$s".\n\nYou will
need to re-enable this repository to install apps from it.
</string>
<string name="minsdk_or_later">Android %s or later</string>
</resources>

View File

@ -76,6 +76,9 @@ import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.utils.StorageUtils;
import android.os.Environment;
public class AppDetails extends ListActivity {
@ -140,10 +143,11 @@ public class AppDetails extends ListActivity {
tv = (TextView) v.findViewById(R.id.status);
if (apk.vercode == app.installedVerCode
&& apk.sig.equals(mInstalledSigID))
&& apk.sig.equals(mInstalledSigID)) {
tv.setText(getString(R.string.inst));
else
} else {
tv.setText(getString(R.string.not_inst));
}
tv.setEnabled(apk.compatible);
tv = (TextView) v.findViewById(R.id.size);
@ -153,6 +157,16 @@ public class AppDetails extends ListActivity {
tv.setText(Utils.getFriendlySize(apk.detail_size));
tv.setEnabled(apk.compatible);
}
tv = (TextView) v.findViewById(R.id.api);
if (apk.minSdkVersion == 0) {
tv.setText("");
} else {
tv.setText(getString(R.string.minsdk_or_later,
Utils.getAndroidVersionName(apk.minSdkVersion)));
tv.setEnabled(apk.compatible);
}
tv = (TextView) v.findViewById(R.id.buildtype);
if (apk.srcname != null) {
tv.setText("source");
@ -160,6 +174,7 @@ public class AppDetails extends ListActivity {
tv.setText("bin");
}
tv.setEnabled(apk.compatible);
tv = (TextView) v.findViewById(R.id.added);
if (apk.added != null) {
tv.setVisibility(View.VISIBLE);
@ -168,6 +183,7 @@ public class AppDetails extends ListActivity {
} else {
tv.setVisibility(View.GONE);
}
tv = (TextView) v.findViewById(R.id.nativecode);
if (pref_expert && apk.nativecode != null) {
tv.setVisibility(View.VISIBLE);
@ -457,26 +473,6 @@ public class AppDetails extends ListActivity {
tv = (TextView) infoView.findViewById(R.id.description);
/*
The following is a quick solution to enable both text selection and
links. Causes glitches and crashes:
java.lang.IndexOutOfBoundsException: setSpan (-1 ... -1) starts before 0
class CustomMovementMethod extends LinkMovementMethod {
@Override
public boolean canSelectArbitrarily () {
return true;
}
}
if (Utils.hasApi(11)) {
tv.setTextIsSelectable(true);
tv.setMovementMethod(new CustomMovementMethod());
} else {
tv.setMovementMethod(LinkMovementMethod.getInstance());
}
*/
tv.setMovementMethod(LinkMovementMethod.getInstance());
// Need this to add the unimplemented support for ordered and unordered
@ -848,8 +844,8 @@ public class AppDetails extends ListActivity {
public void onClick(DialogInterface dialog,
int whichButton) {
downloadHandler = new DownloadHandler(app.curApk,
repoaddress, DB
.getDataPath(getBaseContext()));
repoaddress, Utils
.getApkCacheDir(getBaseContext()));
}
});
ask_alrt.setNegativeButton(getString(R.string.no),
@ -879,7 +875,7 @@ public class AppDetails extends ListActivity {
return;
}
downloadHandler = new DownloadHandler(app.curApk, repoaddress,
DB.getDataPath(this));
Utils.getApkCacheDir(getBaseContext()));
}
private void removeApk(String id) {

View File

@ -108,7 +108,7 @@ public class DB {
+ "lastUpdated string," + "compatible int not null,"
+ "ignoreAllUpdates int not null,"
+ "ignoreThisUpdate int not null,"
+ "provides string," + "primary key(id));";
+ "primary key(id));";
public static class App implements Comparable<App> {
@ -126,7 +126,6 @@ public class DB {
detail_dogecoinAddr = null;
detail_webURL = null;
categories = null;
provides = null;
antiFeatures = null;
requirements = null;
hasUpdates = false;
@ -201,9 +200,6 @@ public class DB {
public int installedVerCode;
public boolean userInstalled;
// List of app IDs that this app provides or null if there aren't any.
public CommaSeparatedList provides;
// List of categories (as defined in the metadata
// documentation) or null if there aren't any.
public CommaSeparatedList categories;
@ -377,10 +373,11 @@ public class DB {
}
}
cpuAbis = new ArrayList<String>();
if (hasApi(8))
cpuAbis.add(android.os.Build.CPU_ABI2);
cpuAbis = new ArrayList<String>(2);
cpuAbis.add(android.os.Build.CPU_ABI);
if (hasApi(8)) {
cpuAbis.add(android.os.Build.CPU_ABI2);
}
Log.d("FDroid", logMsg.toString());
}
@ -413,8 +410,7 @@ public class DB {
}
if (!compatibleApi(apk.nativecode)) {
Log.d("FDroid", apk.id + " vercode " + apk.vercode
+ " makes use of incompatible native code: "
+ CommaSeparatedList.str(apk.nativecode)
+ " only supports " + CommaSeparatedList.str(apk.nativecode)
+ " while your architecture is " + cpuAbis.get(0));
return false;
}
@ -437,6 +433,7 @@ public class DB {
public String address;
public String name;
public String description;
public int version; // index version, i.e. what fdroidserver built it - 0 if not specified
public boolean inuse;
public int priority;
public String pubkey; // null for an unsigned repo
@ -530,7 +527,7 @@ public class DB {
}
}
private final int DBVersion = 33;
private final int DBVersion = 35;
private int countAppsForRepo(int id) {
String[] selection = { "COUNT(distinct id)" };
@ -609,6 +606,7 @@ public class DB {
mContext.getString(R.string.default_repo_name));
values.put("description",
mContext.getString(R.string.default_repo_description));
values.put("version", 0);
String pubkey = mContext.getString(R.string.default_repo_pubkey);
String fingerprint = DB.calcFingerprint(pubkey);
values.put("pubkey", pubkey);
@ -626,9 +624,11 @@ public class DB {
mContext.getString(R.string.default_repo_name2));
values.put("description",
mContext.getString(R.string.default_repo_description2));
values.put("version", 0);
// default #2 is /archive which has the same key as /repo
values.put("pubkey", pubkey);
values.put("fingerprint", fingerprint);
values.put("maxage", 0);
values.put("inuse", 0);
values.put("priority", 20);
values.put("lastetag", (String) null);
@ -720,23 +720,14 @@ public class DB {
db.execSQL("alter table " + TABLE_REPO + " add column maxage integer not null default 0");
}
if (oldVersion < 33) {
if (oldVersion < 35) {
if (!columnExists(db, TABLE_REPO, "lastUpdated"))
db.execSQL("Alter table " + TABLE_REPO + " add column lastUpdated string");
}
}
}
/**
* Get the local storage (cache) path. This will also create it if
* it doesn't exist. It can return null if it's currently unavailable.
*/
public static File getDataPath(Context ctx) {
return ContextCompat.create(ctx).getExternalCacheDir();
}
private Context mContext;
private Apk.CompatibilityChecker compatChecker = null;
@ -924,16 +915,23 @@ public class DB {
}
}
Map<String, App> apps = new HashMap<String, App>();
Cursor c = null;
// Start the map at the actual number of apps we will have
Cursor c = db.rawQuery("select count(*) from "+TABLE_APP, null);
c.moveToFirst();
int count = c.getInt(0);
c.close();
c = null;
Log.d("FDroid", "Will be fetching " + count + " apps, and this took us ");
Map<String, App> apps = new HashMap<String, App>(count);
long startTime = System.currentTimeMillis();
try {
String cols[] = new String[] { "antiFeatures", "requirements",
"categories", "id", "name", "summary", "icon", "license",
"curVersion", "curVercode", "added", "lastUpdated",
"compatible", "ignoreAllUpdates", "ignoreThisUpdate",
"provides" };
"compatible", "ignoreAllUpdates", "ignoreThisUpdate" };
c = db.query(TABLE_APP, cols, null, null, null, null, null);
c.moveToFirst();
while (!c.isAfterLast()) {
@ -959,7 +957,6 @@ public class DB {
app.compatible = c.getInt(12) == 1;
app.ignoreAllUpdates = c.getInt(13) == 1;
app.ignoreThisUpdate = c.getInt(14);
app.provides = DB.CommaSeparatedList.make(c.getString(15));
app.hasUpdates = false;
if (getinstalledinfo && systemApks.containsKey(app.id)) {
@ -979,18 +976,13 @@ public class DB {
}
apps.put(app.id, app);
if (app.provides != null) {
for (String id : app.provides) {
apps.put(id, app);
}
}
c.moveToNext();
}
c.close();
c = null;
Log.d("FDroid", "Read app data from database " + " (took "
Log.d("FDroid", "Read app data from database (took "
+ (System.currentTimeMillis() - startTime) + " ms)");
List<Repo> repos = getRepos();
@ -1049,7 +1041,7 @@ public class DB {
c.close();
}
Log.d("FDroid", "Read app and apk data from database " + " (took "
Log.d("FDroid", "Read app and apk data from database (took "
+ (System.currentTimeMillis() - startTime) + " ms)");
}
@ -1141,7 +1133,7 @@ public class DB {
try {
String filter = "%" + query + "%";
c = db.query(TABLE_APP, new String[] { "id" },
"id like ? or provides like ? or name like ? or summary like ? or description like ?",
"id like ? or name like ? or summary like ? or description like ?",
new String[] { filter, filter, filter, filter }, null, null, null);
c.moveToFirst();
while (!c.isAfterLast()) {
@ -1412,8 +1404,8 @@ public class DB {
Cursor c = null;
try {
c = db.query(TABLE_REPO, new String[] { "address", "name",
"description", "inuse", "priority", "pubkey", "fingerprint",
"maxage", "lastetag", "lastUpdated" },
"description", "version", "inuse", "priority", "pubkey",
"fingerprint", "maxage", "lastetag", "lastUpdated" },
"id = ?", new String[] { Integer.toString(id) }, null, null, null);
if (!c.moveToFirst())
return null;
@ -1422,19 +1414,19 @@ public class DB {
repo.address = c.getString(0);
repo.name = c.getString(1);
repo.description = c.getString(2);
repo.inuse = (c.getInt(3) == 1);
repo.priority = c.getInt(4);
repo.pubkey = c.getString(5);
repo.fingerprint = c.getString(6);
repo.maxage = c.getInt(7);
repo.lastetag = c.getString(8);
repo.version = c.getInt(3);
repo.inuse = (c.getInt(4) == 1);
repo.priority = c.getInt(5);
repo.pubkey = c.getString(6);
repo.fingerprint = c.getString(7);
repo.maxage = c.getInt(8);
repo.lastetag = c.getString(9);
try {
repo.lastUpdated = c.getString(9) != null ?
mDateFormat.parse( c.getString(9)) :
repo.lastUpdated = c.getString(10) != null ?
mDateFormat.parse( c.getString(10)) :
null;
} catch (ParseException e) {
Log.e("FDroid", "Error parsing date " + c.getString(9));
Log.e("FDroid", "Error parsing date " + c.getString(10));
}
return repo;
} finally {
@ -1449,8 +1441,8 @@ public class DB {
Cursor c = null;
try {
c = db.query(TABLE_REPO, new String[] { "id", "address", "name",
"description", "inuse", "priority", "pubkey", "fingerprint",
"maxage", "lastetag" },
"description", "version", "inuse", "priority", "pubkey",
"fingerprint", "maxage", "lastetag" },
null, null, null, null, "priority");
c.moveToFirst();
while (!c.isAfterLast()) {
@ -1459,12 +1451,13 @@ public class DB {
repo.address = c.getString(1);
repo.name = c.getString(2);
repo.description = c.getString(3);
repo.inuse = (c.getInt(4) == 1);
repo.priority = c.getInt(5);
repo.pubkey = c.getString(6);
repo.fingerprint = c.getString(7);
repo.maxage = c.getInt(8);
repo.lastetag = c.getString(9);
repo.version = c.getInt(4);
repo.inuse = (c.getInt(5) == 1);
repo.priority = c.getInt(6);
repo.pubkey = c.getString(7);
repo.fingerprint = c.getString(8);
repo.maxage = c.getInt(9);
repo.lastetag = c.getString(10);
repos.add(repo);
c.moveToNext();
}
@ -1524,6 +1517,7 @@ public class DB {
values.put("name", repo.name);
values.put("address", repo.address);
values.put("description", repo.description);
values.put("version", repo.version);
values.put("inuse", repo.inuse);
values.put("priority", repo.priority);
values.put("pubkey", repo.pubkey);
@ -1558,12 +1552,14 @@ public class DB {
}
public void addRepo(String address, String name, String description,
int priority, String pubkey, String fingerprint, int maxage, boolean inuse)
int version, int priority, String pubkey, String fingerprint,
int maxage, boolean inuse)
throws SecurityException {
ContentValues values = new ContentValues();
values.put("address", address);
values.put("name", name);
values.put("description", description);
values.put("version", version);
values.put("inuse", inuse ? 1 : 0);
values.put("priority", priority);
values.put("pubkey", pubkey);

View File

@ -127,8 +127,11 @@ public class FDroid extends FragmentActivity {
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(Menu.NONE, UPDATE_REPO, 1, R.string.menu_update_repo).setIcon(
MenuItem update = menu.add(Menu.NONE, UPDATE_REPO, 1, R.string.menu_update_repo).setIcon(
android.R.drawable.ic_menu_rotate);
MenuItemCompat.setShowAsAction(update,
MenuItemCompat.SHOW_AS_ACTION_ALWAYS |
MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
menu.add(Menu.NONE, MANAGE_REPO, 2, R.string.menu_manage).setIcon(
android.R.drawable.ic_menu_agenda);
MenuItem search = menu.add(Menu.NONE, SEARCH, 3, R.string.menu_search).setIcon(

View File

@ -31,11 +31,13 @@ import android.util.Log;
import android.content.Context;
import android.content.SharedPreferences;
import com.nostra13.universalimageloader.utils.StorageUtils;
import org.fdroid.fdroid.Utils;
import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.utils.StorageUtils;
public class FDroidApp extends Application {
@ -78,14 +80,14 @@ public class FDroidApp extends Application {
curTheme = Theme.valueOf(prefs.getString("theme", "dark"));
if (!prefs.getBoolean("cacheDownloaded", false)) {
File local_path = DB.getDataPath(this);
File local_path = Utils.getApkCacheDir(this);
// Things can be null if the SD card is not ready - we'll just
// ignore that and do it next time.
if(local_path != null) {
if (local_path != null) {
File[] files = local_path.listFiles();
if(files != null) {
for(File f : files) {
if(f.getName().endsWith(".apk")) {
if (files != null) {
for (File f : files) {
if (f.getName().endsWith(".apk")) {
f.delete();
}
}
@ -101,7 +103,8 @@ public class FDroidApp extends Application {
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(ctx)
.discCache(new LimitedAgeDiscCache(
new File(StorageUtils.getCacheDirectory(ctx), "icons"),
new File(StorageUtils.getCacheDirectory(ctx, true),
"icons"),
new FileNameGenerator() {
@Override
public String generate(String imageUri) {

View File

@ -64,8 +64,9 @@ public class RepoXMLHandler extends DefaultHandler {
private DB.Apk curapk = null;
private StringBuilder curchars = new StringBuilder();
// After processing the XML, this will be -1 if the index didn't specify
// a maximum age - otherwise it will be the value specified.
// After processing the XML, these will be -1 if the index didn't specify
// them - otherwise it will be the value specified.
private int version = -1;
private int maxage = -1;
// After processing the XML, this will be null if the index specified a
@ -242,8 +243,6 @@ public class RepoXMLHandler extends DefaultHandler {
} catch (NumberFormatException ex) {
curapp.curVercode = -1;
}
} else if (curel.equals("provides")) {
curapp.provides = DB.CommaSeparatedList.make(str);
} else if (curel.equals("categories")) {
curapp.categories = DB.CommaSeparatedList.make(str);
} else if (curel.equals("antifeatures")) {
@ -266,10 +265,12 @@ public class RepoXMLHandler extends DefaultHandler {
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if (localName.equals("repo")) {
String pk = attributes.getValue("", "pubkey");
if (pk != null)
pubkey = pk;
String maxAgeAttr = attributes.getValue("", "maxage");
if (maxAgeAttr != null) {
try {
@ -277,12 +278,20 @@ public class RepoXMLHandler extends DefaultHandler {
} catch (NumberFormatException nfe) {}
}
String versionAttr = attributes.getValue("", "version");
if (versionAttr != null) {
try {
version = Integer.parseInt(versionAttr);
} catch (NumberFormatException nfe) {}
}
String nm = attributes.getValue("", "name");
if (nm != null)
name = nm;
String dc = attributes.getValue("", "description");
if (dc != null)
description = dc;
} else if (localName.equals("application") && curapp == null) {
curapp = new DB.App();
curapp.detail_Populated = true;
@ -293,11 +302,13 @@ public class RepoXMLHandler extends DefaultHandler {
new ProgressListener.Event(
RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter,
totalAppCount, progressData));
} else if (localName.equals("package") && curapp != null && curapk == null) {
curapk = new DB.Apk();
curapk.id = curapp.id;
curapk.repo = repo.id;
hashType = null;
} else if (localName.equals("hash") && curapk != null) {
hashType = attributes.getValue("", "type");
}
@ -511,6 +522,13 @@ public class RepoXMLHandler extends DefaultHandler {
repoChanged = true;
}
if (version != -1 && version != repo.version) {
Log.d("FDroid", "Repo specified a new version: from "
+ repo.version + " to " + version);
repo.version = version;
repoChanged = true;
}
if (maxage != -1 && maxage != repo.maxage) {
Log.d("FDroid",
"Repo specified a new maximum age - updated");

View File

@ -31,6 +31,10 @@ import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.Formatter;
import android.content.Context;
import com.nostra13.universalimageloader.utils.StorageUtils;
public final class Utils {
public static final int BUFFER_SIZE = 4096;
@ -86,6 +90,30 @@ public final class Utils {
return String.format(FRIENDLY_SIZE_FORMAT[i], s);
}
public static String getAndroidVersionName(int sdkLevel) {
switch (sdkLevel) {
case 19: return "4.4";
case 18: return "4.3";
case 17: return "4.2";
case 16: return "4.1";
case 15: return "4.0.3";
case 14: return "4.0";
case 13: return "3.2";
case 12: return "3.1";
case 11: return "3.0";
case 10: return "2.3.3";
case 9: return "2.3";
case 8: return "2.2";
case 7: return "2.1";
case 6: return "2.0.1";
case 5: return "2.0";
case 4: return "1.6";
case 3: return "1.5";
case 2: return "1.1";
default: return "1.0";
}
}
public static int countSubstringOccurrence(File file, String substring) throws IOException {
int count = 0;
BufferedReader reader = null;
@ -152,4 +180,14 @@ public final class Utils {
}
return fingerprintString;
}
public static File getApkCacheDir(Context context) {
File apkCacheDir = new File(
StorageUtils.getCacheDirectory(context, true), "apks");
if (!apkCacheDir.exists()) {
apkCacheDir.mkdir();
}
return apkCacheDir;
}
}

View File

@ -39,7 +39,7 @@ class OldContextCompatImpl extends ContextCompat {
public File getExternalCacheDir() {
File file = new File(Environment.getExternalStorageDirectory(),
"Android/data/org.fdroid.fdroid/cache");
if(!file.exists())
if (!file.exists())
file.mkdirs();
return file;
}

View File

@ -27,10 +27,13 @@ abstract public class AppListAdapter extends BaseAdapter {
private List<DB.App> items = new ArrayList<DB.App>();
private Context mContext;
private LayoutInflater mInflater;
private DisplayImageOptions displayImageOptions;
public AppListAdapter(Context context) {
mContext = context;
mInflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
displayImageOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true)
@ -76,38 +79,55 @@ abstract public class AppListAdapter extends BaseAdapter {
return position;
}
static class ViewHolder {
TextView name;
TextView summary;
TextView status;
TextView license;
ImageView icon;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
boolean compact = Preferences.get().hasCompactLayout();
DB.App app = items.get(position);
ViewHolder holder;
if (convertView == null) {
convertView = ((LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.applistitem, null);
convertView = mInflater.inflate(R.layout.applistitem, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.summary = (TextView) convertView.findViewById(R.id.summary);
holder.status = (TextView) convertView.findViewById(R.id.status);
holder.license = (TextView) convertView.findViewById(R.id.license);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
TextView name = (TextView) convertView.findViewById(R.id.name);
TextView summary = (TextView) convertView.findViewById(R.id.summary);
TextView status = (TextView) convertView.findViewById(R.id.status);
TextView license = (TextView) convertView.findViewById(R.id.license);
ImageView icon = (ImageView) convertView.findViewById(R.id.icon);
holder.name.setText(app.name);
holder.summary.setText(app.summary);
name.setText(app.name);
summary.setText(app.summary);
int visibleOnCompact = compact ? View.VISIBLE : View.GONE;
int notVisibleOnCompact = compact ? View.GONE : View.VISIBLE;
layoutIcon(icon, compact);
ImageLoader.getInstance().displayImage(app.iconUrl, icon,
layoutIcon(holder.icon, compact);
ImageLoader.getInstance().displayImage(app.iconUrl, holder.icon,
displayImageOptions);
status.setText(getVersionInfo(app));
license.setText(app.license);
holder.status.setText(getVersionInfo(app));
holder.license.setText(app.license);
// Disable it all if it isn't compatible...
View[] views = { convertView, status, summary, license, name };
View[] views = {
convertView,
holder.status,
holder.summary,
holder.license,
holder.name
};
for (View view : views) {
view.setEnabled(app.compatible && !app.filtered);
}