From 8dd337f345409d5fae28d5095e58f4ec25f192d9 Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Fri, 12 Apr 2013 22:02:42 +0100 Subject: [PATCH 01/10] Need to drop stored etags when resetting --- src/org/fdroid/fdroid/DB.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index 7a15eb142..cf561cc0d 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -379,6 +379,7 @@ public class DB { public static void resetTransient(SQLiteDatabase db) { db.execSQL("drop table " + TABLE_APP); db.execSQL("drop table " + TABLE_APK); + db.execSQL("update " + TABLE_REPO + " set lastetag = NULL"); createAppApk(db); } From 716b1c802bd8c6da20d971923ffad0876855a0e8 Mon Sep 17 00:00:00 2001 From: Andrew Gaul Date: Tue, 11 Dec 2012 19:42:39 -0800 Subject: [PATCH 02/10] Prefer unsynchronized ArrayList over Vector --- src/org/fdroid/fdroid/AppDetails.java | 3 +- src/org/fdroid/fdroid/AppListManager.java | 6 ++-- src/org/fdroid/fdroid/DB.java | 34 +++++++++++------------ src/org/fdroid/fdroid/FDroid.java | 3 +- src/org/fdroid/fdroid/FDroidApp.java | 9 +++--- src/org/fdroid/fdroid/ManageRepo.java | 9 +++--- src/org/fdroid/fdroid/RepoXMLHandler.java | 8 +++--- src/org/fdroid/fdroid/SearchResults.java | 9 +++--- src/org/fdroid/fdroid/UpdateService.java | 15 +++++----- 9 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 5e4f75917..0ce00fe03 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -22,7 +22,6 @@ import java.io.File; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; -import java.util.Vector; import android.support.v4.view.MenuItemCompat; import org.xml.sax.XMLReader; @@ -302,7 +301,7 @@ public class AppDetails extends ListActivity { Log.d("FDroid", "Getting application details for " + appid); app = null; - Vector apps = ((FDroidApp) getApplication()).getApps(); + List apps = ((FDroidApp) getApplication()).getApps(); for (DB.App tapp : apps) { if (tapp.id.equals(appid)) { app = tapp; diff --git a/src/org/fdroid/fdroid/AppListManager.java b/src/org/fdroid/fdroid/AppListManager.java index 59f66f161..30e400bff 100644 --- a/src/org/fdroid/fdroid/AppListManager.java +++ b/src/org/fdroid/fdroid/AppListManager.java @@ -15,7 +15,7 @@ import java.util.*; */ public class AppListManager { - private Vector allApps = null; + private List allApps = null; private FDroid fdroidActivity; @@ -55,7 +55,7 @@ public class AppListManager { // Needs to be created before createViews(), because that will use the // getCategoriesAdapter() accessor which expects this object... categories = new ArrayAdapter(activity, - android.R.layout.simple_spinner_item, new Vector()); + android.R.layout.simple_spinner_item, new ArrayList()); categories .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); } @@ -185,7 +185,7 @@ public class AppListManager { Date recentDate = calcMaxHistory(); AppFilter appFilter = new AppFilter(fdroidActivity); - Vector availApps = new Vector(); + List availApps = new ArrayList(); for (DB.App app : allApps) { boolean isInCategory = isInCategory(app, currentCategory, recentDate); diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index cf561cc0d..a738d2ebe 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -21,6 +21,7 @@ package org.fdroid.fdroid; import java.io.File; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -28,7 +29,6 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Vector; import java.util.concurrent.Semaphore; import android.annotation.TargetApi; @@ -116,7 +116,7 @@ public class DB { updated = false; added = null; lastUpdated = null; - apks = new Vector(); + apks = new ArrayList(); detail_Populated = false; compatible = false; } @@ -181,7 +181,7 @@ public class DB { public boolean updated; // List of apks. - public Vector apks; + public List apks; // Get the current version - this will be one of the Apks from 'apks'. // Can return null if there are no available versions. @@ -413,7 +413,7 @@ public class DB { // Migrate repo list to new structure. (No way to change primary // key in sqlite - table must be recreated) if (oldVersion < 20) { - Vector oldrepos = new Vector(); + List oldrepos = new ArrayList(); Cursor c = db.rawQuery("select address, inuse, pubkey from " + TABLE_REPO, null); c.moveToFirst(); @@ -504,7 +504,7 @@ public class DB { // Get the number of apps that have updates available. This can be a // time consuming operation. public int getNumUpdates() { - Vector apps = getApps(true); + List apps = getApps(true); int count = 0; for (App app : apps) { if (app.hasUpdates) @@ -513,8 +513,8 @@ public class DB { return count; } - public Vector getCategories() { - Vector result = new Vector(); + public List getCategories() { + List result = new ArrayList(); Cursor c = null; try { c = db.rawQuery("select distinct category from " + TABLE_APP @@ -592,7 +592,7 @@ public class DB { // Return a list of apps matching the given criteria. Filtering is // also done based on compatibility and anti-features according to // the user's current preferences. - public Vector getApps(boolean getinstalledinfo) { + public List getApps(boolean getinstalledinfo) { // If we're going to need it, get info in what's currently installed Map systemApks = null; @@ -697,7 +697,7 @@ public class DB { + (System.currentTimeMillis() - startTime) + " ms)"); } - Vector result = new Vector(apps.values()); + List result = new ArrayList(apps.values()); Collections.sort(result); // Fill in the hasUpdates fields if we have the necessary information... @@ -721,9 +721,9 @@ public class DB { return result; } - public Vector doSearch(String query) { + public List doSearch(String query) { - Vector ids = new Vector(); + List ids = new ArrayList(); Cursor c = null; try { String filter = "%" + query + "%"; @@ -771,11 +771,11 @@ public class DB { } } - private Vector updateApps = null; + private List updateApps = null; // Called before a repo update starts. Returns the number of updates // available beforehand. - public int beginUpdate(Vector apps) { + public int beginUpdate(List apps) { // Get a list of all apps. All the apps and apks in this list will // have 'updated' set to false at this point, and we will only set // it to true when we see the app/apk in a repository. Thus, at the @@ -866,7 +866,7 @@ public class DB { // compatible apk - if it's not, leave it out) // Also keep a list of which were compatible, because they're the // only ones we'll add, unless the showIncompatible preference is set. - Vector compatibleapks = new Vector(); + List compatibleapks = new ArrayList(); for (Apk apk : upapp.apks) { if (compatChecker.isCompatible(apk)) { apk.compatible = true; @@ -1017,8 +1017,8 @@ public class DB { } // Get a list of the configured repositories. - public Vector getRepos() { - Vector repos = new Vector(); + public List getRepos() { + List repos = new ArrayList(); Cursor c = null; try { c = db.rawQuery( @@ -1079,7 +1079,7 @@ public class DB { db.insert(TABLE_REPO, null, values); } - public void removeServers(Vector addresses) { + public void removeServers(List addresses) { db.beginTransaction(); try { for (String address : addresses) { diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index c14703eb5..dbc0e5dde 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -23,8 +23,9 @@ import android.app.ActionBar; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; +import java.util.ArrayList; import java.util.Date; -import java.util.Vector; +import java.util.List; import android.support.v4.view.MenuItemCompat; import org.fdroid.fdroid.DB.App; diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java index c4b765cd3..eb8ead6b9 100644 --- a/src/org/fdroid/fdroid/FDroidApp.java +++ b/src/org/fdroid/fdroid/FDroidApp.java @@ -19,7 +19,8 @@ package org.fdroid.fdroid; import java.io.File; -import java.util.Vector; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Semaphore; import android.app.Application; @@ -47,7 +48,7 @@ public class FDroidApp extends Application { } // Global list of all known applications. - private Vector apps; + private List apps; // Set when something has changed (database or installed apps) so we know // we should invalidate the apps. @@ -70,7 +71,7 @@ public class FDroidApp extends Application { // Get a list of all known applications. Should not be called when the // database is locked (i.e. between DB.getDB() and db.releaseDB(). The // contents should never be modified, it's for reading only. - public Vector getApps() { + public List getApps() { boolean invalid = false; try { @@ -95,7 +96,7 @@ public class FDroidApp extends Application { } } if (apps == null) - return new Vector(); + return new ArrayList(); return apps; } diff --git a/src/org/fdroid/fdroid/ManageRepo.java b/src/org/fdroid/fdroid/ManageRepo.java index 5953f3f61..6c6f003dc 100644 --- a/src/org/fdroid/fdroid/ManageRepo.java +++ b/src/org/fdroid/fdroid/ManageRepo.java @@ -26,7 +26,6 @@ import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Vector; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -55,7 +54,7 @@ public class ManageRepo extends ListActivity { private boolean changed = false; - private Vector repos; + private List repos; @Override protected void onCreate(Bundle savedInstanceState) { @@ -201,7 +200,7 @@ public class ManageRepo extends ListActivity { return true; case REM_REPO: - final Vector rem_lst = new Vector(); + final List rem_lst = new ArrayList(); CharSequence[] b = new CharSequence[repos.size()]; for (int i = 0; i < repos.size(); i++) { b[i] = repos.get(i).address; @@ -215,9 +214,9 @@ public class ManageRepo extends ListActivity { public void onClick(DialogInterface dialog, int whichButton, boolean isChecked) { if (isChecked) { - rem_lst.addElement(repos.get(whichButton).address); + rem_lst.add(repos.get(whichButton).address); } else { - rem_lst.removeElement(repos.get(whichButton).address); + rem_lst.remove(repos.get(whichButton).address); } } }); diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index 2ab7360a5..ad19265f1 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -33,7 +33,7 @@ import java.net.URL; import java.security.cert.Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Vector; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -57,7 +57,7 @@ public class RepoXMLHandler extends DefaultHandler { // The ID of the repo we're processing. private int repo; - private Vector apps; + private List apps; private DB.App curapp = null; private DB.Apk curapk = null; @@ -69,7 +69,7 @@ public class RepoXMLHandler extends DefaultHandler { // The date format used in the repo XML file. private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd"); - public RepoXMLHandler(int repo, Vector apps) { + public RepoXMLHandler(int repo, List apps) { this.repo = repo; this.apps = apps; pubkey = null; @@ -293,7 +293,7 @@ public class RepoXMLHandler extends DefaultHandler { // value for the index that was successfully processed, or it may contain // null if none was available. public static String doUpdate(Context ctx, DB.Repo repo, - Vector apps, StringBuilder newetag, Vector keeprepos) { + List apps, StringBuilder newetag, List keeprepos) { try { int code = 0; diff --git a/src/org/fdroid/fdroid/SearchResults.java b/src/org/fdroid/fdroid/SearchResults.java index 62dbc7744..1204f2471 100644 --- a/src/org/fdroid/fdroid/SearchResults.java +++ b/src/org/fdroid/fdroid/SearchResults.java @@ -18,7 +18,8 @@ package org.fdroid.fdroid; -import java.util.Vector; +import java.util.ArrayList; +import java.util.List; import android.app.ListActivity; import android.app.SearchManager; @@ -68,7 +69,7 @@ public class SearchResults extends ListActivity { private void updateView() { - Vector matchingids = new Vector(); + List matchingids = new ArrayList(); try { DB db = DB.getDB(); matchingids = db.doSearch(mQuery); @@ -78,9 +79,9 @@ public class SearchResults extends ListActivity { DB.releaseDB(); } - Vector apps = new Vector(); + List apps = new ArrayList(); AppFilter appfilter = new AppFilter(this); - Vector tapps = ((FDroidApp) getApplication()).getApps(); + List tapps = ((FDroidApp) getApplication()).getApps(); for (DB.App tapp : tapps) { boolean include = false; for (String tid : matchingids) { diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index bfd66bf99..64d0cd01b 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -24,7 +24,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; -import java.util.Vector; +import java.util.ArrayList; +import java.util.List; import android.app.AlarmManager; import android.app.IntentService; @@ -110,7 +111,7 @@ public class UpdateService extends IntentService { // database while we do all the downloading, etc... int prevUpdates = 0; int newUpdates = 0; - Vector repos; + List repos; try { DB db = DB.getDB(); repos = db.getRepos(); @@ -119,8 +120,8 @@ public class UpdateService extends IntentService { } // Process each repo... - Vector apps = new Vector(); - Vector keeprepos = new Vector(); + List apps = new ArrayList(); + List keeprepos = new ArrayList(); boolean success = true; for (DB.Repo repo : repos) { if (repo.inuse) { @@ -142,8 +143,8 @@ public class UpdateService extends IntentService { } if (success) { - Vector acceptedapps = new Vector(); - Vector prevapps = ((FDroidApp) getApplication()) + List acceptedapps = new ArrayList(); + List prevapps = ((FDroidApp) getApplication()) .getApps(); DB db = DB.getDB(); @@ -272,7 +273,7 @@ public class UpdateService extends IntentService { } - private void getIcon(DB.App app, Vector repos) { + private void getIcon(DB.App app, List repos) { try { File f = new File(DB.getIconsPath(), app.icon); From f4abb6389c3bd38f47114f8fd74468bf52a0d877 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 14 Apr 2013 07:05:20 +1000 Subject: [PATCH 03/10] Fixed bug I introduced depending on later API. Also added utility method to make checking a bit easier, and removed reference to SDK from DB (it mentioned in the comments that SDK_INT was only available in v5, but the Android docs say it was introduced in v4. Because FDroid now depends on the Android support library, which in turn depends on v4, it sould be okay to depen on this. --- src/org/fdroid/fdroid/AppDetails.java | 6 +++++- src/org/fdroid/fdroid/DB.java | 13 ++++--------- src/org/fdroid/fdroid/FDroid.java | 6 +++--- src/org/fdroid/fdroid/Utils.java | 10 ++++++++++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 5e4f75917..0821eea47 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -249,7 +249,11 @@ public class AppDetails extends ListActivity { resetRequired = false; } resetViews(); - invalidateOptionsMenu(); + + if (Utils.hasApi(11)) { + invalidateOptionsMenu(); + } + if (downloadHandler != null) { downloadHandler.startUpdates(); } diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index cf561cc0d..613a0056a 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 c14703eb5..444e599ed 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -256,7 +256,7 @@ public class FDroid extends FragmentActivity { } private void createTabs() { - if (Build.VERSION.SDK_INT >= 11) { + if (Utils.hasApi(11)) { createActionBarTabs(); } else { createOldTabs(); @@ -264,7 +264,7 @@ public class FDroid extends FragmentActivity { } private void selectTab(int index) { - if (Build.VERSION.SDK_INT >= 11) { + if (Utils.hasApi(11)) { getActionBar().setSelectedNavigationItem(index); } else { tabHost.setCurrentTab(index); @@ -274,7 +274,7 @@ public class FDroid extends FragmentActivity { public void refreshUpdateTabLabel() { final int INDEX = 2; CharSequence text = viewPager.getAdapter().getPageTitle(INDEX); - if ( Build.VERSION.SDK_INT >= 11) { + if (Utils.hasApi(11)) { getActionBar().getTabAt(INDEX).setText(text); } else { // Update the count on the 'Updates' tab to show the number available. 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; + } } From 04f899d72f1892f0c3979830032ac0c596b61f10 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 14 Apr 2013 08:12:34 +1000 Subject: [PATCH 04/10] Refactored API dependent implementations into classes. See http://stackoverflow.com/a/6495399. I thought that I could just wrap API dependent code in an if statement, ant it would only have a problem if it tried to execute a particular function at runtime. However when testing on a 1.6 emulator, I was getting "VerifyErrors" which as the link above suggest, are because it is verifying every statement in a class. Refactoring out to another class solves this because it only verifies classes which are loaded at runtime. --- src/org/fdroid/fdroid/AppDetails.java | 6 +- src/org/fdroid/fdroid/FDroid.java | 159 ++-------------- src/org/fdroid/fdroid/compat/MenuManager.java | 48 +++++ src/org/fdroid/fdroid/compat/TabManager.java | 173 ++++++++++++++++++ src/org/fdroid/fdroid/views/AppListView.java | 4 - 5 files changed, 242 insertions(+), 148 deletions(-) create mode 100644 src/org/fdroid/fdroid/compat/MenuManager.java create mode 100644 src/org/fdroid/fdroid/compat/TabManager.java diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 0821eea47..c79a4e290 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Vector; import android.support.v4.view.MenuItemCompat; +import org.fdroid.fdroid.compat.MenuManager; import org.xml.sax.XMLReader; import android.app.AlertDialog; @@ -250,9 +251,7 @@ public class AppDetails extends ListActivity { } resetViews(); - if (Utils.hasApi(11)) { - invalidateOptionsMenu(); - } + MenuManager.create(this).invalidateOptionsMenu(); if (downloadHandler != null) { downloadHandler.startUpdates(); @@ -801,4 +800,5 @@ public class AppDetails extends ListActivity { break; } } + } diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index 444e599ed..78719a87a 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -19,32 +19,19 @@ package org.fdroid.fdroid; -import android.app.ActionBar; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.Vector; - -import android.support.v4.view.MenuItemCompat; -import org.fdroid.fdroid.DB.App; -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; @@ -52,7 +39,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 { @@ -75,8 +62,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; @@ -89,7 +75,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 @@ -104,7 +90,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); } } } @@ -250,127 +236,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 (Utils.hasApi(11)) { - createActionBarTabs(); - } else { - createOldTabs(); - } - } - - private void selectTab(int index) { - if (Utils.hasApi(11)) { - getActionBar().setSelectedNavigationItem(index); - } else { - tabHost.setCurrentTab(index); - } - } - - public void refreshUpdateTabLabel() { - final int INDEX = 2; - CharSequence text = viewPager.getAdapter().getPageTitle(INDEX); - if (Utils.hasApi(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); } }); } @@ -409,7 +275,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 { @@ -434,4 +300,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/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; } From 34a2534cc8fbc1918fe72a2ab59d73641c31b8a4 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Sun, 14 Apr 2013 08:37:02 +1000 Subject: [PATCH 05/10] List was repopulating every page view, because category spinner was firing change event. --- src/org/fdroid/fdroid/AppListManager.java | 5 ++++- src/org/fdroid/fdroid/views/fragments/AppListFragment.java | 1 - .../fdroid/fdroid/views/fragments/AvailableAppsFragment.java | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/org/fdroid/fdroid/AppListManager.java b/src/org/fdroid/fdroid/AppListManager.java index 59f66f161..20228de68 100644 --- a/src/org/fdroid/fdroid/AppListManager.java +++ b/src/org/fdroid/fdroid/AppListManager.java @@ -215,7 +215,10 @@ public class AppListManager { } public void setCurrentCategory(String currentCategory) { - this.currentCategory = currentCategory; + if (!this.currentCategory.equals(currentCategory)){ + this.currentCategory = currentCategory; + repopulateLists(); + } } static class WhatsNewComparator implements Comparator { diff --git a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java index 6ad8f9588..33ef1b060 100644 --- a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java @@ -13,7 +13,6 @@ import org.fdroid.fdroid.views.AppListView; abstract class AppListFragment extends Fragment implements AdapterView.OnItemClickListener { - private AppListManager appListManager; private FDroid parent; protected abstract AppListAdapter getAppListAdapter(); diff --git a/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java b/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java index 517476e79..f513e3f13 100644 --- a/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java @@ -51,8 +51,8 @@ public class AvailableAppsFragment extends AppListFragment implements AdapterVie public void onItemSelected(AdapterView parent, View view, int pos, long id) { - getAppListManager().setCurrentCategory(parent.getItemAtPosition(pos).toString()); - getAppListManager().repopulateLists(); + String category = parent.getItemAtPosition(pos).toString(); + getAppListManager().setCurrentCategory(category); } @Override From d641ad85390175d46c39bf76d0bf1c51b5f8ab14 Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Mon, 15 Apr 2013 10:32:59 +0100 Subject: [PATCH 06/10] Default https when adding repo --- res/layout/addrepo.xml | 2 +- res/values/strings.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/res/layout/addrepo.xml b/res/layout/addrepo.xml index 0f0845155..c67ee5d7b 100644 --- a/res/layout/addrepo.xml +++ b/res/layout/addrepo.xml @@ -15,7 +15,7 @@ android:layout_width="wrap_content" android:ems="20" android:layout_height="wrap_content" - android:text="@string/repo_add_http"/> + android:text="https://"/> + Downloading %1$s / %2$s (%3$d%%) + Processing application %1$d of %2$d + Connecting to repository:\n%1$s + Checking apps compatibility with your device… + diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 5e4f75917..e3d86a440 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -127,7 +127,7 @@ public class AppDetails extends ListActivity { if (apk.detail_size == 0) { size.setText(""); } else { - size.setText(getFriendlySize(apk.detail_size)); + size.setText(Utils.getFriendlySize(apk.detail_size)); } TextView buildtype = (TextView) v.findViewById(R.id.buildtype); if (apk.srcname != null) { @@ -153,19 +153,6 @@ public class AppDetails extends ListActivity { } } - private static final String[] FRIENDLY_SIZE_FORMAT = { - "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; - - private static String getFriendlySize(int size) { - double s = size; - int i = 0; - while (i < FRIENDLY_SIZE_FORMAT.length - 1 && s >= 1024) { - s = (100 * s / 1024) / 100.0; - i++; - } - return String.format(FRIENDLY_SIZE_FORMAT[i], s); - } - private static final int INSTALL = Menu.FIRST; private static final int UNINSTALL = Menu.FIRST + 1; private static final int WEBSITE = Menu.FIRST + 2; diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index c14703eb5..ac73b9c76 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -384,13 +384,19 @@ public class FDroid extends FragmentActivity { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == 1) { - Toast.makeText(FDroid.this, resultData.getString("errmsg"), - Toast.LENGTH_LONG).show(); - } else { + String message = resultData.getString(UpdateService.RESULT_MESSAGE); + boolean finished = false; + if (resultCode == UpdateService.STATUS_ERROR) { + Toast.makeText(FDroid.this, message, Toast.LENGTH_LONG).show(); + finished = true; + } else if (resultCode == UpdateService.STATUS_COMPLETE) { repopulateViews(); + finished = true; + } else if (resultCode == UpdateService.STATUS_INFO) { + pd.setMessage(message); } - if (pd.isShowing()) + + if (finished && pd.isShowing()) pd.dismiss(); } } diff --git a/src/org/fdroid/fdroid/ProgressListener.java b/src/org/fdroid/fdroid/ProgressListener.java new file mode 100644 index 000000000..2ec97ed92 --- /dev/null +++ b/src/org/fdroid/fdroid/ProgressListener.java @@ -0,0 +1,7 @@ +package org.fdroid.fdroid; + +public interface ProgressListener { + + public void onProgress(int type, int progress, int total); + +} diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index 2ab7360a5..f8844dc9b 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -30,6 +30,7 @@ import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; import java.security.cert.Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -66,13 +67,21 @@ public class RepoXMLHandler extends DefaultHandler { private String pubkey; private String hashType; + private int progressCounter = 0; + private ProgressListener progressListener; + + public static final int PROGRESS_TYPE_DOWNLOAD = 1; + public static final int PROGRESS_TYPE_PROCESS_XML = 2; + // The date format used in the repo XML file. private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + private int totalAppCount; - public RepoXMLHandler(int repo, Vector apps) { + public RepoXMLHandler(int repo, Vector apps, ProgressListener listener) { this.repo = repo; this.apps = apps; pubkey = null; + progressListener = listener; } @Override @@ -225,7 +234,6 @@ public class RepoXMLHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - super.startElement(uri, localName, qName, attributes); if (localName == "repo") { String pk = attributes.getValue("", "pubkey"); @@ -234,6 +242,8 @@ public class RepoXMLHandler extends DefaultHandler { } else if (localName == "application" && curapp == null) { curapp = new DB.App(); curapp.detail_Populated = true; + progressCounter ++; + progressListener.onProgress(RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, totalAppCount); } else if (localName == "package" && curapp != null && curapk == null) { curapk = new DB.Apk(); curapk.id = curapp.id; @@ -252,29 +262,38 @@ public class RepoXMLHandler extends DefaultHandler { // empty) may contain an etag value for the response, or it may be left // empty if none was available. private static int getRemoteFile(Context ctx, String url, String dest, - String etag, StringBuilder retag) throws MalformedURLException, + String etag, StringBuilder retag, + ProgressListener progressListener ) throws MalformedURLException, IOException { long startTime = System.currentTimeMillis(); URL u = new URL(url); - HttpURLConnection uc = (HttpURLConnection) u.openConnection(); + HttpURLConnection connection = (HttpURLConnection) u.openConnection(); if (etag != null) - uc.setRequestProperty("If-None-Match", etag); + connection.setRequestProperty("If-None-Match", etag); int totalBytes = 0; - int code = uc.getResponseCode(); + int code = connection.getResponseCode(); if (code == 200) { + // Testing in the emulator for me, showed that figuring out the filesize took about 1 to 1.5 seconds. + // To put this in context, downloading a repo of: + // - 400k takes ~6 seconds + // - 5k takes ~3 seconds + // on my connection. I think the 1/1.5 seconds is worth it, because as the repo grows, the tradeoff will + // become more worth it. + int size = connection.getContentLength(); + Log.d("FDroid", "Downloading " + size + " bytes from " + url); InputStream input = null; OutputStream output = null; try { - input = new URL(url).openStream(); + input = connection.getInputStream(); output = ctx.openFileOutput(dest, Context.MODE_PRIVATE); - Utils.copy(input, output); + Utils.copy(input, output, size, progressListener, PROGRESS_TYPE_DOWNLOAD); } finally { Utils.closeQuietly(output); Utils.closeQuietly(input); } - String et = uc.getHeaderField("ETag"); + String et = connection.getHeaderField("ETag"); if (et != null) retag.append(et); } @@ -293,7 +312,8 @@ public class RepoXMLHandler extends DefaultHandler { // value for the index that was successfully processed, or it may contain // null if none was available. public static String doUpdate(Context ctx, DB.Repo repo, - Vector apps, StringBuilder newetag, Vector keeprepos) { + Vector apps, StringBuilder newetag, Vector keeprepos, + ProgressListener progressListener) { try { int code = 0; @@ -310,7 +330,7 @@ public class RepoXMLHandler extends DefaultHandler { } catch (Exception e) { } code = getRemoteFile(ctx, address, "tempindex.jar", - repo.lastetag, newetag); + repo.lastetag, newetag, progressListener); if (code == 200) { String jarpath = ctx.getFilesDir() + "/tempindex.jar"; JarFile jar = null; @@ -366,7 +386,7 @@ public class RepoXMLHandler extends DefaultHandler { // It's an old-fashioned unsigned repo... Log.d("FDroid", "Getting unsigned index from " + repo.address); code = getRemoteFile(ctx, repo.address + "/index.xml", - "tempindex.xml", repo.lastetag, newetag); + "tempindex.xml", repo.lastetag, newetag, progressListener); } if (code == 200) { @@ -374,11 +394,22 @@ public class RepoXMLHandler extends DefaultHandler { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps); + RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps, progressListener); xr.setContentHandler(handler); - Reader r = new BufferedReader(new FileReader(new File( - ctx.getFilesDir() + "/tempindex.xml"))); + File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml"); + BufferedReader r = new BufferedReader(new FileReader(tempIndex)); + + // A bit of a hack, this might return false positives if an apps description + // or some other part of the XML file contains this, but it is a pretty good + // estimate and makes the progress counter more informative. + // As with asking the server about the size of the index before downloading, + // this also has a time tradeoff. It takes about three seconds to iterate + // through the file and count 600 apps on a slow emulator (v17), but if it is + // taking two minutes to update, the three second wait may be worth it. + final String APPLICATION = " 0) + resultData.putString(RESULT_MESSAGE, message); + receiver.send( statusCode, resultData ); + } + } + + /** + * We might be doing a scheduled run, or we might have been launched by + * the app in response to a user's request. If we have a receiver, it's + * the latter... + */ + private boolean isScheduledRun() { + return receiver == null; + } + protected void onHandleIntent(Intent intent) { - // We might be doing a scheduled run, or we might have been launched by - // the app in response to a user's request. If we get this receiver, - // it's - // the latter... - ResultReceiver receiver = intent.getParcelableExtra("receiver"); + receiver = intent.getParcelableExtra("receiver"); long startTime = System.currentTimeMillis(); String errmsg = ""; - try { SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(getBaseContext()); // See if it's time to actually do anything yet... - if (receiver == null) { + if (isScheduledRun()) { long lastUpdate = prefs.getLong("lastUpdateCheck", 0); String sint = prefs.getString("updateInterval", "0"); int interval = Integer.parseInt(sint); @@ -124,9 +148,12 @@ public class UpdateService extends IntentService { boolean success = true; for (DB.Repo repo : repos) { if (repo.inuse) { + + sendStatus(STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); + StringBuilder newetag = new StringBuilder(); String err = RepoXMLHandler.doUpdate(getBaseContext(), - repo, apps, newetag, keeprepos); + repo, apps, newetag, keeprepos, this); if (err == null) { repo.lastetag = newetag.toString(); } else { @@ -142,6 +169,7 @@ public class UpdateService extends IntentService { } if (success) { + sendStatus(STATUS_INFO, getString(R.string.status_checking_compatibility)); Vector acceptedapps = new Vector(); Vector prevapps = ((FDroidApp) getApplication()) .getApps(); @@ -234,17 +262,12 @@ public class UpdateService extends IntentService { } } - if (receiver != null) { - Bundle resultData = new Bundle(); - if (!success) { - if (errmsg.length() == 0) - errmsg = "Unknown error"; - resultData.putString("errmsg", errmsg); - receiver.send(1, resultData); - } else { - receiver.send(0, resultData); - } - + if (!success) { + if (errmsg.length() == 0) + errmsg = "Unknown error"; + sendStatus(STATUS_ERROR, errmsg); + } else { + sendStatus(STATUS_COMPLETE); } if(success) { @@ -257,19 +280,15 @@ public class UpdateService extends IntentService { Log.e("FDroid", "Exception during update processing:\n" + Log.getStackTraceString(e)); - if (receiver != null) { - Bundle resultData = new Bundle(); - if (errmsg.length() == 0) - errmsg = "Unknown error"; - resultData.putString("errmsg", errmsg); - receiver.send(1, resultData); - } + if (errmsg.length() == 0) + errmsg = "Unknown error"; + sendStatus(STATUS_ERROR, errmsg); } finally { Log.d("FDroid", "Update took " + ((System.currentTimeMillis() - startTime) / 1000) + " seconds."); + receiver = null; } - } private void getIcon(DB.App app, Vector repos) { @@ -306,4 +325,23 @@ public class UpdateService extends IntentService { } } + /** + * Received progress event from the RepoXMLHandler. + * It could be progress downloading from the repo, or perhaps processing the info from the repo. + */ + @Override + public void onProgress(int type, int progress, int total) { + + String message = ""; + if (type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { + String downloadedSize = Utils.getFriendlySize( progress ); + String totalSize = Utils.getFriendlySize( total ); + int percent = (int)((double)progress/total * 100); + message = getString(R.string.status_download, downloadedSize, totalSize, percent); + } else if (type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { + message = getString(R.string.status_processing_xml, progress, total); + } + + sendStatus(STATUS_INFO, message); + } } diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index 14dad6be0..d0d5bfe2f 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -22,6 +22,10 @@ import java.io.Closeable; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; public final class Utils { private Utils() { @@ -29,18 +33,32 @@ public final class Utils { public static final int BUFFER_SIZE = 4096; - public static void copy(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[BUFFER_SIZE]; - while (true) { - int count = input.read(buffer); - if (count == -1) { - break; - } - output.write(buffer, 0, count); - } - output.flush(); - } + private static final String[] FRIENDLY_SIZE_FORMAT = { + "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; + + + public static void copy(InputStream input, OutputStream output) + throws IOException { + copy(input, output, -1, null, -1); + } + + public static void copy(InputStream input, OutputStream output, int totalSize, ProgressListener progressListener, int progressType) + throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = 0; + while (true) { + int count = input.read(buffer); + if (count == -1) { + break; + } + if (progressListener != null) { + bytesRead += count; + progressListener.onProgress(progressType, bytesRead, totalSize); + } + output.write(buffer, 0, count); + } + output.flush(); + } public static void closeQuietly(Closeable closeable) { if (closeable == null) { @@ -52,4 +70,52 @@ public final class Utils { // ignore } } + + public static String getFriendlySize(int size) { + double s = size; + int i = 0; + while (i < FRIENDLY_SIZE_FORMAT.length - 1 && s >= 1024) { + s = (100 * s / 1024) / 100.0; + i++; + } + return String.format(FRIENDLY_SIZE_FORMAT[i], s); + } + + public static int countSubstringOccurrence(File file, String substring) throws IOException { + int count = 0; + BufferedReader reader = null; + try { + + reader = new BufferedReader(new FileReader(file)); + while(true) { + String line = reader.readLine(); + if (line == null) { + break; + } + count += countSubstringOccurrence(line, substring); + } + + } finally { + closeQuietly(reader); + } + return count; + } + + /** + * Thanks to http://stackoverflow.com/a/767910 + */ + public static int countSubstringOccurrence(String toSearch, String substring) { + int count = 0; + int index = 0; + while (true) { + index = toSearch.indexOf(substring, index); + if (index == -1){ + break; + } + count ++; + index += substring.length(); + } + return count; + } + } From 841ec9d2896c49c29cdbb57d65ef158d0a0e63b8 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Tue, 16 Apr 2013 12:45:51 +1000 Subject: [PATCH 09/10] Make progress more multi-repo aware. Changed strings.xml to reflect the multi-repo nature of updating. Also refactored progress events to make them more generic and easier to nest deeply down the call stack. The ProgressListener now just expects a ProgressListener.Event, which in addition to statically typed type and progress info, also has an associated Bundle which can store arbitrary data. --- res/values/strings.xml | 11 ++-- src/org/fdroid/fdroid/ProgressListener.java | 49 +++++++++++++++++- src/org/fdroid/fdroid/RepoXMLHandler.java | 54 +++++++++++++------- src/org/fdroid/fdroid/UpdateService.java | 18 ++++--- src/org/fdroid/fdroid/Utils.java | 56 +++++++++------------ 5 files changed, 126 insertions(+), 62 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 26f5c031f..3a064405c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -153,14 +153,15 @@ Recently Updated - Downloading %1$s / %2$s (%3$d%%) - Processing application %1$d of %2$d - Connecting to repository:\n%1$s - Checking apps compatibility with your device… + Downloading\n%2$s / %3$s (%4$d%%) from\n%1$s + Processing application\n%2$d of %3$d from\n%1$s + Connecting to\n%1$s + Checking all apps compatibility with your device… diff --git a/src/org/fdroid/fdroid/ProgressListener.java b/src/org/fdroid/fdroid/ProgressListener.java index 2ec97ed92..d38e342cd 100644 --- a/src/org/fdroid/fdroid/ProgressListener.java +++ b/src/org/fdroid/fdroid/ProgressListener.java @@ -1,7 +1,54 @@ package org.fdroid.fdroid; +import android.os.Bundle; + public interface ProgressListener { - public void onProgress(int type, int progress, int total); + public void onProgress(Event event); + + // I went a bit overboard with the overloaded constructors, but they all + // seemed potentially useful and unambiguous, so I just put them in there + // while I'm here. + public static class Event { + + public static final int NO_VALUE = Integer.MIN_VALUE; + + public final int type; + public final Bundle data; + + // These two are not final, so that you can create a template Event, + // pass it into a function which performs something over time, and + // that function can initialize "total" and progressively + // update "progress" + public int progress; + public int total; + + public Event(int type) { + this(type, NO_VALUE, NO_VALUE, null); + } + + public Event(int type, Bundle data) { + this(type, NO_VALUE, NO_VALUE, data); + } + + public Event(int type, int progress) { + this(type, progress, NO_VALUE, null); + } + + public Event(int type, int progress, Bundle data) { + this(type, NO_VALUE, NO_VALUE, data); + } + + public Event(int type, int progress, int total) { + this(type, progress, total, null); + } + + public Event(int type, int progress, int total, Bundle data) { + this.type = type; + this.progress = progress; + this.total = total; + this.data = data == null ? new Bundle() : data; + } + } } diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index f8844dc9b..2c9ce8917 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -42,6 +42,7 @@ import javax.net.ssl.SSLHandshakeException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import android.os.Bundle; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -55,8 +56,8 @@ import android.util.Log; public class RepoXMLHandler extends DefaultHandler { - // The ID of the repo we're processing. - private int repo; + // The repo we're processing. + private DB.Repo repo; private Vector apps; @@ -73,11 +74,13 @@ public class RepoXMLHandler extends DefaultHandler { public static final int PROGRESS_TYPE_DOWNLOAD = 1; public static final int PROGRESS_TYPE_PROCESS_XML = 2; + public static final String PROGRESS_DATA_REPO = "repo"; + // The date format used in the repo XML file. private SimpleDateFormat mXMLDateFormat = new SimpleDateFormat("yyyy-MM-dd"); private int totalAppCount; - public RepoXMLHandler(int repo, Vector apps, ProgressListener listener) { + public RepoXMLHandler(DB.Repo repo, Vector apps, ProgressListener listener) { this.repo = repo; this.apps = apps; pubkey = null; @@ -228,28 +231,37 @@ public class RepoXMLHandler extends DefaultHandler { curapp.requirements = DB.CommaSeparatedList.make(str); } } - } + private static Bundle createProgressData(String repoAddress) { + Bundle data = new Bundle(); + data.putString(PROGRESS_DATA_REPO, repoAddress); + return data; + } + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { super.startElement(uri, localName, qName, attributes); - if (localName == "repo") { + if (localName.equals("repo")) { String pk = attributes.getValue("", "pubkey"); if (pk != null) pubkey = pk; - } else if (localName == "application" && curapp == null) { + } else if (localName.equals("application") && curapp == null) { curapp = new DB.App(); curapp.detail_Populated = true; + Bundle progressData = createProgressData(repo.address); progressCounter ++; - progressListener.onProgress(RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, totalAppCount); - } else if (localName == "package" && curapp != null && curapk == null) { + progressListener.onProgress( + new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML, progressCounter, + totalAppCount, progressData)); + } else if (localName.equals("package") && curapp != null && curapk == null) { curapk = new DB.Apk(); curapk.id = curapp.id; - curapk.repo = repo; + curapk.repo = repo.id; hashType = null; - } else if (localName == "hash" && curapk != null) { + } else if (localName.equals("hash") && curapk != null) { hashType = attributes.getValue("", "type"); } curchars.setLength(0); @@ -263,7 +275,8 @@ public class RepoXMLHandler extends DefaultHandler { // empty if none was available. private static int getRemoteFile(Context ctx, String url, String dest, String etag, StringBuilder retag, - ProgressListener progressListener ) throws MalformedURLException, + ProgressListener progressListener, + ProgressListener.Event progressEvent) throws MalformedURLException, IOException { long startTime = System.currentTimeMillis(); @@ -280,14 +293,14 @@ public class RepoXMLHandler extends DefaultHandler { // - 5k takes ~3 seconds // on my connection. I think the 1/1.5 seconds is worth it, because as the repo grows, the tradeoff will // become more worth it. - int size = connection.getContentLength(); - Log.d("FDroid", "Downloading " + size + " bytes from " + url); + progressEvent.total = connection.getContentLength(); + Log.d("FDroid", "Downloading " + progressEvent.total + " bytes from " + url); InputStream input = null; OutputStream output = null; try { input = connection.getInputStream(); output = ctx.openFileOutput(dest, Context.MODE_PRIVATE); - Utils.copy(input, output, size, progressListener, PROGRESS_TYPE_DOWNLOAD); + Utils.copy(input, output, progressListener, progressEvent); } finally { Utils.closeQuietly(output); Utils.closeQuietly(input); @@ -329,8 +342,11 @@ public class RepoXMLHandler extends DefaultHandler { address += "?" + pi.versionName; } catch (Exception e) { } + Bundle progressData = createProgressData(repo.address); + ProgressListener.Event event = new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, progressData); code = getRemoteFile(ctx, address, "tempindex.jar", - repo.lastetag, newetag, progressListener); + repo.lastetag, newetag, progressListener, event ); if (code == 200) { String jarpath = ctx.getFilesDir() + "/tempindex.jar"; JarFile jar = null; @@ -385,8 +401,12 @@ public class RepoXMLHandler extends DefaultHandler { // It's an old-fashioned unsigned repo... Log.d("FDroid", "Getting unsigned index from " + repo.address); + Bundle eventData = createProgressData(repo.address); + ProgressListener.Event event = new ProgressListener.Event( + RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD, eventData); code = getRemoteFile(ctx, repo.address + "/index.xml", - "tempindex.xml", repo.lastetag, newetag, progressListener); + "tempindex.xml", repo.lastetag, newetag, + progressListener, event); } if (code == 200) { @@ -394,7 +414,7 @@ public class RepoXMLHandler extends DefaultHandler { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader(); - RepoXMLHandler handler = new RepoXMLHandler(repo.id, apps, progressListener); + RepoXMLHandler handler = new RepoXMLHandler(repo, apps, progressListener); xr.setContentHandler(handler); File tempIndex = new File(ctx.getFilesDir() + "/tempindex.xml"); diff --git a/src/org/fdroid/fdroid/UpdateService.java b/src/org/fdroid/fdroid/UpdateService.java index 667e5ab4e..084af18c0 100644 --- a/src/org/fdroid/fdroid/UpdateService.java +++ b/src/org/fdroid/fdroid/UpdateService.java @@ -330,16 +330,18 @@ public class UpdateService extends IntentService implements ProgressListener { * It could be progress downloading from the repo, or perhaps processing the info from the repo. */ @Override - public void onProgress(int type, int progress, int total) { + public void onProgress(ProgressListener.Event event) { String message = ""; - if (type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { - String downloadedSize = Utils.getFriendlySize( progress ); - String totalSize = Utils.getFriendlySize( total ); - int percent = (int)((double)progress/total * 100); - message = getString(R.string.status_download, downloadedSize, totalSize, percent); - } else if (type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { - message = getString(R.string.status_processing_xml, progress, total); + if (event.type == RepoXMLHandler.PROGRESS_TYPE_DOWNLOAD) { + String repoAddress = event.data.getString(RepoXMLHandler.PROGRESS_DATA_REPO); + String downloadedSize = Utils.getFriendlySize( event.progress ); + String totalSize = Utils.getFriendlySize( event.total ); + int percent = (int)((double)event.progress/event.total * 100); + message = getString(R.string.status_download, repoAddress, downloadedSize, totalSize, percent); + } else if (event.type == RepoXMLHandler.PROGRESS_TYPE_PROCESS_XML) { + String repoAddress = event.data.getString(RepoXMLHandler.PROGRESS_DATA_REPO); + message = getString(R.string.status_processing_xml, repoAddress, event.progress, event.total); } sendStatus(STATUS_INFO, message); diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index d0d5bfe2f..4d73e5d2c 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -18,18 +18,9 @@ package org.fdroid.fdroid; -import java.io.Closeable; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; +import java.io.*; public final class Utils { - private Utils() { - } public static final int BUFFER_SIZE = 4096; @@ -37,28 +28,31 @@ public final class Utils { "%.0f B", "%.0f KiB", "%.1f MiB", "%.2f GiB" }; - public static void copy(InputStream input, OutputStream output) - throws IOException { - copy(input, output, -1, null, -1); - } + public static void copy(InputStream input, OutputStream output) + throws IOException { + copy(input, output, null, null); + } - public static void copy(InputStream input, OutputStream output, int totalSize, ProgressListener progressListener, int progressType) - throws IOException { - byte[] buffer = new byte[BUFFER_SIZE]; - int bytesRead = 0; - while (true) { - int count = input.read(buffer); - if (count == -1) { - break; - } - if (progressListener != null) { - bytesRead += count; - progressListener.onProgress(progressType, bytesRead, totalSize); - } - output.write(buffer, 0, count); - } - output.flush(); - } + public static void copy(InputStream input, OutputStream output, + ProgressListener progressListener, + ProgressListener.Event templateProgressEvent) + throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = 0; + while (true) { + int count = input.read(buffer); + if (count == -1) { + break; + } + if (progressListener != null) { + bytesRead += count; + templateProgressEvent.progress = bytesRead; + progressListener.onProgress(templateProgressEvent); + } + output.write(buffer, 0, count); + } + output.flush(); + } public static void closeQuietly(Closeable closeable) { if (closeable == null) { From 5ed815a34873f1dffb43220d569bc56c55799cbe Mon Sep 17 00:00:00 2001 From: Ciaran Gultnieks Date: Tue, 16 Apr 2013 09:59:24 +0100 Subject: [PATCH 10/10] Clean up of imports after merges --- src/org/fdroid/fdroid/DB.java | 1 - src/org/fdroid/fdroid/FDroid.java | 11 ----------- src/org/fdroid/fdroid/RepoXMLHandler.java | 2 -- src/org/fdroid/fdroid/Utils.java | 3 +++ .../fdroid/views/AppListFragmentPageAdapter.java | 7 ------- .../fdroid/views/fragments/AppListFragment.java | 1 - .../fdroid/views/fragments/AvailableAppsFragment.java | 3 +-- .../fdroid/views/fragments/InstalledAppsFragment.java | 1 - 8 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/org/fdroid/fdroid/DB.java b/src/org/fdroid/fdroid/DB.java index bc36ca9db..2f55a8e94 100644 --- a/src/org/fdroid/fdroid/DB.java +++ b/src/org/fdroid/fdroid/DB.java @@ -41,7 +41,6 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.os.Build; import android.os.Environment; import android.preference.PreferenceManager; import android.text.TextUtils.SimpleStringSplitter; diff --git a/src/org/fdroid/fdroid/FDroid.java b/src/org/fdroid/fdroid/FDroid.java index 88c32b654..9278bc7d8 100644 --- a/src/org/fdroid/fdroid/FDroid.java +++ b/src/org/fdroid/fdroid/FDroid.java @@ -19,19 +19,9 @@ package org.fdroid.fdroid; -import android.app.ActionBar; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - import android.support.v4.view.MenuItemCompat; -import org.fdroid.fdroid.DB.App; import org.fdroid.fdroid.R; -import android.R.drawable; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.ProgressDialog; @@ -44,7 +34,6 @@ 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; diff --git a/src/org/fdroid/fdroid/RepoXMLHandler.java b/src/org/fdroid/fdroid/RepoXMLHandler.java index 27e6300fb..6ad04fd7c 100644 --- a/src/org/fdroid/fdroid/RepoXMLHandler.java +++ b/src/org/fdroid/fdroid/RepoXMLHandler.java @@ -26,11 +26,9 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.Reader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLConnection; import java.security.cert.Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/src/org/fdroid/fdroid/Utils.java b/src/org/fdroid/fdroid/Utils.java index d9d926a45..d1679cbce 100644 --- a/src/org/fdroid/fdroid/Utils.java +++ b/src/org/fdroid/fdroid/Utils.java @@ -20,7 +20,10 @@ package org.fdroid.fdroid; import android.os.Build; +import java.io.BufferedReader; import java.io.Closeable; +import java.io.File; +import java.io.FileReader; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; diff --git a/src/org/fdroid/fdroid/views/AppListFragmentPageAdapter.java b/src/org/fdroid/fdroid/views/AppListFragmentPageAdapter.java index e817ebd29..069fc37fc 100644 --- a/src/org/fdroid/fdroid/views/AppListFragmentPageAdapter.java +++ b/src/org/fdroid/fdroid/views/AppListFragmentPageAdapter.java @@ -1,14 +1,7 @@ package org.fdroid.fdroid.views; -import android.os.Bundle; -import android.os.Parcelable; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import org.fdroid.fdroid.AppListManager; import org.fdroid.fdroid.FDroid; import org.fdroid.fdroid.R; import org.fdroid.fdroid.views.fragments.AvailableAppsFragment; diff --git a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java index 33ef1b060..e5728221e 100644 --- a/src/org/fdroid/fdroid/views/fragments/AppListFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/AppListFragment.java @@ -3,7 +3,6 @@ package org.fdroid.fdroid.views.fragments; import android.app.Activity; import android.content.Intent; import android.support.v4.app.Fragment; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; diff --git a/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java b/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java index f513e3f13..c5955efc4 100644 --- a/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/AvailableAppsFragment.java @@ -1,13 +1,12 @@ package org.fdroid.fdroid.views.fragments; import android.os.Bundle; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.*; + import org.fdroid.fdroid.AppListAdapter; -import org.fdroid.fdroid.AppListManager; import org.fdroid.fdroid.R; import org.fdroid.fdroid.views.AppListView; diff --git a/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java b/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java index e6b48f35f..628ddf9b4 100644 --- a/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java +++ b/src/org/fdroid/fdroid/views/fragments/InstalledAppsFragment.java @@ -4,7 +4,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; import org.fdroid.fdroid.AppListAdapter; public class InstalledAppsFragment extends AppListFragment {