diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 0ce00fe03..3fdd92aae 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; import android.support.v4.view.MenuItemCompat; +import org.fdroid.fdroid.compat.MenuManager; import org.xml.sax.XMLReader; import android.app.AlertDialog; @@ -248,7 +249,9 @@ public class AppDetails extends ListActivity { resetRequired = false; } resetViews(); - invalidateOptionsMenu(); + + MenuManager.create(this).invalidateOptionsMenu(); + if (downloadHandler != null) { downloadHandler.startUpdates(); } @@ -796,4 +799,5 @@ public class AppDetails extends ListActivity { break; } } + } diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index 854458f47..bc36ca9db 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -278,28 +278,23 @@ public class DB { // check if an APK is compatible with the user's device. public static abstract class CompatibilityChecker { - // Because Build.VERSION.SDK_INT requires API level 5 - @SuppressWarnings("deprecation") - protected final static int SDK_INT = Integer - .parseInt(Build.VERSION.SDK); - public abstract boolean isCompatible(Apk apk); public static CompatibilityChecker getChecker(Context ctx) { CompatibilityChecker checker; - if (SDK_INT >= 5) + if (Utils.hasApi(5)) checker = new EclairChecker(ctx); else checker = new BasicChecker(); Log.d("FDroid", "Compatibility checker for API level " - + SDK_INT + ": " + checker.getClass().getName()); + + Utils.getApi() + ": " + checker.getClass().getName()); return checker; } } private static class BasicChecker extends CompatibilityChecker { public boolean isCompatible(Apk apk) { - return (apk.minSdkVersion <= SDK_INT); + return (apk.minSdkVersion <= Utils.getApi()); } } @@ -329,7 +324,7 @@ public class DB { } public boolean isCompatible(Apk apk) { - if (apk.minSdkVersion > SDK_INT) + if (apk.minSdkVersion > Utils.getApi()) return false; if (apk.features != null) { for (String feat : apk.features) { diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index dbc0e5dde..c68e9b662 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -34,18 +34,17 @@ import org.fdroid.fdroid.R; import android.R.drawable; import android.app.AlertDialog; import android.app.AlertDialog.Builder; -import android.app.FragmentTransaction; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; import android.support.v4.app.FragmentActivity; +import android.support.v4.view.MenuItemCompat; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; @@ -53,7 +52,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.*; -import android.widget.TabHost.TabSpec; +import org.fdroid.fdroid.compat.TabManager; import org.fdroid.fdroid.views.AppListFragmentPageAdapter; public class FDroid extends FragmentActivity { @@ -76,8 +75,7 @@ public class FDroid extends FragmentActivity { private AppListManager manager = null; - // Used by pre 3.0 devices which don't have an ActionBar... - private TabHost tabHost; + private TabManager tabManager = null; public AppListManager getManager() { return manager; @@ -90,7 +88,7 @@ public class FDroid extends FragmentActivity { manager = new AppListManager(this); setContentView(R.layout.fdroid); createViews(); - createTabs(); + getTabManager().createTabs(); // Must be done *after* createViews, because it will involve a // callback to update the tab label for the "update" tab. This @@ -105,7 +103,7 @@ public class FDroid extends FragmentActivity { } else if (i.hasExtra(EXTRA_TAB_UPDATE)) { boolean showUpdateTab = i.getBooleanExtra(EXTRA_TAB_UPDATE, false); if (showUpdateTab) { - selectTab(2); + getTabManager().selectTab(2); } } } @@ -251,127 +249,7 @@ public class FDroid extends FragmentActivity { viewPager.setAdapter(viewPageAdapter); viewPager.setOnPageChangeListener( new ViewPager.SimpleOnPageChangeListener() { public void onPageSelected(int position) { - selectTab(position); - } - }); - } - - private void createTabs() { - if (Build.VERSION.SDK_INT >= 11) { - createActionBarTabs(); - } else { - createOldTabs(); - } - } - - private void selectTab(int index) { - if (Build.VERSION.SDK_INT >= 11) { - getActionBar().setSelectedNavigationItem(index); - } else { - tabHost.setCurrentTab(index); - } - } - - public void refreshUpdateTabLabel() { - final int INDEX = 2; - CharSequence text = viewPager.getAdapter().getPageTitle(INDEX); - if ( Build.VERSION.SDK_INT >= 11) { - getActionBar().getTabAt(INDEX).setText(text); - } else { - // Update the count on the 'Updates' tab to show the number available. - // This is quite unpleasant, but seems to be the only way to do it. - TextView textView = (TextView) tabHost.getTabWidget().getChildAt(2) - .findViewById(android.R.id.title); - textView.setText(text); - } - } - - private void createActionBarTabs() { - final ActionBar actionBar = getActionBar(); - final ViewPager pager = viewPager; - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - for (int i = 0; i < viewPager.getAdapter().getCount(); i ++) { - CharSequence label = viewPager.getAdapter().getPageTitle(i); - actionBar.addTab( - actionBar.newTab() - .setText(label) - .setTabListener(new ActionBar.TabListener() { - public void onTabSelected(ActionBar.Tab tab, - FragmentTransaction ft) { - pager.setCurrentItem(tab.getPosition()); - } - - @Override - public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - - @Override - public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { - } - })); - } - } - - /** - * There is a bit of boiler-plate code required to get a TabWidget showing, - * which includes creating a TabHost, populating it with the TabWidget, - * and giving it a FrameLayout as a child. This will make the tabs have - * dummy empty contents and then hook them up to our ViewPager. - */ - private void createOldTabs() { - tabHost = new TabHost(this); - tabHost.setLayoutParams(new TabHost.LayoutParams( - TabHost.LayoutParams.MATCH_PARENT, TabHost.LayoutParams.WRAP_CONTENT)); - - TabWidget tabWidget = new TabWidget(this); - tabWidget.setId(android.R.id.tabs); - tabHost.setLayoutParams(new TabHost.LayoutParams( - TabWidget.LayoutParams.MATCH_PARENT, TabWidget.LayoutParams.WRAP_CONTENT)); - - FrameLayout layout = new FrameLayout(this); - layout.setId(android.R.id.tabcontent); - layout.setLayoutParams(new TabWidget.LayoutParams(0, 0)); - - tabHost.addView(tabWidget); - tabHost.addView(layout); - tabHost.setup(); - - TabHost.TabContentFactory factory = new TabHost.TabContentFactory() { - @Override - public View createTabContent(String tag) { - return new View(FDroid.this); - } - }; - - TabSpec availableTabSpec = tabHost.newTabSpec("available") - .setIndicator( - getString(R.string.tab_noninstalled), - getResources().getDrawable(android.R.drawable.ic_input_add)) - .setContent(factory); - - TabSpec installedTabSpec = tabHost.newTabSpec("installed") - .setIndicator( - getString(R.string.tab_installed), - getResources().getDrawable(android.R.drawable.star_off)) - .setContent(factory); - - TabSpec canUpdateTabSpec = tabHost.newTabSpec("canUpdate") - .setIndicator( - getString(R.string.tab_updates), - getResources().getDrawable(android.R.drawable.star_on)) - .setContent(factory); - - tabHost.addTab(availableTabSpec); - tabHost.addTab(installedTabSpec); - tabHost.addTab(canUpdateTabSpec); - - LinearLayout contentView = (LinearLayout)findViewById(R.id.fdroid_layout); - contentView.addView(tabHost, 0); - - tabHost.setOnTabChangedListener( new TabHost.OnTabChangeListener() { - @Override - public void onTabChanged(String tabId) { - viewPager.setCurrentItem(tabHost.getCurrentTab()); + getTabManager().selectTab(position); } }); } @@ -410,7 +288,7 @@ public class FDroid extends FragmentActivity { boolean hasTriedEmptyUpdate = getPreferences(MODE_PRIVATE).getBoolean(TRIED_EMPTY_UPDATE, false); if (!hasTriedEmptyUpdate) { Log.d("FDroid", "Empty app list, and we haven't done an update yet. Forcing repo update."); - getPreferences(MODE_PRIVATE).edit().putBoolean(TRIED_EMPTY_UPDATE, true).apply(); + getPreferences(MODE_PRIVATE).edit().putBoolean(TRIED_EMPTY_UPDATE, true).commit(); updateRepos(); return true; } else { @@ -435,4 +313,15 @@ public class FDroid extends FragmentActivity { startService(intent); } + private TabManager getTabManager() { + if (tabManager == null) { + tabManager = TabManager.create(this, viewPager); + } + return tabManager; + } + + public void refreshUpdateTabLabel() { + getTabManager().refreshTabLabel(TabManager.INDEX_CAN_UPDATE); + } + } diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index 14dad6be0..529dc9182 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -18,6 +18,8 @@ package org.fdroid.fdroid; +import android.os.Build; + import java.io.Closeable; import java.io.InputStream; import java.io.IOException; @@ -52,4 +54,12 @@ public final class Utils { // ignore } } + + public static boolean hasApi(int apiLevel) { + return Build.VERSION.SDK_INT >= apiLevel; + } + + public static int getApi() { + return Build.VERSION.SDK_INT; + } } diff --git a/src/org/fdroid/fdroid/compat/MenuManager.java b/src/org/fdroid/fdroid/compat/MenuManager.java new file mode 100644 index 000000000..9a60b595e --- /dev/null +++ b/src/org/fdroid/fdroid/compat/MenuManager.java @@ -0,0 +1,48 @@ +package org.fdroid.fdroid.compat; + +import android.app.Activity; +import org.fdroid.fdroid.Utils; + +abstract public class MenuManager { + + public static MenuManager create(Activity activity) { + if (Utils.hasApi(11)) { + return new HoneycombMenuManagerImpl(activity); + } else { + return new OldMenuManagerImpl(activity); + } + } + + protected final Activity activity; + + protected MenuManager(Activity activity) { + this.activity = activity; + } + + abstract public void invalidateOptionsMenu(); + +} + +class OldMenuManagerImpl extends MenuManager { + + protected OldMenuManagerImpl(Activity activity) { + super(activity); + } + + @Override + public void invalidateOptionsMenu() { + } + +} + +class HoneycombMenuManagerImpl extends MenuManager { + + protected HoneycombMenuManagerImpl(Activity activity) { + super(activity); + } + + @Override + public void invalidateOptionsMenu() { + activity.invalidateOptionsMenu(); + } +} \ No newline at end of file diff --git a/src/org/fdroid/fdroid/compat/TabManager.java b/src/org/fdroid/fdroid/compat/TabManager.java new file mode 100644 index 000000000..b8863bedb --- /dev/null +++ b/src/org/fdroid/fdroid/compat/TabManager.java @@ -0,0 +1,173 @@ +package org.fdroid.fdroid.compat; + +import android.app.ActionBar; +import android.app.FragmentTransaction; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.widget.*; +import org.fdroid.fdroid.FDroid; +import org.fdroid.fdroid.R; +import org.fdroid.fdroid.Utils; + +public abstract class TabManager { + + 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)) { + return new HoneycombTabManagerImpl(parent, pager); + } else { + return new OldTabManagerImpl(parent, pager); + } + } + + protected final ViewPager pager; + protected final FDroid parent; + + protected TabManager(FDroid parent, ViewPager pager) { + this.parent = parent; + this.pager = pager; + } + + abstract public void createTabs(); + abstract public void selectTab(int index); + abstract public void refreshTabLabel(int index); + + protected CharSequence getLabel(int index) { + return pager.getAdapter().getPageTitle(index); + } +} + +class OldTabManagerImpl extends TabManager { + + private TabHost tabHost; + + public OldTabManagerImpl(FDroid parent, ViewPager pager) { + super(parent, pager); + } + + /** + * There is a bit of boiler-plate code required to get a TabWidget showing, + * which includes creating a TabHost, populating it with the TabWidget, + * and giving it a FrameLayout as a child. This will make the tabs have + * dummy empty contents and then hook them up to our ViewPager. + */ + public void createTabs() { + tabHost = new TabHost(parent); + tabHost.setLayoutParams(new TabHost.LayoutParams( + TabHost.LayoutParams.MATCH_PARENT, TabHost.LayoutParams.WRAP_CONTENT)); + + TabWidget tabWidget = new TabWidget(parent); + tabWidget.setId(android.R.id.tabs); + tabHost.setLayoutParams(new TabHost.LayoutParams( + TabWidget.LayoutParams.MATCH_PARENT, TabWidget.LayoutParams.WRAP_CONTENT)); + + FrameLayout layout = new FrameLayout(parent); + layout.setId(android.R.id.tabcontent); + layout.setLayoutParams(new TabWidget.LayoutParams(0, 0)); + + tabHost.addView(tabWidget); + tabHost.addView(layout); + tabHost.setup(); + + TabHost.TabContentFactory factory = new TabHost.TabContentFactory() { + @Override + public View createTabContent(String tag) { + return new View(parent); + } + }; + + TabHost.TabSpec availableTabSpec = tabHost.newTabSpec("available") + .setIndicator( + parent.getString(R.string.tab_noninstalled), + parent.getResources().getDrawable(android.R.drawable.ic_input_add)) + .setContent(factory); + + TabHost.TabSpec installedTabSpec = tabHost.newTabSpec("installed") + .setIndicator( + parent.getString(R.string.tab_installed), + parent.getResources().getDrawable(android.R.drawable.star_off)) + .setContent(factory); + + TabHost.TabSpec canUpdateTabSpec = tabHost.newTabSpec("canUpdate") + .setIndicator( + parent.getString(R.string.tab_updates), + parent.getResources().getDrawable(android.R.drawable.star_on)) + .setContent(factory); + + tabHost.addTab(availableTabSpec); + tabHost.addTab(installedTabSpec); + tabHost.addTab(canUpdateTabSpec); + + LinearLayout contentView = (LinearLayout)parent.findViewById(R.id.fdroid_layout); + contentView.addView(tabHost, 0); + + tabHost.setOnTabChangedListener( new TabHost.OnTabChangeListener() { + @Override + public void onTabChanged(String tabId) { + pager.setCurrentItem(tabHost.getCurrentTab()); + } + }); + } + + + public void selectTab(int index) { + tabHost.setCurrentTab(index); + } + + public void refreshTabLabel(int index) { + CharSequence text = getLabel(index); + + // Update the count on the 'Updates' tab to show the number available. + // This is quite unpleasant, but seems to be the only way to do it. + TextView textView = (TextView) tabHost.getTabWidget().getChildAt(index) + .findViewById(android.R.id.title); + textView.setText(text); + } + +} + +class HoneycombTabManagerImpl extends TabManager { + + protected final ActionBar actionBar; + + public HoneycombTabManagerImpl(FDroid parent, ViewPager pager) { + super(parent, pager); + actionBar = parent.getActionBar(); + } + + public void createTabs() { + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + for (int i = 0; i < pager.getAdapter().getCount(); i ++) { + CharSequence label = pager.getAdapter().getPageTitle(i); + actionBar.addTab( + actionBar.newTab() + .setText(label) + .setTabListener(new ActionBar.TabListener() { + public void onTabSelected(ActionBar.Tab tab, + FragmentTransaction ft) { + pager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { + } + + @Override + public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { + } + })); + } + } + + public void selectTab(int index) { + actionBar.setSelectedNavigationItem(index); + } + + public void refreshTabLabel(int index) { + CharSequence text = getLabel(index); + actionBar.getTabAt(index).setText(text); + } +} diff --git a/src/org/fdroid/fdroid/views/AppListView.java b/src/org/fdroid/fdroid/views/AppListView.java index 4fbe716ed..b65f50cc3 100644 --- a/src/org/fdroid/fdroid/views/AppListView.java +++ b/src/org/fdroid/fdroid/views/AppListView.java @@ -27,10 +27,6 @@ public class AppListView extends LinearLayout { super(context, attrs); } - public AppListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - public void setAppList(ListView appList) { this.appList = appList; }