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 java.util.List;
|
||||||
|
|
||||||
import android.support.v4.view.MenuItemCompat;
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||||
import org.fdroid.fdroid.compat.MenuManager;
|
import org.fdroid.fdroid.compat.MenuManager;
|
||||||
import org.fdroid.fdroid.DB.CommaSeparatedList;
|
import org.fdroid.fdroid.DB.CommaSeparatedList;
|
||||||
import org.xml.sax.XMLReader;
|
import org.xml.sax.XMLReader;
|
||||||
@ -182,10 +183,9 @@ public class AppDetails extends ListActivity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (Utils.hasApi(11)) {
|
ActionBarCompat abCompat = ActionBarCompat.create(this);
|
||||||
getActionBar().setDisplayShowTitleEnabled(false);
|
abCompat.setDisplayHomeAsUpEnabled(true);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
abCompat.setDisplayShowTitleEnabled(false);
|
||||||
}
|
|
||||||
|
|
||||||
setContentView(R.layout.appdetails);
|
setContentView(R.layout.appdetails);
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ import android.os.Environment;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils.SimpleStringSplitter;
|
import android.text.TextUtils.SimpleStringSplitter;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import org.fdroid.fdroid.compat.Compatibility;
|
||||||
|
import org.fdroid.fdroid.compat.ContextCompat;
|
||||||
|
|
||||||
public class DB {
|
public class DB {
|
||||||
|
|
||||||
@ -275,25 +277,25 @@ public class DB {
|
|||||||
|
|
||||||
// Call isCompatible(apk) on an instance of this class to
|
// Call isCompatible(apk) on an instance of this class to
|
||||||
// check if an APK is compatible with the user's device.
|
// 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 abstract boolean isCompatible(Apk apk);
|
||||||
|
|
||||||
public static CompatibilityChecker getChecker(Context ctx) {
|
public static CompatibilityChecker getChecker(Context ctx) {
|
||||||
CompatibilityChecker checker;
|
CompatibilityChecker checker;
|
||||||
if (Utils.hasApi(5))
|
if (hasApi(5))
|
||||||
checker = new EclairChecker(ctx);
|
checker = new EclairChecker(ctx);
|
||||||
else
|
else
|
||||||
checker = new BasicChecker();
|
checker = new BasicChecker();
|
||||||
Log.d("FDroid", "Compatibility checker for API level "
|
Log.d("FDroid", "Compatibility checker for API level "
|
||||||
+ Utils.getApi() + ": " + checker.getClass().getName());
|
+ getApi() + ": " + checker.getClass().getName());
|
||||||
return checker;
|
return checker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BasicChecker extends CompatibilityChecker {
|
private static class BasicChecker extends CompatibilityChecker {
|
||||||
public boolean isCompatible(Apk apk) {
|
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) {
|
public boolean isCompatible(Apk apk) {
|
||||||
if (apk.minSdkVersion > Utils.getApi())
|
if (!hasApi(apk.minSdkVersion))
|
||||||
return false;
|
return false;
|
||||||
if (apk.features != null) {
|
if (apk.features != null) {
|
||||||
for (String feat : apk.features) {
|
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) {
|
public static File getDataPath(Context ctx) {
|
||||||
File f;
|
return ContextCompat.create(ctx).getExternalCacheDir();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File getIconsPath(Context ctx) {
|
public static File getIconsPath(Context ctx) {
|
||||||
|
@ -27,6 +27,7 @@ import android.preference.Preference;
|
|||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.Preference.OnPreferenceClickListener;
|
import android.preference.Preference.OnPreferenceClickListener;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||||
|
|
||||||
public class Preferences extends PreferenceActivity implements
|
public class Preferences extends PreferenceActivity implements
|
||||||
OnPreferenceClickListener {
|
OnPreferenceClickListener {
|
||||||
@ -34,8 +35,7 @@ public class Preferences extends PreferenceActivity implements
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (Utils.hasApi(11))
|
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
for (String prefkey : new String[] { "reset", "ignoreTouchscreen",
|
for (String prefkey : new String[] { "reset", "ignoreTouchscreen",
|
||||||
"showIncompatible" }) {
|
"showIncompatible" }) {
|
||||||
|
@ -34,6 +34,7 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import org.fdroid.fdroid.compat.ActionBarCompat;
|
||||||
import org.fdroid.fdroid.views.AppListAdapter;
|
import org.fdroid.fdroid.views.AppListAdapter;
|
||||||
import org.fdroid.fdroid.views.AvailableAppListAdapter;
|
import org.fdroid.fdroid.views.AvailableAppListAdapter;
|
||||||
|
|
||||||
@ -50,8 +51,7 @@ public class SearchResults extends ListActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (Utils.hasApi(11))
|
ActionBarCompat.create(this).setDisplayHomeAsUpEnabled(true);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
applist = new AvailableAppListAdapter(this);
|
applist = new AvailableAppListAdapter(this);
|
||||||
setContentView(R.layout.searchresults);
|
setContentView(R.layout.searchresults);
|
||||||
|
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
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) {
|
public static String getFriendlySize(int size) {
|
||||||
double s = size;
|
double s = size;
|
||||||
int i = 0;
|
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 android.app.Activity;
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
|
|
||||||
abstract public class MenuManager {
|
abstract public class MenuManager extends Compatibility {
|
||||||
|
|
||||||
public static MenuManager create(Activity activity) {
|
public static MenuManager create(Activity activity) {
|
||||||
if (Utils.hasApi(11)) {
|
if (hasApi(11)) {
|
||||||
return new HoneycombMenuManagerImpl(activity);
|
return new HoneycombMenuManagerImpl(activity);
|
||||||
} else {
|
} else {
|
||||||
return new OldMenuManagerImpl(activity);
|
return new OldMenuManagerImpl(activity);
|
||||||
|
@ -14,14 +14,14 @@ import org.fdroid.fdroid.Utils;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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_AVAILABLE = 0;
|
||||||
public static final int INDEX_INSTALLED = 1;
|
public static final int INDEX_INSTALLED = 1;
|
||||||
public static final int INDEX_CAN_UPDATE = 2;
|
public static final int INDEX_CAN_UPDATE = 2;
|
||||||
|
|
||||||
public static TabManager create(FDroid parent, ViewPager pager) {
|
public static TabManager create(FDroid parent, ViewPager pager) {
|
||||||
if (Utils.hasApi(11)) {
|
if (hasApi(11)) {
|
||||||
return new HoneycombTabManagerImpl(parent, pager);
|
return new HoneycombTabManagerImpl(parent, pager);
|
||||||
} else {
|
} else {
|
||||||
return new OldTabManagerImpl(parent, pager);
|
return new OldTabManagerImpl(parent, pager);
|
||||||
|
@ -16,6 +16,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.*;
|
import android.widget.*;
|
||||||
import org.fdroid.fdroid.DB;
|
import org.fdroid.fdroid.DB;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
|
import org.fdroid.fdroid.compat.LayoutCompat;
|
||||||
|
|
||||||
abstract public class AppListAdapter extends BaseAdapter {
|
abstract public class AppListAdapter extends BaseAdapter {
|
||||||
|
|
||||||
@ -110,10 +111,7 @@ abstract public class AppListAdapter extends BaseAdapter {
|
|||||||
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
RelativeLayout.LayoutParams.WRAP_CONTENT,
|
||||||
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||||
summaryLayout.addRule(RelativeLayout.BELOW, R.id.name);
|
summaryLayout.addRule(RelativeLayout.BELOW, R.id.name);
|
||||||
if (Utils.hasApi(17))
|
summaryLayout.addRule(LayoutCompat.RelativeLayout.END_OF, R.id.icon);
|
||||||
summaryLayout.addRule(RelativeLayout.END_OF, R.id.icon);
|
|
||||||
else
|
|
||||||
summaryLayout.addRule(RelativeLayout.RIGHT_OF, R.id.icon);
|
|
||||||
summary.setLayoutParams(summaryLayout);
|
summary.setLayoutParams(summaryLayout);
|
||||||
summary.setPadding(0,0,0,0);
|
summary.setPadding(0,0,0,0);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user