Re-implement show incompatible, and fix details layout more

This commit is contained in:
Ciaran Gultnieks 2012-09-19 17:06:49 +01:00
parent 006ee57bbf
commit 2ae4e6516e
6 changed files with 143 additions and 75 deletions

View File

@ -4,6 +4,7 @@
<string name="searchres_oneapp">Found one application matching \'%s\':</string> <string name="searchres_oneapp">Found one application matching \'%s\':</string>
<string name="searchres_noapps">No applications were found matching \'%s\'</string> <string name="searchres_noapps">No applications were found matching \'%s\'</string>
<string name="SignatureMismatch">The new version is signed with a different key to the old one. To install the new version, the old one must be uninstalled first. Please do this and try again. (Note that uninstalling will erase any internal data stored by the application)</string> <string name="SignatureMismatch">The new version is signed with a different key to the old one. To install the new version, the old one must be uninstalled first. Please do this and try again. (Note that uninstalling will erase any internal data stored by the application)</string>
<string name="installIncompatible">Android says this package is not compatible with your device. Do you want to try and install it anyway?</string>
<string name="version">Version</string> <string name="version">Version</string>
<string name="n_versions_available">%d versions available</string> <string name="n_versions_available">%d versions available</string>
<string name="n_version_available">%d version available</string> <string name="n_version_available">%d version available</string>

View File

@ -37,6 +37,9 @@
android:key="antiNonFreeDep" /> android:key="antiNonFreeDep" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/appcompatibility"> <PreferenceCategory android:title="@string/appcompatibility">
<CheckBoxPreference android:title="@string/showincompat"
android:defaultValue="false" android:summary="@string/showincompat_long"
android:key="showIncompatible" />
<CheckBoxPreference android:title="@string/rooted" <CheckBoxPreference android:title="@string/rooted"
android:defaultValue="true" android:summary="@string/rooted_long" android:defaultValue="true" android:summary="@string/rooted_long"
android:key="rooted" /> android:key="rooted" />

View File

@ -136,6 +136,15 @@ public class AppDetails extends ListActivity {
} else { } else {
added.setVisibility(View.GONE); added.setVisibility(View.GONE);
} }
// Disable it all if it isn't compatible...
if (!apk.compatible) {
View[] views = { v, version, status, size, buildtype, added };
for (View view : views) {
view.setEnabled(false);
}
}
return v; return v;
} }
} }
@ -167,8 +176,9 @@ public class AppDetails extends ListActivity {
private DownloadHandler downloadHandler; private DownloadHandler downloadHandler;
private boolean stateRetained; private boolean stateRetained;
private Context mctx = this; LinearLayout headerView;
private Context mctx = this;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -190,6 +200,13 @@ public class AppDetails extends ListActivity {
appid = i.getStringExtra("appid"); appid = i.getStringExtra("appid");
} }
// Set up the list...
headerView = new LinearLayout(this);
ListView lv = (ListView) findViewById(android.R.id.list);
lv.addHeaderView(headerView);
ApkListAdapter la = new ApkListAdapter(this, null);
setListAdapter(la);
} }
private boolean pref_cacheDownloaded; private boolean pref_cacheDownloaded;
@ -263,8 +280,6 @@ public class AppDetails extends ListActivity {
// place of reset(), so it must initialize all fields normally set // place of reset(), so it must initialize all fields normally set
// there. // there.
private void copyState(AppDetails old) { private void copyState(AppDetails old) {
ApkListAdapter oldAdapter = (ApkListAdapter) old.getListAdapter();
setListAdapter(new ApkListAdapter(this, oldAdapter.getItems()));
if (old.downloadHandler != null) if (old.downloadHandler != null)
downloadHandler = new DownloadHandler(old.downloadHandler); downloadHandler = new DownloadHandler(old.downloadHandler);
app = old.app; app = old.app;
@ -328,9 +343,11 @@ public class AppDetails extends ListActivity {
private void resetViews() { private void resetViews() {
// Clear the listadapter, because we can't mess with the listview's // Repopulate the list...
// header view while it's set. ApkListAdapter la = (ApkListAdapter) getListAdapter();
setListAdapter(null); la.items.clear();
for (DB.Apk apk : app.apks)
la.addItem(apk);
// Insert the 'infoView' (which contains the summary, various odds and // Insert the 'infoView' (which contains the summary, various odds and
// ends, and the description) into the appropriate place, if we're in // ends, and the description) into the appropriate place, if we're in
@ -338,19 +355,15 @@ public class AppDetails extends ListActivity {
// header.. // header..
View infoView = View.inflate(this, R.layout.appinfo, null); View infoView = View.inflate(this, R.layout.appinfo, null);
LinearLayout landparent = (LinearLayout) findViewById(R.id.landleft); LinearLayout landparent = (LinearLayout) findViewById(R.id.landleft);
ListView lv = (ListView) findViewById(android.R.id.list); headerView.removeAllViews();
if (landparent != null) { if (landparent != null) {
landparent.addView(infoView); landparent.addView(infoView);
Log.d("FDroid", "Setting landparent infoview");
} else { } else {
lv.addHeaderView(infoView); headerView.addView(infoView);
Log.d("FDroid", "Setting header infoview");
} }
// Set up the list...
ApkListAdapter la = new ApkListAdapter(this, null);
for (DB.Apk apk : app.apks)
la.addItem(apk);
setListAdapter(la);
// 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(), app.icon); File icon = new File(DB.getIconsPath(), app.icon);
@ -427,7 +440,7 @@ public class AppDetails extends ListActivity {
@Override @Override
protected void onListItemClick(ListView l, View v, int position, long id) { protected void onListItemClick(ListView l, View v, int position, long id) {
curapk = app.apks.get(position); curapk = app.apks.get(position - l.getHeaderViewsCount());
if (app.installedVersion != null if (app.installedVersion != null
&& app.installedVersion.equals(curapk.version)) { && app.installedVersion.equals(curapk.version)) {
removeApk(app.id); removeApk(app.id);
@ -525,6 +538,27 @@ public class AppDetails extends ListActivity {
// Install the version of this app denoted by 'curapk'. // Install the version of this app denoted by 'curapk'.
private void install() { private void install() {
if(!curapk.compatible) {
AlertDialog.Builder ask_alrt = new AlertDialog.Builder(this);
ask_alrt.setMessage(getString(R.string.installIncompatible));
ask_alrt.setPositiveButton(getString(R.string.yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
downloadHandler = new DownloadHandler(curapk);
}
});
ask_alrt.setNegativeButton(getString(R.string.no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
return;
}
});
AlertDialog alert = ask_alrt.create();
alert.show();
return;
}
if (mInstalledSigID != null && curapk.sig != null if (mInstalledSigID != null && curapk.sig != null
&& !curapk.sig.equals(mInstalledSigID)) { && !curapk.sig.equals(mInstalledSigID)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);

View File

@ -90,6 +90,14 @@ public class AppListAdapter extends BaseAdapter {
icon.setImageResource(android.R.drawable.sym_def_app_icon); icon.setImageResource(android.R.drawable.sym_def_app_icon);
} }
// Disable it all if it isn't compatible...
if (!app.compatible) {
View[] views = { v, status, summary, license, name };
for (View view : views) {
view.setEnabled(false);
}
}
return v; return v;
} }

View File

@ -94,7 +94,8 @@ public class DB {
+ "curVersion text," + "curVercode integer," + "curVersion text," + "curVercode integer,"
+ "antiFeatures string," + "donateURL string," + "antiFeatures string," + "donateURL string,"
+ "requirements string," + "category string," + "added string," + "requirements string," + "category string," + "added string,"
+ "lastUpdated string," + "primary key(id));"; + "lastUpdated string," + "compatible int not null,"
+ "primary key(id));";
public static class App implements Comparable<App> { public static class App implements Comparable<App> {
@ -117,11 +118,15 @@ public class DB {
lastUpdated = null; lastUpdated = null;
apks = new Vector<Apk>(); apks = new Vector<Apk>();
detail_Populated = false; detail_Populated = false;
compatible = false;
} }
// True when all the detail fields are populated, False otherwise. // True when all the detail fields are populated, False otherwise.
public boolean detail_Populated; public boolean detail_Populated;
// True if compatible with the device (i.e. if at least one apk is)
public boolean compatible;
public String id; public String id;
public String name; public String name;
public String summary; public String summary;
@ -224,7 +229,8 @@ public class DB {
+ "size int not null," + "apkSource text," + "sig string," + "size int not null," + "apkSource text," + "sig string,"
+ "srcname string," + "minSdkVersion integer," + "srcname string," + "minSdkVersion integer,"
+ "permissions string," + "features string," + "hashType string," + "permissions string," + "features string," + "hashType string,"
+ "added string," + "primary key(id,vercode));"; + "added string," + "compatible int not null,"
+ "primary key(id,vercode));";
public static class Apk { public static class Apk {
@ -237,6 +243,7 @@ public class DB {
detail_hash = null; detail_hash = null;
detail_hashType = null; detail_hashType = null;
detail_permissions = null; detail_permissions = null;
compatible = false;
} }
public String id; public String id;
@ -256,6 +263,9 @@ public class DB {
// transition to this field existing. // transition to this field existing.
public String sig; public String sig;
// True if compatible with the device.
public boolean compatible;
public String apkName; public String apkName;
// If null, the apk comes from the same server as the repo index. // If null, the apk comes from the same server as the repo index.
@ -363,7 +373,7 @@ public class DB {
public String pubkey; // null for an unsigned repo public String pubkey; // null for an unsigned repo
} }
private final int DBVersion = 17; private final int DBVersion = 18;
private static void createAppApk(SQLiteDatabase db) { private static void createAppApk(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_APP); db.execSQL(CREATE_TABLE_APP);
@ -578,7 +588,8 @@ public class DB {
String cols[] = new String[] { "antiFeatures", "requirements", String cols[] = new String[] { "antiFeatures", "requirements",
"id", "name", "summary", "icon", "license", "category", "id", "name", "summary", "icon", "license", "category",
"curVersion", "curVercode", "added", "lastUpdated" }; "curVersion", "curVercode", "added", "lastUpdated",
"compatible" };
c = db.query(TABLE_APP, cols, null, null, null, null, null); c = db.query(TABLE_APP, cols, null, null, null, null, null);
c.moveToFirst(); c.moveToFirst();
while (!c.isAfterLast()) { while (!c.isAfterLast()) {
@ -601,6 +612,7 @@ public class DB {
app.lastUpdated = (sLastUpdated == null || sLastUpdated app.lastUpdated = (sLastUpdated == null || sLastUpdated
.length() == 0) ? null : mDateFormat .length() == 0) ? null : mDateFormat
.parse(sLastUpdated); .parse(sLastUpdated);
app.compatible = c.getInt(12) == 1;
app.hasUpdates = false; app.hasUpdates = false;
if (getinstalledinfo && systemApks.containsKey(app.id)) { if (getinstalledinfo && systemApks.containsKey(app.id)) {
@ -624,7 +636,7 @@ public class DB {
cols = new String[] { "id", "version", "vercode", "sig", "srcname", cols = new String[] { "id", "version", "vercode", "sig", "srcname",
"apkName", "apkSource", "minSdkVersion", "added", "apkName", "apkSource", "minSdkVersion", "added",
"features" }; "features", "compatible" };
c = db.query(TABLE_APK, cols, null, null, null, null, c = db.query(TABLE_APK, cols, null, null, null, null,
"vercode desc"); "vercode desc");
c.moveToFirst(); c.moveToFirst();
@ -642,6 +654,7 @@ public class DB {
apk.added = (sApkAdded == null || sApkAdded.length() == 0) ? null apk.added = (sApkAdded == null || sApkAdded.length() == 0) ? null
: mDateFormat.parse(sApkAdded); : mDateFormat.parse(sApkAdded);
apk.features = CommaSeparatedList.make(c.getString(9)); apk.features = CommaSeparatedList.make(c.getString(9));
apk.compatible = c.getInt(10) == 1;
apps.get(apk.id).apks.add(apk); apps.get(apk.id).apks.add(apk);
c.moveToNext(); c.moveToNext();
} }
@ -821,14 +834,25 @@ public class DB {
if (compatChecker == null) if (compatChecker == null)
compatChecker = Apk.CompatibilityChecker.getChecker(mContext); compatChecker = Apk.CompatibilityChecker.getChecker(mContext);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(mContext);
boolean prefCompat = prefs.getBoolean("showIncompatible", false);
// See if it's compatible (by which we mean if it has at least one // See if it's compatible (by which we mean if it has at least one
// compatible apk - if it's not, leave it out) // compatible apk - if it's not, leave it out)
// Also keep a list of which were compatible, because they're the // Also keep a list of which were compatible, because they're the
// only ones we'll add. // only ones we'll add, unless the showIncompatible preference is set.
Vector<Apk> compatibleapks = new Vector<Apk>(); Vector<Apk> compatibleapks = new Vector<Apk>();
for (Apk apk : upapp.apks) for (Apk apk : upapp.apks) {
if (compatChecker.isCompatible(apk)) if (compatChecker.isCompatible(apk)) {
apk.compatible = true;
compatibleapks.add(apk); compatibleapks.add(apk);
}
}
if (compatibleapks.size() > 0)
upapp.compatible = true;
if (prefCompat)
compatibleapks = upapp.apks;
if (compatibleapks.size() == 0) if (compatibleapks.size() == 0)
return false; return false;
@ -902,6 +926,7 @@ public class DB {
values.put("curVercode", upapp.curVercode); values.put("curVercode", upapp.curVercode);
values.put("antiFeatures", CommaSeparatedList.str(upapp.antiFeatures)); values.put("antiFeatures", CommaSeparatedList.str(upapp.antiFeatures));
values.put("requirements", CommaSeparatedList.str(upapp.requirements)); values.put("requirements", CommaSeparatedList.str(upapp.requirements));
values.put("compatible", upapp.compatible ? 1 : 0);
if (oldapp != null) { if (oldapp != null) {
db.update(TABLE_APP, values, "id = ?", new String[] { oldapp.id }); db.update(TABLE_APP, values, "id = ?", new String[] { oldapp.id });
} else { } else {
@ -934,6 +959,7 @@ public class DB {
values.put("permissions", values.put("permissions",
CommaSeparatedList.str(upapk.detail_permissions)); CommaSeparatedList.str(upapk.detail_permissions));
values.put("features", CommaSeparatedList.str(upapk.features)); values.put("features", CommaSeparatedList.str(upapk.features));
values.put("compatible", upapk.compatible ? 1 : 0);
if (oldapk != null) { if (oldapk != null) {
db.update(TABLE_APK, values, db.update(TABLE_APK, values,
"id = ? and vercode = " + Integer.toString(oldapk.vercode), "id = ? and vercode = " + Integer.toString(oldapk.vercode),

View File

@ -27,18 +27,40 @@ import android.preference.PreferenceActivity;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.widget.Toast; import android.widget.Toast;
public class Preferences extends PreferenceActivity { public class Preferences extends PreferenceActivity implements
OnPreferenceClickListener {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
for (String prefkey : new String[] { "reset", "ignoreTouchscreen",
"showIncompatible" }) {
Preference pref = findPreference(prefkey);
pref.setOnPreferenceClickListener(this);
}
}
Preference r = (Preference) findPreference("reset"); private void deleteAll(File dir) {
r.setOnPreferenceClickListener(new OnPreferenceClickListener() {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
deleteAll(new File(dir, children[i]));
}
}
dir.delete();
}
@Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
String key = preference.getKey();
if (key.equals("ignoreTouchscreen") || key.equals("showIncompatible")) {
Intent ret = new Intent();
ret.putExtra("update", true);
setResult(RESULT_OK, ret);
return true;
} else if (key.equals("reset")) {
// TODO: Progress dialog + thread is needed, it can take a // TODO: Progress dialog + thread is needed, it can take a
// while to delete all the icons and cached apks in a long // while to delete all the icons and cached apks in a long
// standing install! // standing install!
@ -68,33 +90,7 @@ public class Preferences extends PreferenceActivity {
finish(); finish();
return true; return true;
} }
return false;
});
r = (Preference) findPreference("ignoreTouchscreen");
r.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent ret = new Intent();
ret.putExtra("update", true);
setResult(RESULT_OK, ret);
return true;
} }
});
}
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();
}
} }