Major revamp of database and app index handling
This commit is contained in:
parent
c40572ca92
commit
a14a926264
@ -111,10 +111,10 @@ public class AppDetails extends ListActivity {
|
|||||||
else
|
else
|
||||||
status.setText(getString(R.string.not_inst));
|
status.setText(getString(R.string.not_inst));
|
||||||
TextView size = (TextView) v.findViewById(R.id.size);
|
TextView size = (TextView) v.findViewById(R.id.size);
|
||||||
if (apk.size == 0) {
|
if (apk.detail_size == 0) {
|
||||||
size.setText("");
|
size.setText("");
|
||||||
} else {
|
} else {
|
||||||
size.setText(getFriendlySize(apk.size));
|
size.setText(getFriendlySize(apk.detail_size));
|
||||||
}
|
}
|
||||||
TextView buildtype = (TextView) v.findViewById(R.id.buildtype);
|
TextView buildtype = (TextView) v.findViewById(R.id.buildtype);
|
||||||
if (apk.srcname != null) {
|
if (apk.srcname != null) {
|
||||||
@ -277,6 +277,16 @@ public class AppDetails extends ListActivity {
|
|||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the app is populated.
|
||||||
|
try {
|
||||||
|
DB db = DB.getDB();
|
||||||
|
db.populateDetails(app);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.d("FDroid", "Failed to populate app - " + ex.getMessage());
|
||||||
|
} finally {
|
||||||
|
DB.releaseDB();
|
||||||
|
}
|
||||||
|
|
||||||
DB.Apk curver = app.getCurrentVersion();
|
DB.Apk curver = app.getCurrentVersion();
|
||||||
app_currentvercode = curver == null ? 0 : curver.vercode;
|
app_currentvercode = curver == null ? 0 : curver.vercode;
|
||||||
@ -333,7 +343,7 @@ public class AppDetails extends ListActivity {
|
|||||||
tv.setText(String.format(getString(R.string.details_installed),
|
tv.setText(String.format(getString(R.string.details_installed),
|
||||||
app.installedVersion));
|
app.installedVersion));
|
||||||
tv = (TextView) findViewById(R.id.description);
|
tv = (TextView) findViewById(R.id.description);
|
||||||
tv.setText(app.description);
|
tv.setText(app.detail_description);
|
||||||
if (pref_expert && mInstalledSignature != null) {
|
if (pref_expert && mInstalledSignature != null) {
|
||||||
tv = (TextView) findViewById(R.id.signature);
|
tv = (TextView) findViewById(R.id.signature);
|
||||||
tv.setText("Signed: " + mInstalledSigID);
|
tv.setText("Signed: " + mInstalledSigID);
|
||||||
@ -370,21 +380,21 @@ public class AppDetails extends ListActivity {
|
|||||||
menu.add(Menu.NONE, UNINSTALL, 1, R.string.menu_uninstall).setIcon(
|
menu.add(Menu.NONE, UNINSTALL, 1, R.string.menu_uninstall).setIcon(
|
||||||
android.R.drawable.ic_menu_delete);
|
android.R.drawable.ic_menu_delete);
|
||||||
}
|
}
|
||||||
if (app.webURL.length() > 0) {
|
if (app.detail_webURL.length() > 0) {
|
||||||
menu.add(Menu.NONE, WEBSITE, 2, R.string.menu_website).setIcon(
|
menu.add(Menu.NONE, WEBSITE, 2, R.string.menu_website).setIcon(
|
||||||
android.R.drawable.ic_menu_view);
|
android.R.drawable.ic_menu_view);
|
||||||
}
|
}
|
||||||
if (app.trackerURL.length() > 0) {
|
if (app.detail_trackerURL.length() > 0) {
|
||||||
menu.add(Menu.NONE, ISSUES, 3, R.string.menu_issues).setIcon(
|
menu.add(Menu.NONE, ISSUES, 3, R.string.menu_issues).setIcon(
|
||||||
android.R.drawable.ic_menu_view);
|
android.R.drawable.ic_menu_view);
|
||||||
}
|
}
|
||||||
if (app.sourceURL.length() > 0) {
|
if (app.detail_sourceURL.length() > 0) {
|
||||||
menu.add(Menu.NONE, SOURCE, 4, R.string.menu_source).setIcon(
|
menu.add(Menu.NONE, SOURCE, 4, R.string.menu_source).setIcon(
|
||||||
android.R.drawable.ic_menu_view);
|
android.R.drawable.ic_menu_view);
|
||||||
}
|
}
|
||||||
menu.add(Menu.NONE, MARKET, 5, R.string.menu_market).setIcon(
|
menu.add(Menu.NONE, MARKET, 5, R.string.menu_market).setIcon(
|
||||||
android.R.drawable.ic_menu_view);
|
android.R.drawable.ic_menu_view);
|
||||||
if (app.donateURL != null) {
|
if (app.detail_donateURL != null) {
|
||||||
menu.add(Menu.NONE, DONATE, 6, R.string.menu_donate).setIcon(
|
menu.add(Menu.NONE, DONATE, 6, R.string.menu_donate).setIcon(
|
||||||
android.R.drawable.ic_menu_view);
|
android.R.drawable.ic_menu_view);
|
||||||
}
|
}
|
||||||
@ -409,17 +419,17 @@ public class AppDetails extends ListActivity {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case WEBSITE:
|
case WEBSITE:
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(app.webURL)));
|
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(app.detail_webURL)));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ISSUES:
|
case ISSUES:
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW,
|
startActivity(new Intent(Intent.ACTION_VIEW,
|
||||||
Uri.parse(app.trackerURL)));
|
Uri.parse(app.detail_trackerURL)));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case SOURCE:
|
case SOURCE:
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW,
|
startActivity(new Intent(Intent.ACTION_VIEW,
|
||||||
Uri.parse(app.sourceURL)));
|
Uri.parse(app.detail_sourceURL)));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MARKET:
|
case MARKET:
|
||||||
@ -429,7 +439,7 @@ public class AppDetails extends ListActivity {
|
|||||||
|
|
||||||
case DONATE:
|
case DONATE:
|
||||||
startActivity(new Intent(Intent.ACTION_VIEW,
|
startActivity(new Intent(Intent.ACTION_VIEW,
|
||||||
Uri.parse(app.donateURL)));
|
Uri.parse(app.detail_donateURL)));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,8 @@ import android.preference.PreferenceManager;
|
|||||||
import android.text.TextUtils.SimpleStringSplitter;
|
import android.text.TextUtils.SimpleStringSplitter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class DB {
|
public class DB {
|
||||||
|
|
||||||
private static Semaphore dbSync = new Semaphore(1, true);
|
private static Semaphore dbSync = new Semaphore(1, true);
|
||||||
@ -91,16 +93,11 @@ public class DB {
|
|||||||
+ "summary text not null, " + "icon text, "
|
+ "summary text not null, " + "icon text, "
|
||||||
+ "description text not null, " + "license text not null, "
|
+ "description text not null, " + "license text not null, "
|
||||||
+ "webURL text, " + "trackerURL text, " + "sourceURL text, "
|
+ "webURL text, " + "trackerURL text, " + "sourceURL text, "
|
||||||
+ "curVersion text,"
|
+ "curVersion text," + "curVercode integer,"
|
||||||
+ "curVercode integer,"
|
+ "antiFeatures string," + "donateURL string,"
|
||||||
+ "antiFeatures string,"
|
+ "requirements string," + "category string," + "added string,"
|
||||||
+ "donateURL string,"
|
+ "lastUpdated string," + "primary key(id));";
|
||||||
+ "requirements string,"
|
|
||||||
+ "category string,"
|
|
||||||
+ "added string,"
|
|
||||||
+ "lastUpdated string,"
|
|
||||||
+ "primary key(id));";
|
|
||||||
|
|
||||||
public static class App implements Comparable<App> {
|
public static class App implements Comparable<App> {
|
||||||
|
|
||||||
public App() {
|
public App() {
|
||||||
@ -110,10 +107,10 @@ public class DB {
|
|||||||
id = "unknown";
|
id = "unknown";
|
||||||
license = "Unknown";
|
license = "Unknown";
|
||||||
category = "Uncategorized";
|
category = "Uncategorized";
|
||||||
trackerURL = "";
|
detail_trackerURL = null;
|
||||||
sourceURL = "";
|
detail_sourceURL = null;
|
||||||
donateURL = null;
|
detail_donateURL = null;
|
||||||
webURL = "";
|
detail_webURL = null;
|
||||||
antiFeatures = null;
|
antiFeatures = null;
|
||||||
requirements = null;
|
requirements = null;
|
||||||
hasUpdates = false;
|
hasUpdates = false;
|
||||||
@ -121,19 +118,36 @@ public class DB {
|
|||||||
added = null;
|
added = null;
|
||||||
lastUpdated = null;
|
lastUpdated = null;
|
||||||
apks = new Vector<Apk>();
|
apks = new Vector<Apk>();
|
||||||
|
detail_Populated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// True when all the detail fields are populated, False otherwise.
|
||||||
|
public boolean detail_Populated;
|
||||||
|
|
||||||
public String id;
|
public String id;
|
||||||
public String name;
|
public String name;
|
||||||
public String summary;
|
public String summary;
|
||||||
public String icon;
|
public String icon;
|
||||||
public String description;
|
|
||||||
|
// Null when !detail_Populated
|
||||||
|
public String detail_description;
|
||||||
|
|
||||||
public String license;
|
public String license;
|
||||||
public String category;
|
public String category;
|
||||||
public String webURL;
|
|
||||||
public String trackerURL;
|
// Null when !detail_Populated
|
||||||
public String sourceURL;
|
public String detail_webURL;
|
||||||
public String donateURL; // Donate link, or null
|
|
||||||
|
// Null when !detail_Populated
|
||||||
|
public String detail_trackerURL;
|
||||||
|
|
||||||
|
// Null when !detail_Populated
|
||||||
|
public String detail_sourceURL;
|
||||||
|
|
||||||
|
// Donate link, or null
|
||||||
|
// Null when !detail_Populated
|
||||||
|
public String detail_donateURL;
|
||||||
|
|
||||||
public String curVersion;
|
public String curVersion;
|
||||||
public int curVercode;
|
public int curVercode;
|
||||||
public Date added;
|
public Date added;
|
||||||
@ -163,6 +177,7 @@ public class DB {
|
|||||||
// Used internally for tracking during repo updates.
|
// Used internally for tracking during repo updates.
|
||||||
public boolean updated;
|
public boolean updated;
|
||||||
|
|
||||||
|
// List of apks.
|
||||||
public Vector<Apk> apks;
|
public Vector<Apk> apks;
|
||||||
|
|
||||||
// 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'.
|
||||||
@ -208,36 +223,35 @@ public class DB {
|
|||||||
+ " ( " + "id text not null, " + "version text not null, "
|
+ " ( " + "id text not null, " + "version text not null, "
|
||||||
+ "server text not null, " + "hash text not null, "
|
+ "server text not null, " + "hash text not null, "
|
||||||
+ "vercode int not null," + "apkName text not null, "
|
+ "vercode int not null," + "apkName text not null, "
|
||||||
+ "size int not null,"
|
+ "size int not null," + "apkSource text," + "sig string,"
|
||||||
+ "apkSource text,"
|
+ "srcname string," + "minSdkVersion integer,"
|
||||||
+ "sig string,"
|
+ "permissions string," + "features string," + "hashType string,"
|
||||||
+ "srcname string,"
|
+ "added string," + "primary key(id,vercode));";
|
||||||
+ "minSdkVersion integer,"
|
|
||||||
+ "permissions string,"
|
|
||||||
+ "features string,"
|
|
||||||
+ "hashType string,"
|
|
||||||
+ "added string,"
|
|
||||||
+ "primary key(id));";
|
|
||||||
|
|
||||||
public static class Apk {
|
public static class Apk {
|
||||||
|
|
||||||
public Apk() {
|
public Apk() {
|
||||||
updated = false;
|
updated = false;
|
||||||
size = 0;
|
detail_size = 0;
|
||||||
apkSource = null;
|
apkSource = null;
|
||||||
added = null;
|
added = null;
|
||||||
|
detail_server = null;
|
||||||
|
detail_hash = null;
|
||||||
|
detail_hashType = null;
|
||||||
|
detail_permissions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String id;
|
public String id;
|
||||||
public String version;
|
public String version;
|
||||||
public int vercode;
|
public int vercode;
|
||||||
public int size; // Size in bytes - 0 means we don't know!
|
public int detail_size; // Size in bytes - 0 means we don't know!
|
||||||
public String server;
|
public String detail_server;
|
||||||
public String hash;
|
public String detail_hash;
|
||||||
public String hashType;
|
public String detail_hashType;
|
||||||
public int minSdkVersion; // 0 if unknown
|
public int minSdkVersion; // 0 if unknown
|
||||||
public Date added;
|
public Date added;
|
||||||
public CommaSeparatedList permissions; // null if empty or unknown
|
public CommaSeparatedList detail_permissions; // null if empty or
|
||||||
|
// unknown
|
||||||
public CommaSeparatedList features; // null if empty or unknown
|
public CommaSeparatedList features; // null if empty or unknown
|
||||||
|
|
||||||
// ID (md5 sum of public key) of signature. Might be null, in the
|
// ID (md5 sum of public key) of signature. Might be null, in the
|
||||||
@ -260,7 +274,7 @@ public class DB {
|
|||||||
|
|
||||||
public String getURL() {
|
public String getURL() {
|
||||||
String path = apkName.replace(" ", "%20");
|
String path = apkName.replace(" ", "%20");
|
||||||
return server + "/" + path;
|
return detail_server + "/" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call isCompatible(apk) on an instance of this class to
|
// Call isCompatible(apk) on an instance of this class to
|
||||||
@ -315,7 +329,8 @@ public class DB {
|
|||||||
if (apk.features != null) {
|
if (apk.features != null) {
|
||||||
for (String feat : apk.features) {
|
for (String feat : apk.features) {
|
||||||
if (!features.contains(feat)) {
|
if (!features.contains(feat)) {
|
||||||
Log.d("FDroid", "Incompatible based on lack of "
|
Log.d("FDroid", apk.id
|
||||||
|
+ " is incompatible based on lack of "
|
||||||
+ feat);
|
+ feat);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -340,8 +355,21 @@ public class DB {
|
|||||||
public String pubkey; // null for an unsigned repo
|
public String pubkey; // null for an unsigned repo
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int DBVersion = 16;
|
private final int DBVersion = 17;
|
||||||
|
|
||||||
|
private static void createAppApk(SQLiteDatabase db) {
|
||||||
|
db.execSQL(CREATE_TABLE_APP);
|
||||||
|
db.execSQL("create index app_id on " + TABLE_APP + " (id);");
|
||||||
|
db.execSQL(CREATE_TABLE_APK);
|
||||||
|
db.execSQL("create index apk_vercode on " + TABLE_APK
|
||||||
|
+ " (vercode);");
|
||||||
|
db.execSQL("create index apk_id on " + TABLE_APK + " (id);");
|
||||||
|
}
|
||||||
|
public static void resetTransient(SQLiteDatabase db) {
|
||||||
|
db.execSQL("drop table " + TABLE_APP);
|
||||||
|
db.execSQL("drop table " + TABLE_APK);
|
||||||
|
createAppApk(db);
|
||||||
|
}
|
||||||
private class DBHelper extends SQLiteOpenHelper {
|
private class DBHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
public DBHelper(Context context) {
|
public DBHelper(Context context) {
|
||||||
@ -350,10 +378,10 @@ public class DB {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db) {
|
public void onCreate(SQLiteDatabase db) {
|
||||||
|
|
||||||
|
createAppApk(db);
|
||||||
|
|
||||||
db.execSQL(CREATE_TABLE_REPO);
|
db.execSQL(CREATE_TABLE_REPO);
|
||||||
db.execSQL(CREATE_TABLE_APP);
|
|
||||||
db.execSQL(CREATE_TABLE_APK);
|
|
||||||
db.execSQL("create index apk_vercode on " + TABLE_APK + " (vercode);");
|
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("address",
|
values.put("address",
|
||||||
mContext.getString(R.string.default_repo_address));
|
mContext.getString(R.string.default_repo_address));
|
||||||
@ -366,14 +394,12 @@ public class DB {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
db.execSQL("drop table " + TABLE_APP);
|
resetTransient(db);
|
||||||
db.execSQL("drop table " + TABLE_APK);
|
|
||||||
db.execSQL(CREATE_TABLE_APP);
|
|
||||||
db.execSQL(CREATE_TABLE_APK);
|
|
||||||
if (oldVersion < 7)
|
if (oldVersion < 7)
|
||||||
db.execSQL("alter table " + TABLE_REPO + " add pubkey string");
|
db.execSQL("alter table " + TABLE_REPO + " add pubkey string");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getDataPath() {
|
public static File getDataPath() {
|
||||||
@ -418,6 +444,11 @@ public class DB {
|
|||||||
db = null;
|
db = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the transient data in the database.
|
||||||
|
public void reset() {
|
||||||
|
resetTransient(db);
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the database, which should cause it to be re-created next time
|
// Delete the database, which should cause it to be re-created next time
|
||||||
// it's used.
|
// it's used.
|
||||||
public static void delete(Context ctx) {
|
public static void delete(Context ctx) {
|
||||||
@ -470,6 +501,52 @@ public class DB {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate the details for the given app, if necessary.
|
||||||
|
public void populateDetails(App app) {
|
||||||
|
if (app.detail_Populated)
|
||||||
|
return;
|
||||||
|
Cursor c = null;
|
||||||
|
try {
|
||||||
|
String[] cols = new String[] { "description", "webURL",
|
||||||
|
"trackerURL", "sourceURL", "donateURL" };
|
||||||
|
c = db.query(TABLE_APP, cols, "id = ?", new String[] { app.id },
|
||||||
|
null, null, null, null);
|
||||||
|
c.moveToFirst();
|
||||||
|
app.detail_description = c.getString(0);
|
||||||
|
app.detail_webURL = c.getString(1);
|
||||||
|
app.detail_trackerURL = c.getString(2);
|
||||||
|
app.detail_sourceURL = c.getString(3);
|
||||||
|
app.detail_donateURL = c.getString(4);
|
||||||
|
c.close();
|
||||||
|
c = null;
|
||||||
|
|
||||||
|
cols = new String[] { "server", "hash", "hashType", "size",
|
||||||
|
"permissions" };
|
||||||
|
for (Apk apk : app.apks) {
|
||||||
|
|
||||||
|
c = db.query(
|
||||||
|
TABLE_APK,
|
||||||
|
cols,
|
||||||
|
"id = ? and vercode = " + Integer.toString(apk.vercode),
|
||||||
|
new String[] { apk.id }, null, null, null, null);
|
||||||
|
c.moveToFirst();
|
||||||
|
apk.detail_server = c.getString(0);
|
||||||
|
apk.detail_hash = c.getString(1);
|
||||||
|
apk.detail_hashType = c.getString(2);
|
||||||
|
apk.detail_size = c.getInt(3);
|
||||||
|
apk.detail_permissions = CommaSeparatedList
|
||||||
|
.make(c.getString(4));
|
||||||
|
c.close();
|
||||||
|
c = null;
|
||||||
|
}
|
||||||
|
app.detail_Populated = true;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return a list of apps matching the given criteria. Filtering is
|
// Return a list of apps matching the given criteria. Filtering is
|
||||||
// also done based on compatibility and anti-features according to
|
// also done based on compatibility and anti-features according to
|
||||||
// the user's current preferences.
|
// the user's current preferences.
|
||||||
@ -491,34 +568,28 @@ public class DB {
|
|||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
c = db.query(TABLE_APP, null, null, null, null, null, null);
|
String cols[] = new String[] { "antiFeatures", "requirements",
|
||||||
|
"id", "name", "summary", "icon", "license", "category",
|
||||||
|
"curVersion", "curVercode", "added", "lastUpdated" };
|
||||||
|
c = db.query(TABLE_APP, cols, null, null, null, null, null);
|
||||||
c.moveToFirst();
|
c.moveToFirst();
|
||||||
while (!c.isAfterLast()) {
|
while (!c.isAfterLast()) {
|
||||||
|
|
||||||
App app = new App();
|
App app = new App();
|
||||||
app.antiFeatures = DB.CommaSeparatedList.make(c.getString(c
|
app.antiFeatures = DB.CommaSeparatedList.make(c.getString(0));
|
||||||
.getColumnIndex("antiFeatures")));
|
app.requirements = DB.CommaSeparatedList.make(c.getString(1));
|
||||||
app.requirements = DB.CommaSeparatedList.make(c.getString(c
|
app.id = c.getString(2);
|
||||||
.getColumnIndex("requirements")));
|
app.name = c.getString(3);
|
||||||
app.id = c.getString(c.getColumnIndex("id"));
|
app.summary = c.getString(4);
|
||||||
app.name = c.getString(c.getColumnIndex("name"));
|
app.icon = c.getString(5);
|
||||||
app.summary = c.getString(c.getColumnIndex("summary"));
|
app.license = c.getString(6);
|
||||||
app.icon = c.getString(c.getColumnIndex("icon"));
|
app.category = c.getString(7);
|
||||||
app.description = c.getString(c.getColumnIndex("description"));
|
app.curVersion = c.getString(8);
|
||||||
app.license = c.getString(c.getColumnIndex("license"));
|
app.curVercode = c.getInt(9);
|
||||||
app.category = c.getString(c.getColumnIndex("category"));
|
String sAdded = c.getString(10);
|
||||||
app.webURL = c.getString(c.getColumnIndex("webURL"));
|
|
||||||
app.trackerURL = c.getString(c.getColumnIndex("trackerURL"));
|
|
||||||
app.sourceURL = c.getString(c.getColumnIndex("sourceURL"));
|
|
||||||
app.donateURL = c.getString(c.getColumnIndex("donateURL"));
|
|
||||||
app.curVersion = c.getString(c
|
|
||||||
.getColumnIndex("curVersion"));
|
|
||||||
app.curVercode = c.getInt(c.getColumnIndex("curVercode"));
|
|
||||||
String sAdded = c.getString(c.getColumnIndex("added"));
|
|
||||||
app.added = (sAdded == null || sAdded.length() == 0) ? null
|
app.added = (sAdded == null || sAdded.length() == 0) ? null
|
||||||
: mDateFormat.parse(sAdded);
|
: mDateFormat.parse(sAdded);
|
||||||
String sLastUpdated = c.getString(c
|
String sLastUpdated = c.getString(11);
|
||||||
.getColumnIndex("lastUpdated"));
|
|
||||||
app.lastUpdated = (sLastUpdated == null || sLastUpdated
|
app.lastUpdated = (sLastUpdated == null || sLastUpdated
|
||||||
.length() == 0) ? null : mDateFormat
|
.length() == 0) ? null : mDateFormat
|
||||||
.parse(sLastUpdated);
|
.parse(sLastUpdated);
|
||||||
@ -543,30 +614,26 @@ public class DB {
|
|||||||
Log.d("FDroid", "Read app data from database " + " (took "
|
Log.d("FDroid", "Read app data from database " + " (took "
|
||||||
+ (System.currentTimeMillis() - startTime) + " ms)");
|
+ (System.currentTimeMillis() - startTime) + " ms)");
|
||||||
|
|
||||||
c = db.query(TABLE_APK, null, null, null, null, null,
|
cols = new String[] { "id", "version", "vercode", "sig", "srcname",
|
||||||
|
"apkName", "apkSource", "minSdkVersion", "added",
|
||||||
|
"features" };
|
||||||
|
c = db.query(TABLE_APK, cols, null, null, null, null,
|
||||||
"vercode desc");
|
"vercode desc");
|
||||||
c.moveToFirst();
|
c.moveToFirst();
|
||||||
while (!c.isAfterLast()) {
|
while (!c.isAfterLast()) {
|
||||||
Apk apk = new Apk();
|
Apk apk = new Apk();
|
||||||
apk.id = c.getString(c.getColumnIndex("id"));
|
apk.id = c.getString(0);
|
||||||
apk.version = c.getString(c.getColumnIndex("version"));
|
apk.version = c.getString(1);
|
||||||
apk.vercode = c.getInt(c.getColumnIndex("vercode"));
|
apk.vercode = c.getInt(2);
|
||||||
apk.server = c.getString(c.getColumnIndex("server"));
|
apk.sig = c.getString(3);
|
||||||
apk.hash = c.getString(c.getColumnIndex("hash"));
|
apk.srcname = c.getString(4);
|
||||||
apk.hashType = c.getString(c.getColumnIndex("hashType"));
|
apk.apkName = c.getString(5);
|
||||||
apk.sig = c.getString(c.getColumnIndex("sig"));
|
apk.apkSource = c.getString(6);
|
||||||
apk.srcname = c.getString(c.getColumnIndex("srcname"));
|
apk.minSdkVersion = c.getInt(7);
|
||||||
apk.size = c.getInt(c.getColumnIndex("size"));
|
String sApkAdded = c.getString(8);
|
||||||
apk.apkName = c.getString(c.getColumnIndex("apkName"));
|
|
||||||
apk.apkSource = c.getString(c.getColumnIndex("apkSource"));
|
|
||||||
apk.minSdkVersion = c.getInt(c.getColumnIndex("minSdkVersion"));
|
|
||||||
String sApkAdded = c.getString(c.getColumnIndex("added"));
|
|
||||||
apk.added = (sApkAdded == null || sApkAdded.length() == 0) ? null
|
apk.added = (sApkAdded == null || sApkAdded.length() == 0) ? null
|
||||||
: mDateFormat.parse(sApkAdded);
|
: mDateFormat.parse(sApkAdded);
|
||||||
apk.permissions = CommaSeparatedList.make(c.getString(c
|
apk.features = CommaSeparatedList.make(c.getString(9));
|
||||||
.getColumnIndex("permissions")));
|
|
||||||
apk.features = CommaSeparatedList.make(c.getString(c
|
|
||||||
.getColumnIndex("features")));
|
|
||||||
apps.get(apk.id).apks.add(apk);
|
apps.get(apk.id).apks.add(apk);
|
||||||
c.moveToNext();
|
c.moveToNext();
|
||||||
}
|
}
|
||||||
@ -609,6 +676,27 @@ public class DB {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector<String> doSearch(String query) {
|
||||||
|
|
||||||
|
Vector<String> ids = new Vector<String>();
|
||||||
|
Cursor c = null;
|
||||||
|
try {
|
||||||
|
String filter = "%" + query + "%";
|
||||||
|
c = db.query(TABLE_APP, new String[] { "id" },
|
||||||
|
"name like ? or description like ?", new String[] { filter,
|
||||||
|
filter }, null, null, null);
|
||||||
|
c.moveToFirst();
|
||||||
|
while (!c.isAfterLast()) {
|
||||||
|
ids.add(c.getString(0));
|
||||||
|
c.moveToNext();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (c != null)
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
public static class CommaSeparatedList implements Iterable<String> {
|
public static class CommaSeparatedList implements Iterable<String> {
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
@ -669,6 +757,7 @@ public class DB {
|
|||||||
public void endUpdate() {
|
public void endUpdate() {
|
||||||
if (updateApps == null)
|
if (updateApps == null)
|
||||||
return;
|
return;
|
||||||
|
Log.d("FDroid", "Processing endUpdate - " + updateApps.size() + " apps before");
|
||||||
for (App app : updateApps) {
|
for (App app : updateApps) {
|
||||||
if (!app.updated) {
|
if (!app.updated) {
|
||||||
// The application hasn't been updated, so it's no longer
|
// The application hasn't been updated, so it's no longer
|
||||||
@ -735,15 +824,13 @@ public class DB {
|
|||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (App app : updateApps) {
|
for (App app : updateApps) {
|
||||||
if (app.id.equals(upapp.id)) {
|
if (app.id.equals(upapp.id)) {
|
||||||
// Log.d("FDroid", "AppUpdate: " + app.id
|
|
||||||
// + " is already in the database.");
|
|
||||||
updateApp(app, upapp);
|
updateApp(app, upapp);
|
||||||
app.updated = true;
|
app.updated = true;
|
||||||
found = true;
|
found = true;
|
||||||
for (Apk upapk : compatibleapks) {
|
for (Apk upapk : compatibleapks) {
|
||||||
boolean afound = false;
|
boolean afound = false;
|
||||||
for (Apk apk : app.apks) {
|
for (Apk apk : app.apks) {
|
||||||
if (apk.version.equals(upapk.version)) {
|
if (apk.vercode == upapk.vercode) {
|
||||||
// Log.d("FDroid", "AppUpdate: " + apk.version
|
// Log.d("FDroid", "AppUpdate: " + apk.version
|
||||||
// + " is a known version.");
|
// + " is a known version.");
|
||||||
updateApkIfDifferent(apk, upapk);
|
updateApkIfDifferent(apk, upapk);
|
||||||
@ -754,8 +841,6 @@ public class DB {
|
|||||||
}
|
}
|
||||||
if (!afound) {
|
if (!afound) {
|
||||||
// A new version of this application.
|
// A new version of this application.
|
||||||
// Log.d("FDroid", "AppUpdate: " + upapk.version
|
|
||||||
// + " is a new version.");
|
|
||||||
updateApkIfDifferent(null, upapk);
|
updateApkIfDifferent(null, upapk);
|
||||||
upapk.updated = true;
|
upapk.updated = true;
|
||||||
app.apks.add(upapk);
|
app.apks.add(upapk);
|
||||||
@ -766,9 +851,6 @@ public class DB {
|
|||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// It's a brand new application...
|
// It's a brand new application...
|
||||||
// Log
|
|
||||||
// .d("FDroid", "AppUpdate: " + upapp.id
|
|
||||||
// + " is a new application.");
|
|
||||||
updateApp(null, upapp);
|
updateApp(null, upapp);
|
||||||
for (Apk upapk : compatibleapks) {
|
for (Apk upapk : compatibleapks) {
|
||||||
updateApkIfDifferent(null, upapk);
|
updateApkIfDifferent(null, upapk);
|
||||||
@ -791,13 +873,13 @@ public class DB {
|
|||||||
values.put("name", upapp.name);
|
values.put("name", upapp.name);
|
||||||
values.put("summary", upapp.summary);
|
values.put("summary", upapp.summary);
|
||||||
values.put("icon", upapp.icon);
|
values.put("icon", upapp.icon);
|
||||||
values.put("description", upapp.description);
|
values.put("description", upapp.detail_description);
|
||||||
values.put("license", upapp.license);
|
values.put("license", upapp.license);
|
||||||
values.put("category", upapp.category);
|
values.put("category", upapp.category);
|
||||||
values.put("webURL", upapp.webURL);
|
values.put("webURL", upapp.detail_webURL);
|
||||||
values.put("trackerURL", upapp.trackerURL);
|
values.put("trackerURL", upapp.detail_trackerURL);
|
||||||
values.put("sourceURL", upapp.sourceURL);
|
values.put("sourceURL", upapp.detail_sourceURL);
|
||||||
values.put("donateURL", upapp.donateURL);
|
values.put("donateURL", upapp.detail_donateURL);
|
||||||
values.put("added",
|
values.put("added",
|
||||||
upapp.added == null ? "" : mDateFormat.format(upapp.added));
|
upapp.added == null ? "" : mDateFormat.format(upapp.added));
|
||||||
values.put(
|
values.put(
|
||||||
@ -826,22 +908,23 @@ public class DB {
|
|||||||
values.put("id", upapk.id);
|
values.put("id", upapk.id);
|
||||||
values.put("version", upapk.version);
|
values.put("version", upapk.version);
|
||||||
values.put("vercode", upapk.vercode);
|
values.put("vercode", upapk.vercode);
|
||||||
values.put("server", upapk.server);
|
values.put("server", upapk.detail_server);
|
||||||
values.put("hash", upapk.hash);
|
values.put("hash", upapk.detail_hash);
|
||||||
values.put("hashType", upapk.hashType);
|
values.put("hashType", upapk.detail_hashType);
|
||||||
values.put("sig", upapk.sig);
|
values.put("sig", upapk.sig);
|
||||||
values.put("srcname", upapk.srcname);
|
values.put("srcname", upapk.srcname);
|
||||||
values.put("size", upapk.size);
|
values.put("size", upapk.detail_size);
|
||||||
values.put("apkName", upapk.apkName);
|
values.put("apkName", upapk.apkName);
|
||||||
values.put("apkSource", upapk.apkSource);
|
values.put("apkSource", upapk.apkSource);
|
||||||
values.put("minSdkVersion", upapk.minSdkVersion);
|
values.put("minSdkVersion", upapk.minSdkVersion);
|
||||||
values.put("added",
|
values.put("added",
|
||||||
upapk.added == null ? "" : mDateFormat.format(upapk.added));
|
upapk.added == null ? "" : mDateFormat.format(upapk.added));
|
||||||
values.put("permissions", CommaSeparatedList.str(upapk.permissions));
|
values.put("permissions",
|
||||||
|
CommaSeparatedList.str(upapk.detail_permissions));
|
||||||
values.put("features", CommaSeparatedList.str(upapk.features));
|
values.put("features", CommaSeparatedList.str(upapk.features));
|
||||||
if (oldapk != null) {
|
if (oldapk != null) {
|
||||||
db.update(TABLE_APK, values, "id = ? and version =?", new String[] {
|
db.update(TABLE_APK, values, "id = ? and vercode = " + Integer.toString(oldapk.vercode),
|
||||||
oldapk.id, oldapk.version });
|
new String[] { oldapk.id });
|
||||||
} else {
|
} else {
|
||||||
db.insert(TABLE_APK, null, values);
|
db.insert(TABLE_APK, null, values);
|
||||||
}
|
}
|
||||||
|
@ -47,10 +47,10 @@ public class Downloader extends Thread {
|
|||||||
private int max;
|
private int max;
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|
||||||
|
// Constructor - creates a Downloader to download the given Apk,
|
||||||
|
// which must have its detail populated.
|
||||||
Downloader(DB.Apk apk) {
|
Downloader(DB.Apk apk) {
|
||||||
synchronized (this) {
|
curapk = apk;
|
||||||
curapk = apk;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Status getStatus() {
|
public synchronized Status getStatus() {
|
||||||
@ -99,8 +99,8 @@ public class Downloader extends Thread {
|
|||||||
// See if we already have this apk cached...
|
// See if we already have this apk cached...
|
||||||
if (localfile.exists()) {
|
if (localfile.exists()) {
|
||||||
// We do - if its hash matches, we'll use it...
|
// We do - if its hash matches, we'll use it...
|
||||||
Hasher hash = new Hasher(curapk.hashType, localfile);
|
Hasher hash = new Hasher(curapk.detail_hashType, localfile);
|
||||||
if (hash.match(curapk.hash)) {
|
if (hash.match(curapk.detail_hash)) {
|
||||||
Log.d("FDroid", "Using cached apk at " + localfile);
|
Log.d("FDroid", "Using cached apk at " + localfile);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
progress = 1;
|
progress = 1;
|
||||||
@ -117,7 +117,7 @@ public class Downloader extends Thread {
|
|||||||
// If we haven't got the apk locally, we'll have to download it...
|
// If we haven't got the apk locally, we'll have to download it...
|
||||||
String remotefile;
|
String remotefile;
|
||||||
if (curapk.apkSource == null) {
|
if (curapk.apkSource == null) {
|
||||||
remotefile = curapk.server + "/" + apkname.replace(" ", "%20");
|
remotefile = curapk.detail_server + "/" + apkname.replace(" ", "%20");
|
||||||
} else {
|
} else {
|
||||||
remotefile = curapk.apkSource;
|
remotefile = curapk.apkSource;
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ public class Downloader extends Thread {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
filename = remotefile;
|
filename = remotefile;
|
||||||
progress = 0;
|
progress = 0;
|
||||||
max = curapk.size;
|
max = curapk.detail_size;
|
||||||
status = Status.RUNNING;
|
status = Status.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,11 +161,11 @@ public class Downloader extends Thread {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Hasher hash = new Hasher(curapk.hashType, localfile);
|
Hasher hash = new Hasher(curapk.detail_hashType, localfile);
|
||||||
if (!hash.match(curapk.hash)) {
|
if (!hash.match(curapk.detail_hash)) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
Log.d("FDroid", "Downloaded file hash of " + hash.getHash()
|
Log.d("FDroid", "Downloaded file hash of " + hash.getHash()
|
||||||
+ " did not match repo's " + curapk.hash);
|
+ " did not match repo's " + curapk.detail_hash);
|
||||||
// No point keeping a bad file, whether we're
|
// No point keeping a bad file, whether we're
|
||||||
// caching or not.
|
// caching or not.
|
||||||
localfile.delete();
|
localfile.delete();
|
||||||
|
@ -256,6 +256,7 @@ public class FDroid extends TabActivity implements OnItemClickListener,
|
|||||||
// unschedule) the service accordingly. It's cheap, so no need to
|
// unschedule) the service accordingly. It's cheap, so no need to
|
||||||
// check if the particular setting has actually been changed.
|
// check if the particular setting has actually been changed.
|
||||||
UpdateService.schedule(getBaseContext());
|
UpdateService.schedule(getBaseContext());
|
||||||
|
populateLists();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
@ -35,12 +38,33 @@ public class Preferences extends PreferenceActivity {
|
|||||||
r.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
r.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||||
|
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
DB.delete(getApplicationContext());
|
|
||||||
// TODO: Clear cached apks and icons too.
|
// TODO: Progress dialog + thread is needed, it can take a
|
||||||
Toast
|
// while to delete all the icons and cached apks in a long
|
||||||
.makeText(getBaseContext(),
|
// standing install!
|
||||||
"Local cached data has been cleared",
|
Toast.makeText(getBaseContext(),
|
||||||
Toast.LENGTH_LONG).show();
|
"Hold on...", Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
|
||||||
|
// TODO: This is going to cause problems if there is background
|
||||||
|
// update in progress at the time!
|
||||||
|
|
||||||
|
try {
|
||||||
|
DB db = DB.getDB();
|
||||||
|
db.reset();
|
||||||
|
} finally {
|
||||||
|
DB.releaseDB();
|
||||||
|
}
|
||||||
|
((FDroidApp) getApplication()).invalidateApps();
|
||||||
|
|
||||||
|
File dp = DB.getDataPath();
|
||||||
|
deleteAll(dp);
|
||||||
|
dp.mkdir();
|
||||||
|
DB.getIconsPath().mkdir();
|
||||||
|
|
||||||
|
Toast.makeText(getBaseContext(),
|
||||||
|
"Local cached data has been cleared", Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,4 +72,22 @@ public class Preferences extends PreferenceActivity {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
Intent ret = new Intent();
|
||||||
|
this.setResult(RESULT_OK, ret);
|
||||||
|
super.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteAll(File dir) {
|
||||||
|
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
String[] children = dir.list();
|
||||||
|
for (int i = 0; i < children.length; i++) {
|
||||||
|
deleteAll(new File(dir, children[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,9 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
// going to be stupid if the list gets very big!
|
// going to be stupid if the list gets very big!
|
||||||
boolean merged = false;
|
boolean merged = false;
|
||||||
for (DB.App app : apps) {
|
for (DB.App app : apps) {
|
||||||
if (app.id == curapp.id) {
|
if (app.id.equals(curapp.id)) {
|
||||||
app.apks.addAll(curapp.apks);
|
app.apks.addAll(curapp.apks);
|
||||||
|
merged = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,19 +124,19 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
}
|
}
|
||||||
} else if (curel.equals("size")) {
|
} else if (curel.equals("size")) {
|
||||||
try {
|
try {
|
||||||
curapk.size = Integer.parseInt(str);
|
curapk.detail_size = Integer.parseInt(str);
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
curapk.size = 0;
|
curapk.detail_size = 0;
|
||||||
}
|
}
|
||||||
} else if (curel.equals("hash")) {
|
} else if (curel.equals("hash")) {
|
||||||
if (hashType == null || hashType.equals("md5")) {
|
if (hashType == null || hashType.equals("md5")) {
|
||||||
if (curapk.hash == null) {
|
if (curapk.detail_hash == null) {
|
||||||
curapk.hash = str;
|
curapk.detail_hash = str;
|
||||||
curapk.hashType = "MD5";
|
curapk.detail_hashType = "MD5";
|
||||||
}
|
}
|
||||||
} else if (hashType.equals("sha256")) {
|
} else if (hashType.equals("sha256")) {
|
||||||
curapk.hash = str;
|
curapk.detail_hash = str;
|
||||||
curapk.hashType = "SHA-256";
|
curapk.detail_hashType = "SHA-256";
|
||||||
}
|
}
|
||||||
} else if (curel.equals("sig")) {
|
} else if (curel.equals("sig")) {
|
||||||
curapk.sig = str;
|
curapk.sig = str;
|
||||||
@ -159,7 +160,7 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
curapk.added = null;
|
curapk.added = null;
|
||||||
}
|
}
|
||||||
} else if (curel.equals("permissions")) {
|
} else if (curel.equals("permissions")) {
|
||||||
curapk.permissions = DB.CommaSeparatedList.make(str);
|
curapk.detail_permissions = DB.CommaSeparatedList.make(str);
|
||||||
} else if (curel.equals("features")) {
|
} else if (curel.equals("features")) {
|
||||||
curapk.features = DB.CommaSeparatedList.make(str);
|
curapk.features = DB.CommaSeparatedList.make(str);
|
||||||
}
|
}
|
||||||
@ -171,7 +172,7 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
} else if (curel.equals("icon")) {
|
} else if (curel.equals("icon")) {
|
||||||
curapp.icon = str;
|
curapp.icon = str;
|
||||||
} else if (curel.equals("description")) {
|
} else if (curel.equals("description")) {
|
||||||
curapp.description = str;
|
curapp.detail_description = str;
|
||||||
} else if (curel.equals("summary")) {
|
} else if (curel.equals("summary")) {
|
||||||
curapp.summary = str;
|
curapp.summary = str;
|
||||||
} else if (curel.equals("license")) {
|
} else if (curel.equals("license")) {
|
||||||
@ -179,13 +180,13 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
} else if (curel.equals("category")) {
|
} else if (curel.equals("category")) {
|
||||||
curapp.category = str;
|
curapp.category = str;
|
||||||
} else if (curel.equals("source")) {
|
} else if (curel.equals("source")) {
|
||||||
curapp.sourceURL = str;
|
curapp.detail_sourceURL = str;
|
||||||
} else if (curel.equals("donate")) {
|
} else if (curel.equals("donate")) {
|
||||||
curapp.donateURL = str;
|
curapp.detail_donateURL = str;
|
||||||
} else if (curel.equals("web")) {
|
} else if (curel.equals("web")) {
|
||||||
curapp.webURL = str;
|
curapp.detail_webURL = str;
|
||||||
} else if (curel.equals("tracker")) {
|
} else if (curel.equals("tracker")) {
|
||||||
curapp.trackerURL = str;
|
curapp.detail_trackerURL = str;
|
||||||
} else if (curel.equals("added")) {
|
} else if (curel.equals("added")) {
|
||||||
try {
|
try {
|
||||||
curapp.added = str.length() == 0 ? null : mXMLDateFormat
|
curapp.added = str.length() == 0 ? null : mXMLDateFormat
|
||||||
@ -228,10 +229,11 @@ public class RepoXMLHandler extends DefaultHandler {
|
|||||||
pubkey = pk;
|
pubkey = pk;
|
||||||
} else if (localName == "application" && curapp == null) {
|
} else if (localName == "application" && curapp == null) {
|
||||||
curapp = new DB.App();
|
curapp = new DB.App();
|
||||||
|
curapp.detail_Populated = true;
|
||||||
} else if (localName == "package" && curapp != null && curapk == null) {
|
} else if (localName == "package" && curapp != null && curapk == null) {
|
||||||
curapk = new DB.Apk();
|
curapk = new DB.Apk();
|
||||||
curapk.id = curapp.id;
|
curapk.id = curapp.id;
|
||||||
curapk.server = server;
|
curapk.detail_server = server;
|
||||||
hashType = null;
|
hashType = null;
|
||||||
} else if (localName == "hash" && curapk != null) {
|
} else if (localName == "hash" && curapk != null) {
|
||||||
hashType = attributes.getValue("", "type");
|
hashType = attributes.getValue("", "type");
|
||||||
|
@ -32,7 +32,7 @@ import android.widget.ListView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class SearchResults extends ListActivity {
|
public class SearchResults extends ListActivity {
|
||||||
|
|
||||||
private static final int REQUEST_APPDETAILS = 0;
|
private static final int REQUEST_APPDETAILS = 0;
|
||||||
|
|
||||||
private static final int SEARCH = Menu.FIRST;
|
private static final int SEARCH = Menu.FIRST;
|
||||||
@ -40,7 +40,7 @@ public class SearchResults extends ListActivity {
|
|||||||
private AppListAdapter applist = new AppListAdapter(this);
|
private AppListAdapter applist = new AppListAdapter(this);
|
||||||
|
|
||||||
private String mQuery;
|
private String mQuery;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -68,37 +68,55 @@ public class SearchResults extends ListActivity {
|
|||||||
|
|
||||||
private void updateView() {
|
private void updateView() {
|
||||||
|
|
||||||
Vector<DB.App> apps= new Vector<DB.App>();
|
Vector<String> matchingids = new Vector<String>();
|
||||||
|
try {
|
||||||
|
DB db = DB.getDB();
|
||||||
|
matchingids = db.doSearch(mQuery);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.d("FDroid", "Search failed - " + ex.getMessage());
|
||||||
|
} finally {
|
||||||
|
DB.releaseDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<DB.App> apps = new Vector<DB.App>();
|
||||||
AppFilter appfilter = new AppFilter(this);
|
AppFilter appfilter = new AppFilter(this);
|
||||||
String mq = mQuery.toLowerCase();
|
|
||||||
Vector<DB.App> tapps = ((FDroidApp) getApplication()).getApps();
|
Vector<DB.App> tapps = ((FDroidApp) getApplication()).getApps();
|
||||||
for(DB.App tapp : tapps) {
|
for (DB.App tapp : tapps) {
|
||||||
if(tapp.name.toLowerCase().contains(mq) || tapp.description.toLowerCase().contains(mq)) {
|
boolean include = false;
|
||||||
if(!appfilter.filter(tapp))
|
for (String tid : matchingids) {
|
||||||
apps.add(tapp);
|
if (tid.equals(tapp.id)) {
|
||||||
|
include = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (include && !appfilter.filter(tapp))
|
||||||
|
apps.add(tapp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView tv = (TextView) findViewById(R.id.description);
|
TextView tv = (TextView) findViewById(R.id.description);
|
||||||
String headertext;
|
String headertext;
|
||||||
if(apps.size()==0)
|
if (apps.size() == 0)
|
||||||
headertext = String.format(getString(R.string.searchres_noapps),mQuery);
|
headertext = String.format(getString(R.string.searchres_noapps),
|
||||||
else if(apps.size()==1)
|
mQuery);
|
||||||
headertext = String.format(getString(R.string.searchres_oneapp),mQuery);
|
else if (apps.size() == 1)
|
||||||
|
headertext = String.format(getString(R.string.searchres_oneapp),
|
||||||
|
mQuery);
|
||||||
else
|
else
|
||||||
headertext = String.format(getString(R.string.searchres_napps),apps.size(),mQuery);
|
headertext = String.format(getString(R.string.searchres_napps),
|
||||||
|
apps.size(), mQuery);
|
||||||
tv.setText(headertext);
|
tv.setText(headertext);
|
||||||
Log.d("FDroid", "Search for '" + mQuery + "' returned "
|
Log.d("FDroid", "Search for '" + mQuery + "' returned " + apps.size()
|
||||||
+ apps.size() + " results");
|
+ " results");
|
||||||
applist.clear();
|
applist.clear();
|
||||||
for (DB.App app : apps) {
|
for (DB.App app : apps) {
|
||||||
applist.addItem(app);
|
applist.addItem(app);
|
||||||
}
|
}
|
||||||
applist.notifyDataSetChanged();
|
applist.notifyDataSetChanged();
|
||||||
setListAdapter(applist);
|
setListAdapter(applist);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
final DB.App app;
|
final DB.App app;
|
||||||
@ -127,10 +145,9 @@ public class SearchResults extends ListActivity {
|
|||||||
case SEARCH:
|
case SEARCH:
|
||||||
onSearchRequested();
|
onSearchRequested();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,8 @@ public class UpdateService extends IntentService {
|
|||||||
|
|
||||||
// See if it's time to actually do anything yet...
|
// See if it's time to actually do anything yet...
|
||||||
if (receiver == null) {
|
if (receiver == null) {
|
||||||
long lastUpdate = prefs.getLong("lastUpdateCheck", 0);
|
long lastUpdate = prefs.getLong("lastUpdateCheck",
|
||||||
|
System.currentTimeMillis());
|
||||||
String sint = prefs.getString("updateInterval", "0");
|
String sint = prefs.getString("updateInterval", "0");
|
||||||
int interval = Integer.parseInt(sint);
|
int interval = Integer.parseInt(sint);
|
||||||
if (interval == 0)
|
if (interval == 0)
|
||||||
@ -127,7 +128,8 @@ public class UpdateService extends IntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
Vector<DB.App> prevapps = ((FDroidApp)getApplication()).getApps();
|
Vector<DB.App> prevapps = ((FDroidApp) getApplication())
|
||||||
|
.getApps();
|
||||||
db = DB.getDB();
|
db = DB.getDB();
|
||||||
try {
|
try {
|
||||||
prevUpdates = db.beginUpdate(prevapps);
|
prevUpdates = db.beginUpdate(prevapps);
|
||||||
@ -135,7 +137,7 @@ public class UpdateService extends IntentService {
|
|||||||
db.updateApplication(app);
|
db.updateApplication(app);
|
||||||
}
|
}
|
||||||
db.endUpdate();
|
db.endUpdate();
|
||||||
((FDroidApp)getApplication()).invalidateApps();
|
((FDroidApp) getApplication()).invalidateApps();
|
||||||
if (notify)
|
if (notify)
|
||||||
newUpdates = db.getNumUpdates();
|
newUpdates = db.getNumUpdates();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user