Backed out 3 changesets (bug 1265525) for android rc1 failures in testBrowserProvider
authorWes Kocher <wkocher@mozilla.com>
Wed, 27 Apr 2016 15:49:20 -0700
changeset 357098 4d32f073e413d9209d710b032557e2517bb3bbd5
parent 357097 5d2ffa365918a0991fbc8b985dc22d77bb3f613d
child 357099 1d2eb27cf2f3e012b15eda6e8c225db2d3b53613
push id16695
push usermichael.l.comella@gmail.com
push dateThu, 28 Apr 2016 00:43:09 +0000
bugs1265525
milestone49.0a1
backs out64ff3f5121d75d61e6f6a9798240f7a79332d006
d34dc8387cd4cc4e018bd358488dd3d9c8e9dfa4
0f659fc840cd218a8ffd6c8b79a49a3e6166ad3d
Backed out 3 changesets (bug 1265525) for android rc1 failures in testBrowserProvider Backed out changeset 64ff3f5121d7 (bug 1265525) Backed out changeset d34dc8387cd4 (bug 1265525) Backed out changeset 0f659fc840cd (bug 1265525) MozReview-Commit-ID: EeMHCLV0BMG
mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java
mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
mobile/android/tests/background/junit3/instrumentation.ini
mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java
mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java
mobile/android/tests/browser/robocop/assets/browser_db_upgrade/v32.db
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserContract.java
@@ -3,18 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.db;
 
 import org.mozilla.gecko.AppConstants;
 
 import android.net.Uri;
-import android.support.annotation.NonNull;
-
 import org.mozilla.gecko.annotation.RobocopTarget;
 
 @RobocopTarget
 public class BrowserContract {
     public static final String AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.browser";
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     public static final String PASSWORDS_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.passwords";
@@ -54,85 +52,29 @@ public class BrowserContract {
     public static final String PARAM_DATASET_ID = "dataset_id";
     public static final String PARAM_GROUP_BY = "group_by";
 
     static public enum ExpirePriority {
         NORMAL,
         AGGRESSIVE
     }
 
-    /**
-     * Produces a SQL expression used for sorting results of the "combined" view by frecency.
-     * Combines remote and local frecency calculations, weighting local visits much heavier.
-     *
-     * @param includesBookmarks When URL is bookmarked, should we give it bonus frecency points?
-     * @param ascending Indicates if sorting order ascending
-     * @return Combined frecency sorting expression
-     */
-    static public String getCombinedFrecencySortOrder(boolean includesBookmarks, boolean ascending) {
-        final long now = System.currentTimeMillis();
-        StringBuilder order = new StringBuilder(getRemoteFrecencySQL(now) + " + " + getLocalFrecencySQL(now));
+    static public String getFrecencySortOrder(boolean includesBookmarks, boolean asc) {
+        final String age = "(" + Combined.DATE_LAST_VISITED + " - " + System.currentTimeMillis() + ") / 86400000";
+
+        StringBuilder order = new StringBuilder(Combined.VISITS + " * MAX(1, 100 * 225 / (" + age + "*" + age + " + 225)) ");
 
         if (includesBookmarks) {
             order.insert(0, "(CASE WHEN " + Combined.BOOKMARK_ID + " > -1 THEN 100 ELSE 0 END) + ");
         }
 
-        order.append(ascending ? " ASC" : " DESC");
+        order.append(asc ? " ASC" : " DESC");
         return order.toString();
     }
 
-    /**
-     * See Bug 1265525 for details (explanation + graphs) on how Remote frecency compares to Local frecency for different
-     * combinations of visits count and age.
-     *
-     * @param now Base time in milliseconds for age calculation
-     * @return remote frecency SQL calculation
-     */
-    static public String getRemoteFrecencySQL(final long now) {
-        return getFrecencyCalculation(now, 1, 110, Combined.REMOTE_VISITS_COUNT, Combined.REMOTE_DATE_LAST_VISITED);
-    }
-
-    /**
-     * Local frecency SQL calculation. Note higher scale factor and squared visit count which achieve
-     * visits generated locally being much preferred over remote visits.
-     * See Bug 1265525 for details (explanation + comparison graphs).
-     *
-     * @param now Base time in milliseconds for age calculation
-     * @return local frecency SQL calculation
-     */
-    static public String getLocalFrecencySQL(final long now) {
-        String visitCountExpr = "(" + Combined.LOCAL_VISITS_COUNT + " + 2)";
-        visitCountExpr = visitCountExpr + " * " + visitCountExpr;
-
-        return getFrecencyCalculation(now, 2, 225, visitCountExpr, Combined.LOCAL_DATE_LAST_VISITED);
-    }
-
-    /**
-     * Our version of frecency is computed by scaling the number of visits by a multiplier
-     * that approximates Gaussian decay, based on how long ago the entry was last visited.
-     * Since we're limited by the math we can do with sqlite, we're calculating this
-     * approximation using the Cauchy distribution: multiplier = scale_const / (age^2 + scale_const).
-     * For example, with 15 as our scale parameter, we get a scale constant 15^2 = 225. Then:
-     * frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977)
-     *
-     * @param now Base time in milliseconds for age calculation
-     * @param minFrecency Minimum allowed frecency value
-     * @param multiplier Scale constant
-     * @param visitCountExpr Expression which will produce a visit count
-     * @param lastVisitExpr Expression which will produce "last-visited" timestamp
-     * @return Frecency SQL calculation
-     */
-    static public String getFrecencyCalculation(final long now, final int minFrecency, final int multiplier, @NonNull  final String visitCountExpr, @NonNull final String lastVisitExpr) {
-        final long nowInMicroseconds = now * 1000;
-        final long microsecondsPerDay = 86400000000L;
-        final String ageExpr = "(" + nowInMicroseconds + " - " + lastVisitExpr + ") / " + microsecondsPerDay;
-
-        return visitCountExpr + " * MAX(" + minFrecency + ", 100 * " + multiplier + " / (" + ageExpr + " * " + ageExpr + " + " + multiplier + "))";
-    }
-
     @RobocopTarget
     public interface CommonColumns {
         public static final String _ID = "_id";
     }
 
     @RobocopTarget
     public interface DateSyncColumns {
         public static final String DATE_CREATED = "created";
@@ -298,22 +240,16 @@ public class BrowserContract {
         public static final String VIEW_NAME = "combined";
 
         public static final String VIEW_WITH_FAVICONS = "combined_with_favicons";
 
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined");
 
         public static final String BOOKMARK_ID = "bookmark_id";
         public static final String HISTORY_ID = "history_id";
-
-        public static final String REMOTE_VISITS_COUNT = "remoteVisitCount";
-        public static final String REMOTE_DATE_LAST_VISITED = "remoteDateLastVisited";
-
-        public static final String LOCAL_VISITS_COUNT = "localVisitCount";
-        public static final String LOCAL_DATE_LAST_VISITED = "localDateLastVisited";
     }
 
     public static final class Schema {
         private Schema() {}
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "schema");
 
         public static final String VERSION = "version";
     }
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserDatabaseHelper.java
@@ -53,17 +53,17 @@ import android.util.Log;
 
 
 // public for robocop testing
 public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
     private static final String LOGTAG = "GeckoBrowserDBHelper";
 
     // Replace the Bug number below with your Bug that is conducting a DB upgrade, as to force a merge conflict with any
     // other patches that require a DB upgrade.
-    public static final int DATABASE_VERSION = 33; // Bug 1265525
+    public static final int DATABASE_VERSION = 32; // Bug 1046709
     public static final String DATABASE_NAME = "browser.db";
 
     final protected Context mContext;
 
     static final String TABLE_BOOKMARKS = Bookmarks.TABLE_NAME;
     static final String TABLE_HISTORY = History.TABLE_NAME;
     static final String TABLE_VISITS = Visits.TABLE_NAME;
     static final String TABLE_FAVICONS = Favicons.TABLE_NAME;
@@ -381,143 +381,16 @@ public final class BrowserDatabaseHelper
                 " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " +
                     qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " +
                     qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON +
                 " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS +
                     " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID));
 
     }
 
-    private void createCombinedViewOn33(final SQLiteDatabase db) {
-        /*
-        Builds on top of v19 combined view, and adds the following aggregates:
-        - Combined.LOCAL_DATE_LAST_VISITED - last date visited for all local visits
-        - Combined.REMOTE_DATE_LAST_VISITED - last date visited for all remote visits
-        - Combined.LOCAL_VISITS_COUNT - total number of local visits
-        - Combined.REMOTE_VISITS_COUNT - total number of remote visits
-
-        Any code written prior to v33 referencing columns by index directly remains intact
-        (yet must die a fiery death), as new columns were added to the end of the list.
-
-        The rows in the ensuing view are, in order:
-            Combined.BOOKMARK_ID
-            Combined.HISTORY_ID
-            Combined._ID (always 0)
-            Combined.URL
-            Combined.TITLE
-            Combined.VISITS
-            Combined.DISPLAY
-            Combined.DATE_LAST_VISITED
-            Combined.FAVICON_ID
-            Combined.LOCAL_DATE_LAST_VISITED
-            Combined.REMOTE_DATE_LAST_VISITED
-            Combined.LOCAL_VISITS_COUNT
-            Combined.REMOTE_VISITS_COUNT
-         */
-        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED + " AS" +
-
-                // Bookmarks without history.
-                " SELECT " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) + " AS " + Combined.BOOKMARK_ID + "," +
-                "-1 AS " + Combined.HISTORY_ID + "," +
-                "0 AS " + Combined._ID + "," +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " AS " + Combined.URL + ", " +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + " AS " + Combined.TITLE + ", " +
-                "-1 AS " + Combined.VISITS + ", " +
-                "-1 AS " + Combined.DATE_LAST_VISITED + "," +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.FAVICON_ID) + " AS " + Combined.FAVICON_ID + "," +
-                "0 AS " + Combined.LOCAL_DATE_LAST_VISITED + ", " +
-                "0 AS " + Combined.REMOTE_DATE_LAST_VISITED + ", " +
-                "0 AS " + Combined.LOCAL_VISITS_COUNT + ", " +
-                "0 AS " + Combined.REMOTE_VISITS_COUNT +
-                " FROM " + TABLE_BOOKMARKS +
-                " WHERE " +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE)  + " = " + Bookmarks.TYPE_BOOKMARK + " AND " +
-                // Ignore pinned bookmarks.
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT)  + " <> " + Bookmarks.FIXED_PINNED_LIST_ID + " AND " +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED)  + " = 0 AND " +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) +
-                " NOT IN (SELECT " + History.URL + " FROM " + TABLE_HISTORY + ")" +
-                " UNION ALL" +
-
-                // History with and without bookmark.
-                " SELECT " +
-                "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.IS_DELETED) +
-
-                // Give pinned bookmarks a NULL ID so that they're not treated as bookmarks. We can't
-                // completely ignore them here because they're joined with history entries we care about.
-                " WHEN 0 THEN " +
-                "CASE " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.PARENT) +
-                " WHEN " + Bookmarks.FIXED_PINNED_LIST_ID + " THEN " +
-                "NULL " +
-                "ELSE " +
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks._ID) +
-                " END " +
-                "ELSE " +
-                "NULL " +
-                "END AS " + Combined.BOOKMARK_ID + "," +
-                qualifyColumn(TABLE_HISTORY, History._ID) + " AS " + Combined.HISTORY_ID + "," +
-                "0 AS " + Combined._ID + "," +
-                qualifyColumn(TABLE_HISTORY, History.URL) + " AS " + Combined.URL + "," +
-
-                // Prioritize bookmark titles over history titles, since the user may have
-                // customized the title for a bookmark.
-                "COALESCE(" + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TITLE) + ", " +
-                qualifyColumn(TABLE_HISTORY, History.TITLE) +
-                ") AS " + Combined.TITLE + "," +
-                qualifyColumn(TABLE_HISTORY, History.VISITS) + " AS " + Combined.VISITS + "," +
-                qualifyColumn(TABLE_HISTORY, History.DATE_LAST_VISITED) + " AS " + Combined.DATE_LAST_VISITED + "," +
-                qualifyColumn(TABLE_HISTORY, History.FAVICON_ID) + " AS " + Combined.FAVICON_ID + "," +
-
-                // Figure out "last visited" days using MAX values for visit timestamps.
-                // We use CASE statements here to separate local from remote visits.
-                "COALESCE(MAX(CASE " + qualifyColumn(TABLE_VISITS, Visits.IS_LOCAL) + " " +
-                    "WHEN 1 THEN " + qualifyColumn(TABLE_VISITS, Visits.DATE_VISITED) + " " +
-                    "ELSE 0 END" +
-                "), 0) AS " + Combined.LOCAL_DATE_LAST_VISITED + ", " +
-
-                "COALESCE(MAX(CASE " + qualifyColumn(TABLE_VISITS, Visits.IS_LOCAL) + " " +
-                    "WHEN 0 THEN " + qualifyColumn(TABLE_VISITS, Visits.DATE_VISITED) + " " +
-                    "ELSE 0 END" +
-                "), 0) AS " + Combined.REMOTE_DATE_LAST_VISITED + ", " +
-
-                // Sum up visit counts for local and remote visit types. Again, use CASE to separate the two.
-                "COALESCE(SUM(" + qualifyColumn(TABLE_VISITS, Visits.IS_LOCAL) + "), 0) AS " + Combined.LOCAL_VISITS_COUNT + ", " +
-                "COALESCE(SUM(CASE " + qualifyColumn(TABLE_VISITS, Visits.IS_LOCAL) + " WHEN 0 THEN 1 ELSE 0 END), 0) AS " + Combined.REMOTE_VISITS_COUNT +
-
-                // We need to JOIN on Visits in order to compute visit counts
-                " FROM " + TABLE_HISTORY + " " +
-                "INNER JOIN " + TABLE_VISITS +
-                " ON " + qualifyColumn(TABLE_HISTORY, History.GUID) + " = " + qualifyColumn(TABLE_VISITS, Visits.HISTORY_GUID) + " " +
-
-                // We really shouldn't be selecting deleted bookmarks, but oh well.
-                "LEFT OUTER JOIN " + TABLE_BOOKMARKS +
-                " ON " + qualifyColumn(TABLE_BOOKMARKS, Bookmarks.URL) + " = " + qualifyColumn(TABLE_HISTORY, History.URL) +
-                " WHERE " +
-                qualifyColumn(TABLE_HISTORY, History.IS_DELETED) + " = 0 AND " +
-                "(" +
-                // The left outer join didn't match...
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " IS NULL OR " +
-
-                // ... or it's a bookmark. This is less efficient than filtering prior
-                // to the join if you have lots of folders.
-                qualifyColumn(TABLE_BOOKMARKS, Bookmarks.TYPE) + " = " + Bookmarks.TYPE_BOOKMARK +
-
-                ") GROUP BY " + qualifyColumn(TABLE_HISTORY, History.GUID)
-        );
-
-        debug("Creating " + VIEW_COMBINED_WITH_FAVICONS + " view");
-
-        db.execSQL("CREATE VIEW IF NOT EXISTS " + VIEW_COMBINED_WITH_FAVICONS + " AS" +
-                " SELECT " + qualifyColumn(VIEW_COMBINED, "*") + ", " +
-                qualifyColumn(TABLE_FAVICONS, Favicons.URL) + " AS " + Combined.FAVICON_URL + ", " +
-                qualifyColumn(TABLE_FAVICONS, Favicons.DATA) + " AS " + Combined.FAVICON +
-                " FROM " + VIEW_COMBINED + " LEFT OUTER JOIN " + TABLE_FAVICONS +
-                " ON " + Combined.FAVICON_ID + " = " + qualifyColumn(TABLE_FAVICONS, Favicons._ID));
-    }
-
     private void createLoginsTable(SQLiteDatabase db, final String tableName) {
         debug("Creating logins.db: " + db.getPath());
         debug("Creating " + tableName + " table");
 
         // Table for each login.
         db.execSQL("CREATE TABLE " + tableName + "(" +
                 BrowserContract.Logins._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
                 BrowserContract.Logins.HOSTNAME + " TEXT NOT NULL," +
@@ -584,16 +457,17 @@ public final class BrowserDatabaseHelper
         createClientsTable(db);
         createLocalClient(db);
         createTabsTable(db, TABLE_TABS);
         createTabsTableIndices(db, TABLE_TABS);
 
 
         createBookmarksWithFaviconsView(db);
         createHistoryWithFaviconsView(db);
+        createCombinedViewOn19(db);
 
         createOrUpdateSpecialFolder(db, Bookmarks.PLACES_FOLDER_GUID,
             R.string.bookmarks_folder_places, 0);
 
         createOrUpdateAllSpecialFolders(db);
         createSearchHistoryTable(db);
         createUrlAnnotationsTable(db);
         createNumbersTable(db);
@@ -601,17 +475,16 @@ public final class BrowserDatabaseHelper
         createDeletedLoginsTable(db, TABLE_DELETED_LOGINS);
         createDisabledHostsTable(db, TABLE_DISABLED_HOSTS);
         createLoginsTable(db, TABLE_LOGINS);
         createLoginsTableIndices(db, TABLE_LOGINS);
 
         createBookmarksWithAnnotationsView(db);
 
         createVisitsTable(db);
-        createCombinedViewOn33(db);
     }
 
     /**
      * Copies the tabs and clients tables out of the given tabs.db file and into the destinationDB.
      *
      * @param tabsDBFile Path to existing tabs.db.
      * @param destinationDB The destination database.
      */
@@ -1752,27 +1625,16 @@ public final class BrowserDatabaseHelper
             } while (cursor.moveToNext());
         } catch (Exception e) {
             Log.e(LOGTAG, "Error while synthesizing visits for history record", e);
         } finally {
             cursor.close();
         }
     }
 
-    private void upgradeDatabaseFrom32to33(final SQLiteDatabase db) {
-        createV33CombinedView(db);
-    }
-
-    private void createV33CombinedView(final SQLiteDatabase db) {
-        db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
-        db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
-
-        createCombinedViewOn33(db);
-    }
-
     private void createV19CombinedView(SQLiteDatabase db) {
         db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
         db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
 
         createCombinedViewOn19(db);
     }
 
     @Override
@@ -1868,20 +1730,16 @@ public final class BrowserDatabaseHelper
 
                 case 31:
                     upgradeDatabaseFrom30to31(db);
                     break;
 
                 case 32:
                     upgradeDatabaseFrom31to32(db);
                     break;
-
-                case 33:
-                    upgradeDatabaseFrom32to33(db);
-                    break;
             }
         }
 
         for (Table table : BrowserProvider.sTables) {
             table.onUpgrade(db, oldVersion, newVersion);
         }
 
         // Delete the obsolete favicon database after all other upgrades complete.
--- a/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/BrowserProvider.java
@@ -243,20 +243,16 @@ public class BrowserProvider extends Sha
         map.put(Combined.HISTORY_ID, Combined.HISTORY_ID);
         map.put(Combined.URL, Combined.URL);
         map.put(Combined.TITLE, Combined.TITLE);
         map.put(Combined.VISITS, Combined.VISITS);
         map.put(Combined.DATE_LAST_VISITED, Combined.DATE_LAST_VISITED);
         map.put(Combined.FAVICON, Combined.FAVICON);
         map.put(Combined.FAVICON_ID, Combined.FAVICON_ID);
         map.put(Combined.FAVICON_URL, Combined.FAVICON_URL);
-        map.put(Combined.LOCAL_DATE_LAST_VISITED, Combined.LOCAL_DATE_LAST_VISITED);
-        map.put(Combined.REMOTE_DATE_LAST_VISITED, Combined.REMOTE_DATE_LAST_VISITED);
-        map.put(Combined.LOCAL_VISITS_COUNT, Combined.LOCAL_VISITS_COUNT);
-        map.put(Combined.REMOTE_VISITS_COUNT, Combined.REMOTE_VISITS_COUNT);
         COMBINED_PROJECTION_MAP = Collections.unmodifiableMap(map);
 
         // Schema
         URI_MATCHER.addURI(BrowserContract.AUTHORITY, "schema", SCHEMA);
 
         map = new HashMap<String, String>();
         map.put(Schema.VERSION, Schema.VERSION);
         SCHEMA_PROJECTION_MAP = Collections.unmodifiableMap(map);
@@ -320,17 +316,17 @@ public class BrowserProvider extends Sha
         Log.d(LOGTAG, "Expiring history.");
         final long rows = DatabaseUtils.queryNumEntries(db, TABLE_HISTORY);
 
         if (retain >= rows) {
             debug("Not expiring history: only have " + rows + " rows.");
             return;
         }
 
-        final String sortOrder = BrowserContract.getCombinedFrecencySortOrder(false, true);
+        final String sortOrder = BrowserContract.getFrecencySortOrder(false, true);
         final long toRemove = rows - retain;
         debug("Expiring at most " + toRemove + " rows earlier than " + keepAfter + ".");
 
         final String sql;
         if (keepAfter > 0) {
             sql = "DELETE FROM " + TABLE_HISTORY + " " +
                   "WHERE MAX(" + History.DATE_LAST_VISITED + ", " + History.DATE_MODIFIED + ") < " + keepAfter + " " +
                   " AND " + History._ID + " IN ( SELECT " +
@@ -351,17 +347,17 @@ public class BrowserProvider extends Sha
     /**
      * Remove any thumbnails that for sites that aren't likely to be ever shown.
      * Items will be removed according to a frecency calculation and only if they are not pinned
      *
      * Call this method within a transaction.
      */
     private void expireThumbnails(final SQLiteDatabase db) {
         Log.d(LOGTAG, "Expiring thumbnails.");
-        final String sortOrder = BrowserContract.getCombinedFrecencySortOrder(true, false);
+        final String sortOrder = BrowserContract.getFrecencySortOrder(true, false);
         final String sql = "DELETE FROM " + TABLE_THUMBNAILS +
                            " WHERE " + Thumbnails.URL + " NOT IN ( " +
                              " SELECT " + Combined.URL +
                              " FROM " + Combined.VIEW_NAME +
                              " ORDER BY " + sortOrder +
                              " LIMIT " + DEFAULT_EXPIRY_THUMBNAIL_COUNT +
                            ") AND " + Thumbnails.URL + " NOT IN ( " +
                              " SELECT " + Bookmarks.URL +
@@ -897,17 +893,17 @@ public class BrowserProvider extends Sha
                        Combined.BOOKMARK_ID + ", " +
                        Combined.HISTORY_ID + ", " +
                        Bookmarks.URL + ", " +
                        Bookmarks.TITLE + ", " +
                        Combined.HISTORY_ID + ", " +
                        TopSites.TYPE_TOP + " AS " + TopSites.TYPE +
                        " FROM " + Combined.VIEW_NAME +
                        " WHERE " + ignoreForTopSitesWhereClause +
-                       " ORDER BY " + BrowserContract.getCombinedFrecencySortOrder(true, false) +
+                       " ORDER BY " + BrowserContract.getFrecencySortOrder(true, false) +
                        " LIMIT " + totalLimit,
 
                        ignoreForTopSitesArgs);
 
             if (hasProcessedAnySuggestedSites) {
                 db.execSQL("INSERT INTO " + TABLE_TOPSITES +
                            // We need to LIMIT _after_ selecting the relevant suggested sites, which requires us to
                            // use an additional internal subquery, since we cannot LIMIT a subquery that is part of UNION ALL.
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalBrowserDB.java
@@ -564,20 +564,24 @@ public class LocalBrowserDB implements B
             }
         }
 
         if (urlFilter != null) {
             selection = DBUtils.concatenateWhere(selection, "(" + Combined.URL + " NOT LIKE ?)");
             selectionArgs = DBUtils.appendSelectionArgs(selectionArgs, new String[] { urlFilter.toString() });
         }
 
-        // Order by combined remote+local frecency score.
-        // Local visits are preferred, so they will by far outweigh remote visits.
-        // Bookmarked history items get extra frecency points.
-        final String sortOrder = BrowserContract.getCombinedFrecencySortOrder(true, false);
+        // Our version of frecency is computed by scaling the number of visits by a multiplier
+        // that approximates Gaussian decay, based on how long ago the entry was last visited.
+        // Since we're limited by the math we can do with sqlite, we're calculating this
+        // approximation using the Cauchy distribution: multiplier = 15^2 / (age^2 + 15^2).
+        // Using 15 as our scale parameter, we get a constant 15^2 = 225. Following this math,
+        // frecencyScore = numVisits * max(1, 100 * 225 / (age*age + 225)). (See bug 704977)
+        // We also give bookmarks an extra bonus boost by adding 100 points to their frecency score.
+        final String sortOrder = BrowserContract.getFrecencySortOrder(true, false);
 
         return cr.query(combinedUriWithLimit(limit),
                         projection,
                         selection,
                         selectionArgs,
                         sortOrder);
     }
 
--- a/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
+++ b/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
@@ -1,16 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 background_junit3_sources = [
     'src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java',
+    'src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java',
     'src/org/mozilla/gecko/background/common/TestUtils.java',
     'src/org/mozilla/gecko/background/common/TestWaitHelper.java',
     'src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java',
     'src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java',
     'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java',
     'src/org/mozilla/gecko/background/db/TestBookmarks.java',
     'src/org/mozilla/gecko/background/db/TestClientsDatabase.java',
     'src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java',
--- a/mobile/android/tests/background/junit3/instrumentation.ini
+++ b/mobile/android/tests/background/junit3/instrumentation.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 subsuite = background
 
 [src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java]
+[src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java]
 [src/org/mozilla/gecko/background/common/TestUtils.java]
 [src/org/mozilla/gecko/background/common/TestWaitHelper.java]
 [src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java]
 [src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java]
 [src/org/mozilla/gecko/background/db/TestBookmarks.java]
 [src/org/mozilla/gecko/background/db/TestClientsDatabase.java]
 [src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java]
 [src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java]
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.background.common;
+
+import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
+import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
+
+public class TestBrowserContractHelpers extends AndroidSyncTestCase {
+  public void testBookmarkCodes() {
+    final String[] strings = {
+      // Observe omissions: "microsummary", "item".
+      "folder", "bookmark", "separator", "livemark", "query"
+    };
+    for (int i = 0; i < strings.length; ++i) {
+      assertEquals(strings[i], BrowserContractHelpers.typeStringForCode(i));
+      assertEquals(i, BrowserContractHelpers.typeCodeForString(strings[i]));
+    }
+    assertEquals(null, BrowserContractHelpers.typeStringForCode(-1));
+    assertEquals(null, BrowserContractHelpers.typeStringForCode(100));
+
+    assertEquals(-1, BrowserContractHelpers.typeCodeForString(null));
+    assertEquals(-1, BrowserContractHelpers.typeCodeForString("folder "));
+    assertEquals(-1, BrowserContractHelpers.typeCodeForString("FOLDER"));
+    assertEquals(-1, BrowserContractHelpers.typeCodeForString(""));
+    assertEquals(-1, BrowserContractHelpers.typeCodeForString("nope"));
+  }
+}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/db/BrowserContractTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.db;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BrowserContractTest {
-    @Test
-    /**
-     * Test that bookmark and sorting order clauses are set correctly
-     */
-    public void testGetCombinedFrecencySortOrder() throws Exception {
-        String sqlNoBookmarksDesc = BrowserContract.getCombinedFrecencySortOrder(false, false);
-        String sqlNoBookmarksAsc = BrowserContract.getCombinedFrecencySortOrder(false, true);
-        String sqlBookmarksDesc = BrowserContract.getCombinedFrecencySortOrder(true, false);
-        String sqlBookmarksAsc = BrowserContract.getCombinedFrecencySortOrder(true, true);
-
-        assertTrue(sqlBookmarksAsc.endsWith(" ASC"));
-        assertTrue(sqlBookmarksDesc.endsWith(" DESC"));
-        assertTrue(sqlNoBookmarksAsc.endsWith(" ASC"));
-        assertTrue(sqlNoBookmarksDesc.endsWith(" DESC"));
-
-        assertTrue(sqlBookmarksAsc.startsWith("(CASE WHEN bookmark_id > -1 THEN 100 ELSE 0 END) + "));
-        assertTrue(sqlBookmarksDesc.startsWith("(CASE WHEN bookmark_id > -1 THEN 100 ELSE 0 END) + "));
-    }
-
-    @Test
-    /**
-     * Test that calculation string is correct for remote visits
-     * maxFrecency=1, scaleConst=110, correct sql params for visit count and last date
-     * and that time is converted to microseconds.
-     */
-    public void testGetRemoteFrecencySQL() throws Exception {
-        long now = 1;
-        String sql = BrowserContract.getRemoteFrecencySQL(now);
-        String ageExpr = "(" + now * 1000 + " - remoteDateLastVisited) / 86400000000";
-
-        assertEquals(
-                "remoteVisitCount * MAX(1, 100 * 110 / (" + ageExpr + " * " + ageExpr + " + 110))",
-                sql
-        );
-    }
-
-    @Test
-    /**
-     * Test that calculation string is correct for remote visits
-     * maxFrecency=2, scaleConst=225, correct sql params for visit count and last date
-     * and that time is converted to microseconds.
-     */
-    public void testGetLocalFrecencySQL() throws Exception {
-        long now = 1;
-        String sql = BrowserContract.getLocalFrecencySQL(now);
-        String ageExpr = "(" + now * 1000 + " - localDateLastVisited) / 86400000000";
-        String visitCountExpr = "(localVisitCount + 2) * (localVisitCount + 2)";
-
-        assertEquals(
-                visitCountExpr + " * MAX(2, 100 * 225 / (" + ageExpr + " * " + ageExpr + " + 225))",
-                sql
-        );
-    }
-}
\ No newline at end of file
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpersTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.sync.repositories.android;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import static org.junit.Assert.*;
-
-@RunWith(TestRunner.class)
-public class BrowserContractHelpersTest {
-    @Test
-    public void testBookmarkCodes() {
-        final String[] strings = {
-                // Observe omissions: "microsummary", "item".
-                "folder", "bookmark", "separator", "livemark", "query"
-        };
-        for (int i = 0; i < strings.length; ++i) {
-            assertEquals(strings[i], BrowserContractHelpers.typeStringForCode(i));
-            assertEquals(i, BrowserContractHelpers.typeCodeForString(strings[i]));
-        }
-        assertEquals(null, BrowserContractHelpers.typeStringForCode(-1));
-        assertEquals(null, BrowserContractHelpers.typeStringForCode(100));
-
-        assertEquals(-1, BrowserContractHelpers.typeCodeForString(null));
-        assertEquals(-1, BrowserContractHelpers.typeCodeForString("folder "));
-        assertEquals(-1, BrowserContractHelpers.typeCodeForString("FOLDER"));
-        assertEquals(-1, BrowserContractHelpers.typeCodeForString(""));
-        assertEquals(-1, BrowserContractHelpers.typeCodeForString("nope"));
-    }
-}
\ No newline at end of file
deleted file mode 100644
index e33b54a6d1b11429dbca88ff31c22de1d9c091c2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001