Merge last PGO-green changeset of mozilla-inbound to mozilla-central a=merge
authorEd Morley <emorley@mozilla.com>
Thu, 19 Apr 2012 15:25:58 -0700
changeset 91967 c861d58b7ade2378bc7f1e80a5f1cb2c7fd6c07f
parent 91956 900945f9909a447a028bac6db5bb6b6fa077cf9b (current diff)
parent 91966 1d3aea7115d36068c375f00e2d3048f734a4da7b (diff)
child 91968 3e2557ca55d665956268f63870c18264ee28da1a
push id22493
push useremorley@mozilla.com
push dateThu, 19 Apr 2012 22:29:04 +0000
treeherdermozilla-central@c861d58b7ade [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central a=merge
--- a/b2g/components/DirectoryProvider.js
+++ b/b2g/components/DirectoryProvider.js
@@ -5,33 +5,34 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-const OFFLINE_PROFILE_DIR = "/data/local"
+const LOCAL_DIR = "/data/local";
 
 function DirectoryProvider() {
 }
 
 DirectoryProvider.prototype = {
   classID: Components.ID("{9181eb7c-6f87-11e1-90b1-4f59d80dd2e5}"),
-  
+
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
 
   getFile: function dp_getFile(prop, persistent) {
 #ifdef MOZ_WIDGET_GONK
-    if (prop == "cachePDir" || prop == "webappsDir") {
+    let localProps = ["cachePDir", "webappsDir", "PrefD"];
+    if (localProps.indexOf(prop) != -1) {
       prop.persistent = true;
       let file = Cc["@mozilla.org/file/local;1"]
                    .createInstance(Ci.nsILocalFile)
-      file.initWithPath(OFFLINE_PROFILE_DIR);
+      file.initWithPath(LOCAL_DIR);
       return file;
     }
 #endif
 
     return null;
   }
 };
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -4759,16 +4759,29 @@ nsEventStateManager::SetContentState(nsI
   }
 
   return true;
 }
 
 void
 nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
 {
+  /*
+   * Anchor and area elements when focused or hovered might make the UI to show
+   * the current link. We want to make sure that the UI gets informed when they
+   * are actually removed from the DOM.
+   */
+  if (aContent->IsHTML() &&
+      (aContent->Tag() == nsGkAtoms::a || aContent->Tag() == nsGkAtoms::area) &&
+      (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS |
+                                                            NS_EVENT_STATE_HOVER))) {
+    nsGenericHTMLElement* element = static_cast<nsGenericHTMLElement*>(aContent);
+    element->LeaveLink(element->GetPresContext());
+  }
+
   // inform the focus manager that the content is being removed. If this
   // content is focused, the focus will be removed without firing events.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm)
     fm->ContentRemoved(aDocument, aContent);
 
   if (mHoverContent &&
       nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -136,63 +136,51 @@ DOMWifiManager.prototype = {
       case "WifiManager:forget:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:onconnecting":
         this._currentNetwork = msg.network;
         this._connectionStatus = "connecting";
-        this._fireOnConnecting(msg.network);
+        this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onassociate":
         this._currentNetwork = msg.network;
         this._connectionStatus = "associated";
-        this._fireOnAssociate(msg.network);
+        this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:onconnect":
         this._currentNetwork = msg.network;
         this._connectionStatus = "connected";
-        this._fireOnConnect(msg.network);
+        this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:ondisconnect":
-        this._fireOnDisconnect(this._currentNetwork);
         this._currentNetwork = null;
         this._connectionStatus = "disconnected";
         this._lastConnectionInfo = null;
+        this._fireStatusChangeEvent();
         break;
 
       case "WifiManager:connectionInfoUpdate":
         this._lastConnectionInfo = msg;
         this._fireConnectionInfoUpdate(msg);
         break;
     }
   },
 
-  _fireOnConnecting: function onConnecting(network) {
-    if (this._onConnecting)
-      this._onConnecting.handleEvent(new WifiStateChangeEvent(network));
-  },
-
-  _fireOnAssociate: function onAssociate(network) {
-    if (this._onAssociate)
-      this._onAssociate.handleEvent(new WifiStateChangeEvent(network));
-  },
-
-  _fireOnConnect: function onConnect(network) {
-    if (this._onConnect)
-      this._onConnect.handleEvent(new WifiStateChangeEvent(network));
-  },
-
-  _fireOnDisconnect: function onDisconnect(network) {
-    if (this._onDisconnect)
-      this._onDisconnect.handleEvent(new WifiStateChangeEvent(network));
+  _fireStatusChangeEvent: function StatusChangeEvent() {
+    if (this._onStatusChange) {
+      var event = new WifiStatusChangeEvent(this._currentNetwork,
+                                            this._connectionStatus);
+      this._onStatusChange.handleEvent(event);
+    }
   },
 
   _fireConnectionInfoUpdate: function connectionInfoUpdate(info) {
     if (this._onConnectionInfoUpdate) {
       var evt = new ConnectionInfoUpdate(this._currentNetwork,
                                          info.signalStrength,
                                          info.relSignalStrength,
                                          info.linkSpeed);
@@ -246,57 +234,39 @@ DOMWifiManager.prototype = {
   },
 
   get connectionInfo() {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     return this._lastConnectionInfo;
   },
 
-  set onconnecting(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onConnecting = callback;
-  },
-
-  set onassociate(callback) {
+  set onstatuschange(callback) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onAssociate = callback;
-  },
-
-  set onconnect(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onConnect = callback;
-  },
-
-  set ondisconnect(callback) {
-    if (!this._hasPrivileges)
-      throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
-    this._onDisconnect = callback;
+    this._onStatusChange = callback;
   },
 
   set connectionInfoUpdate(callback) {
     if (!this._hasPrivileges)
       throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
     this._onConnectionInfoUpdate = callback;
   }
 };
 
-function WifiStateChangeEvent(network) {
+function WifiStatusChangeEvent(network) {
   this.network = network;
 }
 
-WifiStateChangeEvent.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiStateChangeEvent]),
+WifiStatusChangeEvent.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMWifiStatusChangeEvent]),
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{f28c1ae7-4db7-4a4d-bb06-737eb04ad700}"),
                                     contractID: "@mozilla.org/wifi/statechange-event;1",
-                                    interfaces: [Ci.nsIDOMWifiStateChangeEvent],
+                                    interfaces: [Ci.nsIDOMWifiStatusChangeEvent],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Wifi State Change Event"})
 };
 
 function ConnectionInfoUpdate(network, signalStrength, relSignalStrength, linkSpeed) {
   this.network = network;
   this.signalStrength = signalStrength;
   this.relSignalStrength = relSignalStrength;
--- a/dom/wifi/nsIWifi.idl
+++ b/dom/wifi/nsIWifi.idl
@@ -42,17 +42,17 @@
 [scriptable, uuid(abb936bc-ba81-4c23-8dfa-3e5d96557044)]
 interface nsIWifi : nsISupports {
     /**
      * Shutdown the wifi system.
      */
     void shutdown();
 };
 
-[scriptable, uuid(36e4137b-dc8b-47e2-a90c-6adfb731fc41)]
+[scriptable, uuid(e3d5a7d7-6abd-4ac2-83dc-5315ec08a1c3)]
 interface nsIDOMWifiManager : nsISupports {
     /**
      * TODO Remove in favor of a settings API.
      * Activates or disactivates wifi.
      * onsuccess: Wifi has been successfully activated and can start
      *            attempting to connect to networks. request.value will be true.
      * onerror: Wifi was not successfully activated. (TODO provide details!)
      */
@@ -111,47 +111,55 @@ interface nsIDOMWifiManager : nsISupport
     /**
      * A connectionInformation object with the same information found in an
      * nsIDOMWifiConnectionInfoEvent (but without the network).
      * If we are not currently connected to a network, this will be null.
      */
     readonly attribute jsval connectionInformation;
 
     /**
-     * These four functions serve as state notification listeners.
-     * onconnecting: Fires when we start the process of connecting to a
-     *               network.
-     * onassociate: Fires when we have connected to an access point but do not
-     *              yet have an IP address.
-     * onconnect: Fires once we are fully connected to an access point and can
-     *            access the internet.
-     * ondisconnect: Fires when we either fail to connect to an access point
-     *               (transition: onassociate -> ondisconnect) or when we were
-     *               connected to a network but have disconnected for any
-     *               reason (transition: onconnect -> ondisconnect).
+     * State notification listeners. These all take an
+     * nsIDOMWifiStatusChangeEvent with the new status and a network (which
+     * may be null).
+     *
+     * The possible statuses are:
+     *   - connecting: Fires when we start the process of connecting to a
+     *                 network.
+     *   - associated: Fires when we have connected to an access point but do
+     *                 not yet have an IP address.
+     *   - connected: Fires once we are fully connected to an access point and
+     *                can access the internet.
+     *   - disconnected: Fires when we either fail to connect to an access
+     *                   point (transition: associated -> disconnected) or
+     *                   when we were connected to a network but have
+     *                   disconnected for any reason (transition: connected ->
+     *                   disconnected).
      */
-             attribute nsIDOMEventListener onconnecting;
-             attribute nsIDOMEventListener onassociate;
-             attribute nsIDOMEventListener onconnect;
-             attribute nsIDOMEventListener ondisconnect;
+             attribute nsIDOMEventListener onstatuschange;
 
     /**
      * An event listener that is called with information about the signal
      * strength and link speed every 5 seconds.
      */
              attribute nsIDOMEventListener connectionInfoUpdate;
 };
 
 [scriptable, uuid(4674c6f1-ea64-44db-ac2f-e7bd6514dfd6)]
-interface nsIDOMWifiStateChangeEvent : nsIDOMEvent {
+interface nsIDOMWifiStatusChangeEvent : nsIDOMEvent {
     /**
      * Network object with a SSID field describing the network affected by
-     * this change.
+     * this change. This might be null.
      */
     readonly attribute jsval network;
+
+    /**
+     * String describing the current status of the wifi manager. See above for
+     * the possible values.
+     */
+    readonly attribute string status;
 };
 
 [scriptable, uuid(5c9ee332-dd98-4227-b7fc-768418fd50e3)]
 interface nsIDOMWifiConnectionInfoEvent : nsIDOMEvent {
     /**
      * Network object with an SSID field.
      */
     readonly attribute jsval network;
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -2282,41 +2282,43 @@ abstract public class GeckoApp
         return status;
     }
 
     private void checkMigrateProfile() {
         final File profileDir = getProfile().getDir();
         final long currentTime = SystemClock.uptimeMillis();
 
         if (profileDir != null) {
-            Log.i(LOGTAG, "Checking profile migration in: " + profileDir.getAbsolutePath());
             final GeckoApp app = GeckoApp.mAppContext;
-            final ProfileMigrator profileMigrator =
-                new ProfileMigrator(app, profileDir);
-
-            // Do a migration run on the first start after an upgrade.
-            if (!profileMigrator.hasMigrationRun()) {
-                final SetupScreen setupScreen = new SetupScreen(app);
-
-                // Don't show unless this take a while.
-                setupScreen.showDelayed(mMainHandler);
-
-                GeckoAppShell.getHandler().post(new Runnable() {
-                    public void run() {
+
+            GeckoAppShell.getHandler().post(new Runnable() {
+                public void run() {
+                    Log.i(LOGTAG, "Checking profile migration in: " + profileDir.getAbsolutePath());
+
+                    ProfileMigrator profileMigrator =
+                        new ProfileMigrator(app, profileDir);
+
+                    // Do a migration run on the first start after an upgrade.
+                    if (!profileMigrator.hasMigrationRun()) {
+                        final SetupScreen setupScreen = new SetupScreen(app);
+
+                        // Don't show unless this take a while.
+                        setupScreen.showDelayed(mMainHandler);
+
                         profileMigrator.launchPlaces();
                         setupScreen.dismiss();
 
                         long timeDiff = SystemClock.uptimeMillis() - currentTime;
                         Log.i(LOGTAG, "Profile migration took " + timeDiff + " ms");
 
                         // Update about:home with the new information.
                         updateAboutHomeTopSites();
                     }
-                });
-            }
+                }}
+            );
         }
     }
 
     private void checkMigrateSync() {
         final File profileDir = getProfile().getDir();
         if (profileDir != null) {
             final GeckoApp app = GeckoApp.mAppContext;
             ProfileMigrator profileMigrator =
--- a/mobile/android/base/ProfileMigrator.java
+++ b/mobile/android/base/ProfileMigrator.java
@@ -111,125 +111,151 @@ public class ProfileMigrator {
     // Number of history entries already migrated.
     private static final String PREFS_MIGRATE_HISTORY_COUNT = "history_count";
     private static final String PREFS_MIGRATE_SYNC_DONE = "sync_done";
 
     /*
        These queries are derived from the low-level Places schema
        https://developer.mozilla.org/en/The_Places_database
     */
-    private final String kRootQuery =
+    private static final String ROOT_QUERY =
         "SELECT root_name, folder_id FROM moz_bookmarks_roots";
-    private final String kRootName     = "root_name";
-    private final String kRootFolderId = "folder_id";
+    private static final String ROOT_NAME      = "root_name";
+    private static final String ROOT_FOLDER_ID = "folder_id";
 
-    private final String kBookmarkQuery =
+    private static final String BOOKMARK_QUERY_SELECT =
         "SELECT places.url             AS p_url,"         +
         "       bookmark.guid          AS b_guid,"        +
         "       bookmark.id            AS b_id,"          +
         "       bookmark.title         AS b_title,"       +
         "       bookmark.type          AS b_type,"        +
         "       bookmark.parent        AS b_parent,"      +
         "       bookmark.dateAdded     AS b_added,"       +
         "       bookmark.lastModified  AS b_modified,"    +
-        "       bookmark.position      AS b_position,"    +
-        "       favicon.data           AS f_data,"        +
-        "       favicon.mime_type      AS f_mime_type,"   +
-        "       favicon.url            AS f_url,"         +
-        "       favicon.guid           AS f_guid "        +
+        "       bookmark.position      AS b_position,";
+
+    private static final String BOOKMARK_QUERY_TRAILER =
         "FROM ((moz_bookmarks AS bookmark "               +
         "       LEFT OUTER JOIN moz_places AS places "    +
         "       ON places.id = bookmark.fk) "             +
         "       LEFT OUTER JOIN moz_favicons AS favicon " +
         "       ON places.favicon_id = favicon.id) "      +
         // Bookmark folders don't have a places entry.
         "WHERE (places.hidden IS NULL "                   +
         "       OR places.hidden <> 1) "                  +
         // This gives us a better chance of adding a folder before
         // adding its contents and hence avoiding extra iterations below.
         "ORDER BY bookmark.id";
 
+    private static final String BOOKMARK_QUERY_GUID =
+        BOOKMARK_QUERY_SELECT                              +
+        "       favicon.data           AS f_data,"        +
+        "       favicon.mime_type      AS f_mime_type,"   +
+        "       favicon.url            AS f_url,"         +
+        "       favicon.guid           AS f_guid "        +
+        BOOKMARK_QUERY_TRAILER;
+
+    private static final String BOOKMARK_QUERY_NO_GUID =
+        BOOKMARK_QUERY_SELECT                              +
+        "       favicon.data           AS f_data,"        +
+        "       favicon.mime_type      AS f_mime_type,"   +
+        "       favicon.url            AS f_url "         +
+        BOOKMARK_QUERY_TRAILER;
+
     // Result column of relevant data
-    private final String kBookmarkUrl      = "p_url";
-    private final String kBookmarkTitle    = "b_title";
-    private final String kBookmarkGuid     = "b_guid";
-    private final String kBookmarkId       = "b_id";
-    private final String kBookmarkType     = "b_type";
-    private final String kBookmarkParent   = "b_parent";
-    private final String kBookmarkAdded    = "b_added";
-    private final String kBookmarkModified = "b_modified";
-    private final String kBookmarkPosition = "b_position";
-    private final String kFaviconData      = "f_data";
-    private final String kFaviconMime      = "f_mime_type";
-    private final String kFaviconUrl       = "f_url";
-    private final String kFaviconGuid      = "f_guid";
+    private static final String BOOKMARK_URL      = "p_url";
+    private static final String BOOKMARK_TITLE    = "b_title";
+    private static final String BOOKMARK_GUID     = "b_guid";
+    private static final String BOOKMARK_ID       = "b_id";
+    private static final String BOOKMARK_TYPE     = "b_type";
+    private static final String BOOKMARK_PARENT   = "b_parent";
+    private static final String BOOKMARK_ADDED    = "b_added";
+    private static final String BOOKMARK_MODIFIED = "b_modified";
+    private static final String BOOKMARK_POSITION = "b_position";
+    private static final String FAVICON_DATA      = "f_data";
+    private static final String FAVICON_MIME      = "f_mime_type";
+    private static final String FAVICON_URL       = "f_url";
+    private static final String FAVICON_GUID      = "f_guid";
 
     // Helper constants
-    private static final int kPlacesTypeBookmark = 1;
-    private static final int kPlacesTypeFolder   = 2;
+    private static final int PLACES_TYPE_BOOKMARK = 1;
+    private static final int PLACES_TYPE_FOLDER   = 2;
 
     /*
       For statistics keeping.
     */
-    private final String kHistoryCountQuery =
+    private static final String HISTORY_COUNT_QUERY =
         "SELECT COUNT(*) FROM moz_historyvisits";
 
     /*
       The sort criterion here corresponds to the one used for the
       Awesomebar results. It's a simplification of Frecency.
       We must divide date by 1000 due to the micro (Places)
       vs milli (Android) distiction.
     */
-    private final String kHistoryQuery =
+    private static final String HISTORY_QUERY_SELECT =
         "SELECT places.url              AS p_url, "       +
         "       places.title            AS p_title, "     +
+        "       places.guid             AS p_guid, "      +
         "       MAX(history.visit_date) AS h_date, "      +
         "       COUNT(*) AS h_visits, "                   +
         // see BrowserDB.filterAllSites for this formula
         "       MAX(1, 100 * 225 / (" +
-                  "((MAX(history.visit_date)/1000 - ?) / 86400000) * " +
-                  "((MAX(history.visit_date)/1000 - ?) / 86400000) + 225)) AS a_recent, " +
-        "       favicon.data            AS f_data, "      +
-        "       favicon.mime_type       AS f_mime_type, " +
-        "       places.guid             AS p_guid, "      +
-        "       favicon.url             AS f_url, "       +
-        "       favicon.guid            AS f_guid "       +
+        "          ((MAX(history.visit_date)/1000 - ?) / 86400000) * " +
+        "          ((MAX(history.visit_date)/1000 - ?) / 86400000) + 225)) AS a_recent, ";
+
+    private static final String HISTORY_QUERY_TRAILER =
         "FROM (moz_historyvisits AS history "             +
         "      JOIN moz_places AS places "                +
         "      ON places.id = history.place_id "          +
         // Add favicon data if a favicon is present for this URL.
         "      LEFT OUTER JOIN moz_favicons AS favicon "  +
         "      ON places.favicon_id = favicon.id) "       +
         "WHERE places.hidden <> 1 "                       +
         "GROUP BY p_url "                                 +
         "ORDER BY h_visits * a_recent "                   +
         "DESC LIMIT ? OFFSET ?";
 
-    private final String kHistoryUrl    = "p_url";
-    private final String kHistoryTitle  = "p_title";
-    private final String kHistoryGuid   = "p_guid";
-    private final String kHistoryDate   = "h_date";
-    private final String kHistoryVisits = "h_visits";
+    private static final String HISTORY_QUERY_GUID =
+        HISTORY_QUERY_SELECT                               +
+        "       favicon.data            AS f_data, "      +
+        "       favicon.mime_type       AS f_mime_type, " +
+        "       favicon.url             AS f_url, "       +
+        "       favicon.guid            AS f_guid "       +
+        HISTORY_QUERY_TRAILER;
+
+    private static final String HISTORY_QUERY_NO_GUID =
+        HISTORY_QUERY_SELECT                               +
+        "       favicon.data            AS f_data, "      +
+        "       favicon.mime_type       AS f_mime_type, " +
+        "       favicon.url             AS f_url "        +
+        HISTORY_QUERY_TRAILER;
+
+    private static final String HISTORY_URL    = "p_url";
+    private static final String HISTORY_TITLE  = "p_title";
+    private static final String HISTORY_GUID   = "p_guid";
+    private static final String HISTORY_DATE   = "h_date";
+    private static final String HISTORY_VISITS = "h_visits";
 
     /*
       Sync settings to get from prefs.js.
     */
-    private final String[] kSyncSettingsList = new String[] {
+    private static final String[] SYNC_SETTINGS_LIST = new String[] {
         "services.sync.account",
         "services.sync.client.name",
         "services.sync.client.GUID",
         "services.sync.serverURL",
         "services.sync.clusterURL"
     };
 
     /*
       Sync settings to get from password manager.
     */
-    private final String kSyncHostName = "chrome://weave";
-    private final String[] kSyncRealmList = new String[] {
+    private static final String SYNC_HOST_NAME = "chrome://weave";
+    private static final String[] SYNC_REALM_LIST = new String[] {
         "Mozilla Services Password",
         "Mozilla Services Encryption Passphrase"
     };
 
 
     public ProfileMigrator(Context context, File profileDir) {
         mProfileDir = profileDir;
         mContext = context;
@@ -270,17 +296,18 @@ public class ProfileMigrator {
 
     // Have Sync settings been transferred?
     public boolean hasSyncMigrated() {
         return getPreferences().getBoolean(PREFS_MIGRATE_SYNC_DONE, false);
     }
 
     // Has migration run before?
     protected boolean hasMigrationRun() {
-        return areBookmarksMigrated() && (getMigratedHistoryEntries() > 0);
+        return areBookmarksMigrated()
+            && ((getMigratedHistoryEntries() > 0) || isHistoryMigrated());
     }
 
     // Has migration entirely finished?
     protected boolean hasMigrationFinished() {
         return areBookmarksMigrated() && isHistoryMigrated();
     }
 
     protected SharedPreferences getPreferences() {
@@ -316,17 +343,17 @@ public class ProfileMigrator {
     }
 
     private class SyncTask implements Runnable, GeckoEventListener {
         private List<String> mSyncSettingsList;
         private Map<String, String> mSyncSettingsMap;
 
         // Initialize preferences by sending the "Preferences:Get" command to Gecko
         protected void requestValues() {
-            mSyncSettingsList = Arrays.asList(kSyncSettingsList);
+            mSyncSettingsList = Arrays.asList(SYNC_SETTINGS_LIST);
             mSyncSettingsMap = new HashMap<String, String>();
             JSONArray jsonPrefs = new JSONArray(mSyncSettingsList);
             Log.d(LOGTAG, "Sending: " + jsonPrefs.toString());
             GeckoEvent event =
                 GeckoEvent.createBroadcastEvent("Preferences:Get",
                                                 jsonPrefs.toString());
             GeckoAppShell.sendEventToGecko(event);
         }
@@ -340,17 +367,17 @@ public class ProfileMigrator {
                     // This includes personal info, so don't log.
                     // Log.d(LOGTAG, "Message: " + message.toString());
                     JSONArray jsonPrefs = message.getJSONArray("preferences");
                     parsePrefs(jsonPrefs);
                     GeckoAppShell.unregisterGeckoEventListener("Preferences:Data",
                                                                (GeckoEventListener)this);
 
                     // Now call the password provider to fill in the rest.
-                    for (String location: kSyncRealmList) {
+                    for (String location: SYNC_REALM_LIST) {
                         Log.d(LOGTAG, "Checking: " + location);
                         String passwd = getPassword(location);
                         if (!TextUtils.isEmpty(passwd)) {
                             Log.d(LOGTAG, "Got password");
                             mSyncSettingsMap.put(location, passwd);
                         } else {
                             Log.d(LOGTAG, "No password found");
                             mSyncSettingsMap.put(location, null);
@@ -368,17 +395,17 @@ public class ProfileMigrator {
         protected String getPassword(String realm) {
             Cursor cursor = null;
             String result = null;
             try {
                 cursor = mCr.query(Passwords.CONTENT_URI,
                                    null,
                                    Passwords.HOSTNAME + " = ? AND "
                                    + Passwords.HTTP_REALM + " = ?",
-                                   new String[] { kSyncHostName, realm },
+                                   new String[] { SYNC_HOST_NAME, realm },
                                    null);
 
                 if (cursor != null) {
                     final int userCol =
                         cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_USERNAME);
                     final int passCol =
                         cursor.getColumnIndexOrThrow(Passwords.ENCRYPTED_PASSWORD);
 
@@ -508,16 +535,20 @@ public class ProfileMigrator {
             // cleanupXULLibCache();
         }
     }
 
     private class PlacesRunnable implements Runnable {
         private Map<Long, Long> mRerootMap;
         private ArrayList<ContentProviderOperation> mOperations;
         private int mMaxEntries;
+        // We support 2 classes of schemas: Firefox Places 12-13
+        // and Firefox Places 13-20. The relevant difference for us
+        // is whether there is a GUID on favicons or not.
+        private boolean mHasFaviconGUID;
 
         public PlacesRunnable(int limit) {
             mMaxEntries = limit;
         }
 
         protected Uri getBookmarksUri() {
             Uri.Builder uriBuilder = Bookmarks.CONTENT_URI.buildUpon()
                 .appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
@@ -551,38 +582,61 @@ public class ProfileMigrator {
             } finally {
                 if (c != null)
                     c.close();
             }
             // Default fallback
             return Bookmarks.FIXED_ROOT_ID;
         }
 
+        // Check the Schema version of the Firefox Places Database.
+        public boolean checkPlacesSchema(SQLiteBridge db) {
+            final int schemaVersion = db.getVersion();
+            Log.d(LOGTAG, "Schema version " + schemaVersion);
+            if (schemaVersion < 12) {
+                Log.e(LOGTAG, "Places DB is too old, not migrating.");
+                return false;
+            } else if (schemaVersion >= 12 && schemaVersion <= 13) {
+                Log.d(LOGTAG, "Not Migrating Favicon GUIDs.");
+                mHasFaviconGUID = false;
+                return true;
+            } else if (schemaVersion <= 20) {
+                Log.d(LOGTAG, "Migrating Favicon GUIDs.");
+                mHasFaviconGUID = true;
+                return true;
+            } else {
+                Log.e(LOGTAG, "Too new (corrupted?) Places schema.");
+                return false;
+            }
+        }
+
         // We want to know the id of special root folders in the places DB,
         // and replace them by the corresponding root id in the Android DB.
         protected void calculateReroot(SQLiteBridge db) {
             mRerootMap = new HashMap<Long, Long>();
 
             try {
-                Cursor cursor = db.rawQuery(kRootQuery, null);
-                final int rootCol = cursor.getColumnIndex(kRootName);
-                final int folderCol = cursor.getColumnIndex(kRootFolderId);
+                Cursor cursor = db.rawQuery(ROOT_QUERY, null);
+                final int rootCol = cursor.getColumnIndex(ROOT_NAME);
+                final int folderCol = cursor.getColumnIndex(ROOT_FOLDER_ID);
 
                 cursor.moveToFirst();
                 while (!cursor.isAfterLast()) {
                     String name = cursor.getString(rootCol);
                     long placesFolderId = cursor.getLong(folderCol);
                     mRerootMap.put(placesFolderId, getFolderId(name));
                     Log.v(LOGTAG, "Name: " + name + ", pid=" + placesFolderId
                           + ", nid=" + mRerootMap.get(placesFolderId));
                     cursor.moveToNext();
                 }
                 cursor.close();
             } catch (SQLiteBridgeException e) {
                 Log.e(LOGTAG, "Failed to get bookmark roots: ", e);
+                // Do not try again.
+                setMigratedBookmarks();
                 return;
             }
         }
 
         protected void updateBrowserHistory(String url, String title,
                                             long date, int visits) {
             Cursor cursor = null;
 
@@ -690,17 +744,19 @@ public class ProfileMigrator {
                     // from having to convert them into a byte[].
                     values.put(Images.FAVICON, data);
                 }
 
                 values.put(Images.URL, url);
                 values.put(Images.FAVICON_URL, faviconUrl);
                 // Restore deleted record if possible
                 values.put(Images.IS_DELETED, 0);
-                values.put(Images.GUID, faviconGuid);
+                if (faviconGuid != null) {
+                    values.put(Images.GUID, faviconGuid);
+                }
 
                 Cursor cursor = null;
                 ContentProviderOperation.Builder builder = null;
                 try {
                     cursor = mCr.query(getImagesUri(),
                                        null,
                                        Images.URL + " = ?",
                                        new String[] { url },
@@ -734,66 +790,77 @@ public class ProfileMigrator {
 
         protected void doMigrateHistoryBatch(SQLiteBridge db,
                                              int maxEntries, int currentEntries) {
             final ArrayList<String> placesHistory = new ArrayList<String>();
             mOperations = new ArrayList<ContentProviderOperation>();
             int queryResultEntries = 0;
 
             try {
-                Cursor cursor = db.rawQuery(kHistoryCountQuery, null);
+                Cursor cursor = db.rawQuery(HISTORY_COUNT_QUERY, null);
                 cursor.moveToFirst();
                 int historyCount = cursor.getInt(0);
                 Telemetry.HistogramAdd("BROWSERPROVIDER_XUL_IMPORT_HISTORY",
                                        historyCount);
 
                 final String currentTime = Long.toString(System.currentTimeMillis());
                 final String[] queryParams = new String[] {
                     /* current time */
                     currentTime,
                     currentTime,
                     Integer.toString(maxEntries),
                     Integer.toString(currentEntries)
                 };
-                cursor = db.rawQuery(kHistoryQuery, queryParams);
+
+                if (mHasFaviconGUID) {
+                    cursor = db.rawQuery(HISTORY_QUERY_GUID, queryParams);
+                } else {
+                    cursor = db.rawQuery(HISTORY_QUERY_NO_GUID, queryParams);
+                }
                 queryResultEntries = cursor.getCount();
 
-                final int urlCol = cursor.getColumnIndex(kHistoryUrl);
-                final int titleCol = cursor.getColumnIndex(kHistoryTitle);
-                final int dateCol = cursor.getColumnIndex(kHistoryDate);
-                final int visitsCol = cursor.getColumnIndex(kHistoryVisits);
-                final int faviconMimeCol = cursor.getColumnIndex(kFaviconMime);
-                final int faviconDataCol = cursor.getColumnIndex(kFaviconData);
-                final int faviconUrlCol = cursor.getColumnIndex(kFaviconUrl);
-                final int faviconGuidCol = cursor.getColumnIndex(kFaviconGuid);
+                final int urlCol = cursor.getColumnIndex(HISTORY_URL);
+                final int titleCol = cursor.getColumnIndex(HISTORY_TITLE);
+                final int dateCol = cursor.getColumnIndex(HISTORY_DATE);
+                final int visitsCol = cursor.getColumnIndex(HISTORY_VISITS);
+                final int faviconMimeCol = cursor.getColumnIndex(FAVICON_MIME);
+                final int faviconDataCol = cursor.getColumnIndex(FAVICON_DATA);
+                final int faviconUrlCol = cursor.getColumnIndex(FAVICON_URL);
+                // Safe even if it doesn't exist.
+                final int faviconGuidCol = cursor.getColumnIndex(FAVICON_GUID);
 
                 cursor.moveToFirst();
                 while (!cursor.isAfterLast()) {
                     String url = cursor.getString(urlCol);
                     String title = cursor.getString(titleCol);
                     long date = cursor.getLong(dateCol) / (long)1000;
                     int visits = cursor.getInt(visitsCol);
                     byte[] faviconDataBuff = cursor.getBlob(faviconDataCol);
                     String faviconMime = cursor.getString(faviconMimeCol);
                     String faviconUrl = cursor.getString(faviconUrlCol);
-                    String faviconGuid = cursor.getString(faviconGuidCol);
+                    String faviconGuid = null;
+                    if (mHasFaviconGUID) {
+                        faviconGuid = cursor.getString(faviconGuidCol);
+                    }
 
                     try {
                         placesHistory.add(url);
                         addFavicon(url, faviconUrl, faviconGuid,
                                    faviconMime, faviconDataBuff);
                         updateBrowserHistory(url, title, date, visits);
                     } catch (Exception e) {
                         Log.e(LOGTAG, "Error adding history entry: ", e);
                     }
                     cursor.moveToNext();
                 }
                 cursor.close();
             } catch (SQLiteBridgeException e) {
                 Log.e(LOGTAG, "Failed to get history: ", e);
+                // Do not try again.
+                setMigratedHistory();
                 return;
             }
 
             flushBatchOperations();
 
             int totalEntries = currentEntries + queryResultEntries;
             setMigratedHistoryEntries(totalEntries);
 
@@ -901,30 +968,35 @@ public class ProfileMigrator {
         }
 
         protected void migrateBookmarks(SQLiteBridge db) {
             mOperations = new ArrayList<ContentProviderOperation>();
 
             try {
                 Log.i(LOGTAG, "Fetching bookmarks from places");
 
-                Cursor cursor = db.rawQuery(kBookmarkQuery, null);
-                final int urlCol = cursor.getColumnIndex(kBookmarkUrl);
-                final int titleCol = cursor.getColumnIndex(kBookmarkTitle);
-                final int guidCol = cursor.getColumnIndex(kBookmarkGuid);
-                final int idCol = cursor.getColumnIndex(kBookmarkId);
-                final int typeCol = cursor.getColumnIndex(kBookmarkType);
-                final int parentCol = cursor.getColumnIndex(kBookmarkParent);
-                final int addedCol = cursor.getColumnIndex(kBookmarkAdded);
-                final int modifiedCol = cursor.getColumnIndex(kBookmarkModified);
-                final int positionCol = cursor.getColumnIndex(kBookmarkPosition);
-                final int faviconMimeCol = cursor.getColumnIndex(kFaviconMime);
-                final int faviconDataCol = cursor.getColumnIndex(kFaviconData);
-                final int faviconUrlCol = cursor.getColumnIndex(kFaviconUrl);
-                final int faviconGuidCol = cursor.getColumnIndex(kFaviconGuid);
+                Cursor cursor = null;
+                if (mHasFaviconGUID) {
+                    cursor = db.rawQuery(BOOKMARK_QUERY_GUID, null);
+                } else {
+                    cursor = db.rawQuery(BOOKMARK_QUERY_NO_GUID, null);
+                }
+                final int urlCol = cursor.getColumnIndex(BOOKMARK_URL);
+                final int titleCol = cursor.getColumnIndex(BOOKMARK_TITLE);
+                final int guidCol = cursor.getColumnIndex(BOOKMARK_GUID);
+                final int idCol = cursor.getColumnIndex(BOOKMARK_ID);
+                final int typeCol = cursor.getColumnIndex(BOOKMARK_TYPE);
+                final int parentCol = cursor.getColumnIndex(BOOKMARK_PARENT);
+                final int addedCol = cursor.getColumnIndex(BOOKMARK_ADDED);
+                final int modifiedCol = cursor.getColumnIndex(BOOKMARK_MODIFIED);
+                final int positionCol = cursor.getColumnIndex(BOOKMARK_POSITION);
+                final int faviconMimeCol = cursor.getColumnIndex(FAVICON_MIME);
+                final int faviconDataCol = cursor.getColumnIndex(FAVICON_DATA);
+                final int faviconUrlCol = cursor.getColumnIndex(FAVICON_URL);
+                final int faviconGuidCol = cursor.getColumnIndex(FAVICON_GUID);
 
                 // Keep statistics
                 int bookmarkCount = cursor.getCount();
                 Telemetry.HistogramAdd("BROWSERPROVIDER_XUL_IMPORT_BOOKMARKS",
                                        bookmarkCount);
 
                 // The keys are places IDs.
                 Set<Long> openFolders = new HashSet<Long>();
@@ -957,39 +1029,42 @@ public class ProfileMigrator {
                             continue;
                         }
 
                         int type = cursor.getInt(typeCol);
                         long parent = cursor.getLong(parentCol);
 
                         // Places has an explicit root folder, id=1 parent=0.
                         // Skip that.
-                        if (id == 1 && parent == 0 && type == kPlacesTypeFolder) {
+                        if (id == 1 && parent == 0 && type == PLACES_TYPE_FOLDER) {
                             cursor.moveToNext();
                             continue;
                         }
 
                         String url = cursor.getString(urlCol);
                         String title = cursor.getString(titleCol);
                         String guid = cursor.getString(guidCol);
                         long dateadded =
                             cursor.getLong(addedCol) / (long)1000;
                         long datemodified =
                             cursor.getLong(modifiedCol) / (long)1000;
                         long position = cursor.getLong(positionCol);
                         byte[] faviconDataBuff = cursor.getBlob(faviconDataCol);
                         String faviconMime = cursor.getString(faviconMimeCol);
                         String faviconUrl = cursor.getString(faviconUrlCol);
-                        String faviconGuid = cursor.getString(faviconGuidCol);
+                        String faviconGuid = null;
+                        if (mHasFaviconGUID) {
+                            faviconGuid = cursor.getString(faviconGuidCol);
+                        }
 
                         // Is the parent for this bookmark already added?
                         // If so, we can add the bookmark itself.
                         if (knownFolders.contains(parent)) {
                             try {
-                                boolean isFolder = (type == kPlacesTypeFolder);
+                                boolean isFolder = (type == PLACES_TYPE_FOLDER);
                                 addBookmark(url, title, guid, parent,
                                             dateadded, datemodified,
                                             position, isFolder);
                                 addFavicon(url, faviconUrl, faviconGuid,
                                            faviconMime, faviconDataBuff);
                                 if (isFolder) {
                                     // We need to know the ID of the folder
                                     // we just inserted. It's possible to
@@ -1032,16 +1107,18 @@ public class ProfileMigrator {
                     iterations++;
                     Log.i(LOGTAG, "Iteration = " + iterations + ", added " + added +
                           " bookmark(s), skipped " + skipped + " bookmark(s)");
                 } while (!openFolders.isEmpty());
 
                 cursor.close();
             } catch (SQLiteBridgeException e) {
                 Log.e(LOGTAG, "Failed to get bookmarks: ", e);
+                // Do not try again.
+                setMigratedBookmarks();
                 return;
             }
 
             flushBatchOperations();
         }
 
         protected void flushBatchOperations() {
             Log.i(LOGTAG, "Flushing " + mOperations.size() + " DB operations");
@@ -1079,29 +1156,36 @@ public class ProfileMigrator {
             }
             File dbFileWal = new File(dbPathWal);
             File dbFileShm = new File(dbPathShm);
 
             SQLiteBridge db = null;
             GeckoAppShell.loadSQLiteLibs(mContext, mContext.getPackageResourcePath());
             try {
                 db = new SQLiteBridge(dbPath);
-                calculateReroot(db);
-
-                if (!areBookmarksMigrated()) {
-                    migrateBookmarks(db);
+                if (!checkPlacesSchema(db)) {
+                    // Incompatible schema. Bail out.
                     setMigratedBookmarks();
+                    setMigratedHistory();
                 } else {
-                    Log.i(LOGTAG, "Bookmarks already migrated. Skipping...");
-                }
+                    // Compatible schema. Let's go.
+                    calculateReroot(db);
 
-                if (!isHistoryMigrated()) {
-                    migrateHistory(db);
-                } else {
-                    Log.i(LOGTAG, "History already migrated. Skipping...");
+                    if (!areBookmarksMigrated()) {
+                        migrateBookmarks(db);
+                        setMigratedBookmarks();
+                    } else {
+                        Log.i(LOGTAG, "Bookmarks already migrated. Skipping...");
+                    }
+
+                    if (!isHistoryMigrated()) {
+                        migrateHistory(db);
+                    } else {
+                        Log.i(LOGTAG, "History already migrated. Skipping...");
+                    }
                 }
 
                 db.close();
 
                 // Clean up if we finished this run. Bookmarks are always
                 // migrated if we get here.
                 if (isHistoryMigrated()) {
                     Log.i(LOGTAG, "Profile Migration has processed all entries. "
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -77,17 +77,16 @@ public final class Tab {
     private Drawable mThumbnail;
     private List<HistoryEntry> mHistory;
     private int mHistoryIndex;
     private int mParentId;
     private boolean mExternal;
     private boolean mBookmark;
     private HashMap<String, DoorHanger> mDoorHangers;
     private long mFaviconLoadId;
-    private CheckBookmarkTask mCheckBookmarkTask;
     private String mDocumentURI;
     private String mContentType;
     private boolean mHasTouchListeners;
     private ArrayList<View> mPluginViews;
     private HashMap<Surface, Layer> mPluginLayers;
     private ContentResolver mContentResolver;
     private ContentObserver mContentObserver;
     private int mState;
@@ -368,27 +367,26 @@ public final class Tab {
         Log.i(LOGTAG, "Updated favicon URL for tab with id: " + mId);
     }
 
     public void updateSecurityMode(String mode) {
         mSecurityMode = mode;
     }
 
     private void updateBookmark() {
-        GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-            public void run() {
-                if (mCheckBookmarkTask != null)
-                    mCheckBookmarkTask.cancel(false);
+        final String url = getURL();
+        if (url == null)
+            return;
 
-                String url = getURL();
-                if (url == null)
-                    return;
-
-                mCheckBookmarkTask = new CheckBookmarkTask(url);
-                mCheckBookmarkTask.execute();
+        GeckoBackgroundThread.getHandler().post(new Runnable() {
+            public void run() {
+                boolean bookmark = BrowserDB.isBookmark(mContentResolver, url);
+                if (url.equals(getURL())) {
+                    mBookmark = bookmark;
+                }
             }
         });
     }
 
     public void addBookmark() {
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 String url = getURL();
@@ -519,50 +517,16 @@ public final class Tab {
             }
             mHistoryIndex = index;
         } else if (event.equals("Purge")) {
             mHistory.clear();
             mHistoryIndex = -1;
         }
     }
 
-    private final class CheckBookmarkTask extends AsyncTask<Void, Void, Boolean> {
-        private final String mUrl;
-
-        public CheckBookmarkTask(String url) {
-            mUrl = url;
-        }
-
-        @Override
-        protected Boolean doInBackground(Void... unused) {
-            return BrowserDB.isBookmark(mContentResolver, mUrl);
-        }
-
-        @Override
-        protected void onCancelled() {
-            mCheckBookmarkTask = null;
-        }
-
-        @Override
-        protected void onPostExecute(final Boolean isBookmark) {
-            mCheckBookmarkTask = null;
-
-            GeckoApp.mAppContext.runOnUiThread(new Runnable() {
-                public void run() {
-                    // Ignore this task if it's not about the current
-                    // tab URL anymore.
-                    if (!mUrl.equals(getURL()))
-                        return;
-
-                    mBookmark = isBookmark.booleanValue();
-                }
-            });
-        }
-    }
-
     private void saveThumbnailToDB(BitmapDrawable thumbnail) {
         try {
             String url = getURL();
             if (url == null)
                 return;
 
             BrowserDB.updateThumbnailForUrl(mContentResolver, url, thumbnail);
         } catch (Exception e) {