Fixed issues with api version differences.
I moved the Utils.hasApi to the protected method in Compatibility. It was misleading having it in Utils, because it is not as simple as putting a "if(Utils.hasApi(11)) callApi_11_method()" there. The problem isn't when the method is executed during runtime, it is when the class is loaded into the VM using the classloader. At that point, it tries to verify that indeed every method you call from your class exists, so the conditional check doesn't work, hence VerifyError's and breakage. The appropriate way to do it is the same way as the Android support library does it. The goal is to have an interface which only one implementation is every loaded at runtime. Any implementations for versions that your device doesn't support will never get loaded, so no VerifyErrors. If you have the support library installed in your Android SDK, check out extras/android/support/v4/src/java/android/support/v4/view/MenuItemCompat.java to see how the pattern works.
This commit is contained in:
parent
d2e2b492fb
commit
c8fa5303c4
@ -26,6 +26,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
import org.fdroid.fdroid.compat.MenuManager;
|
||||
import org.fdroid.fdroid.DB.CommaSeparatedList;
|
||||
import org.xml.sax.XMLReader;
|
||||
@ -182,10 +183,9 @@ public class AppDetails extends ListActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Utils.hasApi(11)) {
|
||||
getActionBar().setDisplayShowTitleEnabled(false);
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
ActionBarCompat abCompat = ActionBarCompat.create(this);
|
||||
abCompat.setDisplayHomeAsUpEnabled(true);
|
||||
abCompat.setDisplayShowTitleEnabled(false);
|
||||
|
||||
setContentView(R.layout.appdetails);
|
||||
|
||||
|
@ -45,6 +45,8 @@ import android.os.Environment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils.SimpleStringSplitter;
|
||||
import android.util.Log;
|
||||
import org.fdroid.fdroid.compat.Compatibility;
|
||||
import org.fdroid.fdroid.compat.ContextCompat;
|
||||
|
||||
public class DB {
|
||||
|
||||
@ -275,25 +277,25 @@ public class DB {
|
||||
|
||||
// Call isCompatible(apk) on an instance of this class to
|
||||
// check if an APK is compatible with the user's device.
|
||||
public static abstract class CompatibilityChecker {
|
||||
public static abstract class CompatibilityChecker extends Compatibility {
|
||||
|
||||
public abstract boolean isCompatible(Apk apk);
|
||||
|
||||
public static CompatibilityChecker getChecker(Context ctx) {
|
||||
CompatibilityChecker checker;
|
||||
if (Utils.hasApi(5))
|
||||
if (hasApi(5))
|
||||
checker = new EclairChecker(ctx);
|
||||
else
|
||||
checker = new BasicChecker();
|
||||
Log.d("FDroid", "Compatibility checker for API level "
|
||||
+ Utils.getApi() + ": " + checker.getClass().getName());
|
||||
+ getApi() + ": " + checker.getClass().getName());
|
||||
return checker;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BasicChecker extends CompatibilityChecker {
|
||||
public boolean isCompatible(Apk apk) {
|
||||
return (apk.minSdkVersion <= Utils.getApi());
|
||||
return hasApi(apk.minSdkVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +325,7 @@ public class DB {
|
||||
}
|
||||
|
||||
public boolean isCompatible(Apk apk) {
|
||||
if (apk.minSdkVersion > Utils.getApi())
|
||||
if (!hasApi(apk.minSdkVersion))
|
||||
return false;
|
||||
if (apk.features != null) {
|
||||
for (String feat : apk.features) {
|
||||
@ -485,21 +487,12 @@ public class DB {
|
||||
|
||||
}
|
||||
|
||||
// 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.
|
||||
/**
|
||||
* 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) {
|
||||
File f;
|
||||
if (Utils.hasApi(8)) {
|
||||
f = ctx.getExternalCacheDir();
|
||||
} else {
|
||||
f = new File(Environment.getExternalStorageDirectory(),
|
||||
"Android/data/org.fdroid.fdroid/cache");
|
||||
if(f != null) {
|
||||
if(!f.exists())
|
||||
f.mkdirs();
|
||||
}
|
||||
}
|
||||
return f;
|
||||
return ContextCompat.create(ctx).getExternalCacheDir();
|
||||
}
|
||||
|
||||
public static File getIconsPath(Context ctx) {
|
||||
|
@ -27,6 +27,7 @@ import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.widget.Toast;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
|
||||
public class Preferences extends PreferenceActivity implements
|
||||
OnPreferenceClickListener {
|
||||
@ -34,8 +35,7 @@ public class Preferences extends PreferenceActivity implements
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Utils.hasApi(11))
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
for (String prefkey : new String[] { "reset", "ignoreTouchscreen",
|
||||
"showIncompatible" }) {
|
||||
|
@ -34,6 +34,7 @@ import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||
import org.fdroid.fdroid.views.AppListAdapter;
|
||||
import org.fdroid.fdroid.views.AvailableAppListAdapter;
|
||||
|
||||
@ -50,8 +51,7 @@ public class SearchResults extends ListActivity {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (Utils.hasApi(11))
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||
applist = new AvailableAppListAdapter(this);
|
||||
setContentView(R.layout.searchresults);
|
||||
|
||||
|
@ -18,8 +18,6 @@
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
@ -73,14 +71,6 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasApi(int apiLevel) {
|
||||
return Build.VERSION.SDK_INT >= apiLevel;
|
||||
}
|
||||
|
||||
public static int getApi() {
|
||||
return Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
public static String getFriendlySize(int size) {
|
||||
double s = size;
|
||||
int i = 0;
|
||||
|
62
src/org/fdroid/fdroid/compat/ActionBarCompat.java
Normal file
62
src/org/fdroid/fdroid/compat/ActionBarCompat.java
Normal file
@ -0,0 +1,62 @@
|
||||
package org.fdroid.fdroid.compat;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
|
||||
public abstract class ActionBarCompat extends Compatibility {
|
||||
|
||||
public static ActionBarCompat create(Activity activity) {
|
||||
if (hasApi(11)) {
|
||||
return new HoneycombActionBarCompatImpl(activity);
|
||||
} else {
|
||||
return new OldActionBarCompatImpl(activity);
|
||||
}
|
||||
}
|
||||
|
||||
protected final Activity activity;
|
||||
|
||||
public ActionBarCompat(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
public abstract void setDisplayHomeAsUpEnabled(boolean value);
|
||||
public abstract void setDisplayShowTitleEnabled(boolean value);
|
||||
|
||||
}
|
||||
|
||||
class OldActionBarCompatImpl extends ActionBarCompat {
|
||||
|
||||
public OldActionBarCompatImpl(Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayHomeAsUpEnabled(boolean value) {
|
||||
// Do nothing...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowTitleEnabled(boolean value) {
|
||||
// Do nothing...
|
||||
}
|
||||
}
|
||||
|
||||
class HoneycombActionBarCompatImpl extends ActionBarCompat {
|
||||
|
||||
private final ActionBar actionBar;
|
||||
|
||||
public HoneycombActionBarCompatImpl(Activity activity) {
|
||||
super(activity);
|
||||
this.actionBar = activity.getActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayHomeAsUpEnabled(boolean value) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowTitleEnabled(boolean value) {
|
||||
actionBar.setDisplayShowTitleEnabled(value);
|
||||
}
|
||||
}
|
16
src/org/fdroid/fdroid/compat/Compatibility.java
Normal file
16
src/org/fdroid/fdroid/compat/Compatibility.java
Normal file
@ -0,0 +1,16 @@
|
||||
package org.fdroid.fdroid.compat;
|
||||
|
||||
import android.os.Build;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
|
||||
public abstract class Compatibility {
|
||||
|
||||
protected static boolean hasApi(int apiLevel) {
|
||||
return getApi() >= apiLevel;
|
||||
}
|
||||
|
||||
protected static int getApi() {
|
||||
return Build.VERSION.SDK_INT;
|
||||
}
|
||||
|
||||
}
|
59
src/org/fdroid/fdroid/compat/ContextCompat.java
Normal file
59
src/org/fdroid/fdroid/compat/ContextCompat.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.fdroid.fdroid.compat;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class ContextCompat extends Compatibility {
|
||||
|
||||
public static ContextCompat create(Context context) {
|
||||
if (hasApi(8)) {
|
||||
return new FroyoContextCompatImpl(context);
|
||||
} else {
|
||||
return new OldContextCompatImpl(context);
|
||||
}
|
||||
}
|
||||
|
||||
protected final Context context;
|
||||
|
||||
public ContextCompat(Context context ) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.content.Context#getExternalCacheDir()
|
||||
*/
|
||||
public abstract File getExternalCacheDir();
|
||||
|
||||
}
|
||||
|
||||
class OldContextCompatImpl extends ContextCompat {
|
||||
|
||||
public OldContextCompatImpl(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getExternalCacheDir() {
|
||||
File file = new File(Environment.getExternalStorageDirectory(),
|
||||
"Android/data/org.fdroid.fdroid/cache");
|
||||
if(!file.exists())
|
||||
file.mkdirs();
|
||||
return file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FroyoContextCompatImpl extends ContextCompat {
|
||||
|
||||
public FroyoContextCompatImpl(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getExternalCacheDir() {
|
||||
return context.getExternalCacheDir();
|
||||
}
|
||||
|
||||
}
|
39
src/org/fdroid/fdroid/compat/LayoutCompat.java
Normal file
39
src/org/fdroid/fdroid/compat/LayoutCompat.java
Normal file
@ -0,0 +1,39 @@
|
||||
package org.fdroid.fdroid.compat;
|
||||
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
public abstract class LayoutCompat extends Compatibility {
|
||||
|
||||
public static LayoutCompat create() {
|
||||
if (hasApi(17)) {
|
||||
return new JellyBeanMr1LayoutCompatImpl();
|
||||
} else {
|
||||
return new OldLayoutCompatImpl();
|
||||
}
|
||||
}
|
||||
|
||||
private static final LayoutCompat impl = LayoutCompat.create();
|
||||
|
||||
protected abstract int relativeLayoutEndOf();
|
||||
|
||||
public static class RelativeLayout {
|
||||
public static final int END_OF = impl.relativeLayoutEndOf();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class OldLayoutCompatImpl extends LayoutCompat {
|
||||
|
||||
@Override
|
||||
protected int relativeLayoutEndOf() {
|
||||
return android.widget.RelativeLayout.RIGHT_OF;
|
||||
}
|
||||
}
|
||||
|
||||
class JellyBeanMr1LayoutCompatImpl extends LayoutCompat {
|
||||
|
||||
@Override
|
||||
protected int relativeLayoutEndOf() {
|
||||
return android.widget.RelativeLayout.END_OF;
|
||||
}
|
||||
}
|
@ -3,10 +3,10 @@ package org.fdroid.fdroid.compat;
|
||||
import android.app.Activity;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
|
||||
abstract public class MenuManager {
|
||||
abstract public class MenuManager extends Compatibility {
|
||||
|
||||
public static MenuManager create(Activity activity) {
|
||||
if (Utils.hasApi(11)) {
|
||||
if (hasApi(11)) {
|
||||
return new HoneycombMenuManagerImpl(activity);
|
||||
} else {
|
||||
return new OldMenuManagerImpl(activity);
|
||||
|
@ -14,14 +14,14 @@ import org.fdroid.fdroid.Utils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TabManager {
|
||||
public abstract class TabManager extends Compatibility {
|
||||
|
||||
public static final int INDEX_AVAILABLE = 0;
|
||||
public static final int INDEX_INSTALLED = 1;
|
||||
public static final int INDEX_CAN_UPDATE = 2;
|
||||
|
||||
public static TabManager create(FDroid parent, ViewPager pager) {
|
||||
if (Utils.hasApi(11)) {
|
||||
if (hasApi(11)) {
|
||||
return new HoneycombTabManagerImpl(parent, pager);
|
||||
} else {
|
||||
return new OldTabManagerImpl(parent, pager);
|
||||
|
@ -16,6 +16,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import org.fdroid.fdroid.DB;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.compat.LayoutCompat;
|
||||
|
||||
abstract public class AppListAdapter extends BaseAdapter {
|
||||
|
||||
@ -110,10 +111,7 @@ abstract public class AppListAdapter extends BaseAdapter {
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||
summaryLayout.addRule(RelativeLayout.BELOW, R.id.name);
|
||||
if (Utils.hasApi(17))
|
||||
summaryLayout.addRule(RelativeLayout.END_OF, R.id.icon);
|
||||
else
|
||||
summaryLayout.addRule(RelativeLayout.RIGHT_OF, R.id.icon);
|
||||
summaryLayout.addRule(LayoutCompat.RelativeLayout.END_OF, R.id.icon);
|
||||
summary.setLayoutParams(summaryLayout);
|
||||
summary.setPadding(0,0,0,0);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user