Merge mobile-browser -> mobile2
authorMatt Brubeck <mbrubeck@mozilla.com>
Fri, 10 Sep 2010 14:39:23 -0700
changeset 66644 a9515c975d686b0c7476eede0ccaf87185646bc4
parent 66643 62fbd8300803fc6c2eb41486c3cf79dc79507fdf (current diff)
parent 66563 9f2baf1caf20498df0f51cb76505f36004363203 (diff)
child 66645 44c5a4d9c4c7aed13c144e6c6702e2fb5ffbf97f
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
Merge mobile-browser -> mobile2
mobile/app/mobile.js
mobile/chrome/content/InputHandler.js
mobile/chrome/content/Util.js
mobile/chrome/content/bindings.xml
mobile/chrome/content/browser-ui.js
mobile/chrome/content/browser.js
mobile/chrome/content/browser.xul
mobile/chrome/content/content.js
mobile/components/GeolocationPrompt.js
mobile/themes/core/browser.css
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -482,8 +482,12 @@ pref("font.default.x-western", "SwissA")
 // See bug 545869 for details on why these are set the way they are
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  16384);
 
 // sync service
 pref("services.sync.client.type", "mobile");
 pref("services.sync.registerEngines", "Tab,Bookmarks,Form,History,Password");
 pref("services.sync.autoconnectDelay", 5);
+
+// Drag thresholds
+pref("ui.dragThresholdX", 25);
+pref("ui.dragThresholdY", 25);
--- a/mobile/chrome/content/InputHandler.js
+++ b/mobile/chrome/content/InputHandler.js
@@ -37,24 +37,25 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-// how many msecs elapse before two taps are not a double tap
+// Maximum delay in ms between the two taps of a double-tap
 const kDoubleClickInterval = 400;
 
-// threshold in ms to detect if the click is possibly a dblClick
-const kDoubleClickThreshold = 300;
+// If a tap lasts longer than this duration in ms, treat it as a single-tap
+// immediately instead of waiting for a possible double tap.
+const kDoubleClickThreshold = 200;
 
 // threshold in pixels for sensing a tap as opposed to a pan
-const kTapRadius = 25;
+const kTapRadius = Services.prefs.getIntPref("ui.dragThresholdX");
 
 // maximum drag distance in pixels while axis locking can still be reverted
 const kAxisLockRevertThreshold = 200;
 
 // Same as NS_EVENT_STATE_ACTIVE from nsIEventStateManager.h
 const kStateActive = 0x00000001;
 
 /**
--- a/mobile/chrome/content/Util.js
+++ b/mobile/chrome/content/Util.js
@@ -125,44 +125,16 @@ let Util = {
     let dontShare = /^(chrome|about|file|javascript|resource)$/;
     return (aProtocol && !dontShare.test(aProtocol));
   },
 
   clamp: function(num, min, max) {
     return Math.max(min, Math.min(max, num));
   },
 
-  /**
-   * Determines whether a home page override is needed.
-   * Returns:
-   *  "new profile" if this is the first run with a new profile.
-   *  "new version" if this is the first run with a build with a different
-   *                      Gecko milestone (i.e. right after an upgrade).
-   *  "none" otherwise.
-   */
-  needHomepageOverride: function needHomepageOverride() {
-    let savedmstone = null;
-    try {
-      savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
-    } catch (e) {}
-
-    if (savedmstone == "ignore")
-      return "none";
-
-#expand    let ourmstone = "__MOZ_APP_VERSION__";
-
-    if (ourmstone != savedmstone) {
-      Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone);
-
-      return (savedmstone ? "new version" : "new profile");
-    }
-
-    return "none";
-  },
-
   /** Don't display anything in the urlbar for these special URIs. */
   isURLEmpty: function isURLEmpty(aURL) {
     return (!aURL || aURL == "about:blank" || aURL == "about:empty" || aURL == "about:home");
   },
 
   /** Recursively find all documents, including root document. */
   getAllDocuments: function getAllDocuments(doc, resultSoFar) {
     resultSoFar = resultSoFar || [doc];
--- a/mobile/chrome/content/aboutHome.xhtml
+++ b/mobile/chrome/content/aboutHome.xhtml
@@ -79,17 +79,17 @@
     <div id="newAddons" class="section-box">
       <h1>&aboutHome.recommendedAddons2;</h1>
       <div id="loadingAddons" class="loading">
         <img src="chrome://browser/skin/images/throbber.png"/>
       </div>
     </div>
 
     <div id="about">
-      <img src="chrome://browser/skin/images/mozilla-32.png"/> <a href="http://www.mozilla.com/about/">&aboutHome.aboutMozilla;</a>
+      <img src="chrome://browser/skin/images/mozilla-32.png"/> <a href="http://www.mozilla.com/about/" onclick="openTabs([this.href]); return false;">&aboutHome.aboutMozilla;</a>
     </div>
   </div>
 
   <!-- l10n hack -->
   <div style="display: none">
     <span id="text-openalltabs">&aboutHome.openAllTabs;</span>
     <span id="text-notabs">&aboutHome.noTabs;</span>
     <span id="text-noaddons">&aboutHome.noAddons;</span>
@@ -204,17 +204,18 @@
         titlePart.className = "title";
         inner.appendChild(titlePart);
 
         outer.appendChild(inner);
         list.appendChild(outer);
       }
 
       if (allPageURLs.length > 0) {
-        document.getElementById("loadingTabs").style.display = "none";
+        let loading = document.getElementById("loadingTabs");
+        loading.parentNode.removeChild(loading);
 
         if (allPageURLs.length > 1) {
           let outer = document.createElement("div");
           outer.className = "openall";
           outer.textContent = document.getElementById("text-openalltabs").textContent;
           outer.setAttribute("role", "button");
 
           outer.addEventListener("click", function() {
@@ -233,17 +234,18 @@
       let chromeWin = getChromeWin();
       if ("WeaveGlue" in chromeWin) {
         chromeWin.Services.obs.addObserver(updateWeaveButton, "weave:service:login:finish", false);
         chromeWin.Services.obs.addObserver(updateWeaveButton, "weave:service:logout:finish", false);
 
         updateWeaveButton();
       }
       else {
-        document.getElementById("remoteTabs").style.display = "none";
+        let loading = document.getElementById("remoteTabs");
+        loading.parentNode.removeChild(loading);
       }
     }
 
     function uninitWeave() {
       let chromeWin = getChromeWin();
       if ("WeaveGlue" in chromeWin) {
         chromeWin.Services.obs.removeObserver(updateWeaveButton, "weave:service:login:finish");
         chromeWin.Services.obs.removeObserver(updateWeaveButton, "weave:service:logout:finish");
@@ -280,17 +282,18 @@
       searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
         let list = document.getElementById("newAddons");
         if (aAddons.length == 0) {
           let placeHolder = document.getElementById("loadingAddons");
           placeHolder.innerHTML = "<div class='no-items'>" + document.getElementById("text-noaddons").textContent + "</div>";
           return;
         }
 
-        document.getElementById("loadingAddons").style.display = "none";
+        let loading = document.getElementById("loadingAddons");
+        loading.parentNode.removeChild(loading);
 
         for (let i=0; i<aAddons.length; i++) {  
           let outer = document.createElement("div");
           outer.setAttribute("role", "button");
           outer.setAttribute("addonID", aAddons[i].id);
   
           let addonName = aAddons[i].name;
           outer.addEventListener("click", function() {
@@ -316,17 +319,18 @@
           inner.appendChild(versionPart);
   
           outer.appendChild(inner);
           list.appendChild(outer);
         }
       },
     
       searchFailed: function searchFailed() {
-        document.getElementById("newAddons").style.display = "none";
+        let loading = document.getElementById("newAddons");
+        loading.parentNode.removeChild(loading);
       }
     }
 
     const kAddonsMaxDisplay = 2;
 
     function initAddons() {
       Cu.import("resource://gre/modules/AddonRepository.jsm");
       if (AddonRepository.isSearching)
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -8,16 +8,17 @@
 <bindings
     xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:svg="http://www.w3.org/2000/svg"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="autocomplete-aligned" extends="chrome://global/content/bindings/autocomplete.xml#autocomplete">
     <implementation>
+      <property name="mIgnoreFocus" onget="return true;"/>
       <method name="openPopup">
         <body><![CDATA[
           this.popup.openAutocompletePopup(this, null);
         ]]></body>
       </method>
       <method name="closePopup">
         <body><![CDATA[
           // hack! we want to revert to the "all results" popup when the
@@ -40,30 +41,55 @@
       <handler event="text" phase="bubbling">
         <![CDATA[
           if (this.mController.input == this)
             this.mController.handleText();
         ]]>
       </handler>
       <handler event="blur" phase="capturing">
         <![CDATA[
-          // suppress disconnect of autocomplete controller
+          // Bug 583341 - suppress disconnect of autocomplete controller
           this._dontBlur = true;
         ]]>
       </handler>
     </handlers>
   </binding>
 
   <binding id="popup_autocomplete_result">
+    <handlers>
+      <handler event="contextmenu" phase="capturing">
+        <![CDATA[
+          let url = this.getAttribute("url");
+          if (!url)
+            return;
+
+          let value = this.getAttribute("value");
+          let data = {
+            target: this,
+            json: {
+              types: ["link-saveable", "link-shareable"],
+              label: value,
+              linkTitle: value,
+              linkURL: url
+            }
+          };
+          ContextHelper.showPopup(data);
+        ]]>
+      </handler>
+    </handlers>
     <content orient="vertical">
-      <xul:hbox class="autocomplete-item-label" align="top" xbl:inherits="tags, favorite" mousethrough="always">
+      <xul:hbox class="autocomplete-item-container" align="top" xbl:inherits="favorite" mousethrough="always">
         <xul:image xbl:inherits="src"/>
         <xul:vbox flex="1">
-          <xul:label crop="center" xbl:inherits="value"/>
-          <xul:label class="autocomplete-item-url" xbl:inherits="value=url" crop="center" mousethrough="always"/>
+          <xul:label class="autocomplete-item-label" crop="center" xbl:inherits="value"/>
+          <xul:label class="autocomplete-item-url" xbl:inherits="value=url" crop="center"/>
+        </xul:vbox>
+        <xul:vbox align="end">
+          <xul:label class="autocomplete-item-tags" value="" xbl:inherits="value=tags"/>
+          <xul:label class="autocomplete-item-badge" value="" xbl:inherits="value=badge"/>
         </xul:vbox>
       </xul:hbox>
     </content>
   </binding>
 
   <binding id="popup_autocomplete">
     <content orient="vbox" class="autocomplete-box" flex="1">
       <!-- 24 child items, to match browser.urlbar.maxRichResults -->
@@ -104,16 +130,21 @@
       <property name="boxObject"
                 readonly="true"
                 onget="return this._items.boxObject;"/>
 
       <field name="_scrollBoxObject">
         this.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
       </field>
 
+      <!-- Used by the badges implementation -->
+      <field name="_badges">[]</field>
+      <field name="_badgesTimeout">-1</field>
+      <field name="_eTLDService">Cc["@mozilla.org/network/effective-tld-service;1"].getService(Ci.nsIEffectiveTLDService);</field>
+
       <!-- nsIAutocompleteInput -->
       <property name="overrideValue"
                 readonly="true"
                 onget="return null;"/>
 
       <field name="_input"/>
       <property name="input"
                 readonly="true"
@@ -232,60 +263,68 @@
             if (i > matchCount - 1) {
               // Just clear out the old item's value. CSS takes care of hiding
               // everything else based on value="" (star, tags, etc.)
               item.setAttribute("value", "");
               item._empty = true;
 
               continue;
             }
-            item._empty = false;
 
             // Assign the values
             let type = controller.getStyleAt(i);
             let title = controller.getCommentAt(i);
             let tags = '';
 
             if (type == "tag") {
               try {
                 [, title, tags] = title.match(/^(.+) \u2013 (.+)$/);
               } catch (e) {}
             }
             item.setAttribute("tags", tags);
 
             let url = controller.getValueAt(i);
             item.setAttribute("value", title || url);
-            item.setAttribute("url", url);
+
+            // remove the badge only if the url has changed
+            if (item._empty || item.getAttribute("url") != url) {
+              item.setAttribute("url", url);
+              item.removeAttribute("badge");
+            }
 
             let isBookmark = ((type == "bookmark") || (type == "tag"));
             item.setAttribute("favorite", isBookmark);
             item.setAttribute("src", controller.getImageAt(i));
+
+            item._empty = false;
           }
 
           // Show the "no results" or "all bookmarks" entries as needed
           this._updateNoResultsItem(matchCount);
 
           // Make sure the list is scrolled to the top
           this.scrollToTop();
+          this._invalidateBadges();
         ]]></body>
       </method>
 
       <method name="_updateNoResultsItem">
         <parameter name="isResults" />
         <body><![CDATA[
           let noResultsItem = this._items.childNodes.item(1);
           if (isResults) {
             noResultsItem.className = "";
           } else {
             noResultsItem.className = "noresults";
             noResultsItem.setAttribute("value", "]]>&noResults.label;<![CDATA[");
             noResultsItem.removeAttribute("favorite");
             noResultsItem.removeAttribute("url");
             noResultsItem.removeAttribute("src");
             noResultsItem.removeAttribute("tags");
+            noResultsItem.removeAttribute("badge");
           }
         ]]></body>
       </method>
 
       <method name="selectBy">
         <parameter name="aReverse"/>
         <parameter name="aPage"/>
         <body><![CDATA[
@@ -302,16 +341,74 @@
             newIndex = 0;
           else if (newIndex < 0)
             newIndex = lastIndex;
 
           this.selectedIndex = newIndex;
         ]]></body>
       </method>
 
+      <method name="_getEffectiveHost">
+        <parameter name="aURI"/>
+        <body><![CDATA[
+          let host = null;
+          try {
+            host = aURI.host;
+            return this._eTLDService.getBaseDomainFromHost(host);
+          } catch (e) {}
+
+          return host ? host : aURI.spec;
+        ]]></body>
+      </method>
+
+      <method name="registerBadgeHandler">
+        <parameter name="aURL"/>
+        <parameter name="aHandler"/>
+        <body><![CDATA[
+          if (!aHandler)
+            return false;
+
+          let effectiveHost = this._getEffectiveHost(Services.io.newURI(aURL, null, null));
+          this._badges[effectiveHost] = aHandler;
+          return true;
+        ]]></body>
+      </method>
+
+      <method name="unregisterBagdeHandler">
+        <parameter name="aURL"/>
+        <body><![CDATA[
+          let effectiveHost = this._getEffectiveHost(Services.io.newURI(aURL, null, null));
+          if (this._badges[effectiveHost])
+            delete this._badges[effectiveHost];
+        ]]></body>
+      </method>
+
+      <method name="_invalidateBadges">
+        <body><![CDATA[
+          window.clearTimeout(this._badgesTimeout);
+
+          this._badgesTimeout = window.setTimeout(function(self) {
+            for (let i = 0; i < self._items.childNodes.length; i++) {
+              let item = self._items.childNodes[i];
+              if (!item.hasAttribute("url"))
+                continue;
+
+              let itemHost = self._getEffectiveHost(Services.io.newURI(item.getAttribute("url"), null, null));
+              for (let badgeHost in self._badges) {
+                if (itemHost == badgeHost) {
+                  let handler = self._badges[badgeHost];
+                  handler.updateBadge ? handler.updateBadge(item) : handler(item);
+                  break;
+                }
+              }
+            }
+          }, 300, this);
+        ]]></body>
+      </method>
+
       <!-- Helpers -->
       <field name="_items">
         document.getAnonymousElementByAttribute(this,
                         "anonid", "autocomplete-items");
       </field>
 
       <property name="_matchCount"
                 readonly="true">
@@ -359,23 +456,25 @@
       <handler event="contextmenu" phase="capturing">
         <![CDATA[
           if (!this.uri || this._isEditing)
             return;
 
           let data = {
             target: this,
             json: {
-              types: ["edit-bookmark"],
-              label: this.uri.spec
-          }};
-          ContextHelper.showPopup(data);
-        ]]>
-      </handler>
-    </handlers>
+              types: ["edit-bookmark", "link-saveable", "link-shareable"],
+              label: this.name,
+              linkTitle: this.name,
+              linkURL: this.spec
+           }};
+           ContextHelper.showPopup(data);
+         ]]>
+       </handler>
+     </handlers>
 
     <implementation>
       <field name="_uri">null</field>
       <field name="_control">null</field>
       <field name="_isEditing">false</field>
 
       <field name="_nameField">
         document.getAnonymousElementByAttribute(this, "anonid", "name");
@@ -592,22 +691,25 @@
           ]]>
         </body>
       </method>
     </implementation>
   </binding>
 
   <binding id="place-item" extends="chrome://browser/content/bindings.xml#place-base">
     <content orient="vertical">
-      <xul:hbox anonid="bookmark-item" class="bookmark-item-label" align="top" flex="1" xbl:inherits="tags" mousethrough="always">
+      <xul:hbox anonid="bookmark-item" class="bookmark-item-container" align="top" flex="1" mousethrough="always">
         <xul:image xbl:inherits="src"/>
         <xul:vbox flex="1">
-          <xul:label crop="center" xbl:inherits="value=title"/>
+          <xul:label class="bookmark-item-label" crop="center" xbl:inherits="value=title"/>
           <xul:label anonid="bookmark-url" class="bookmark-item-url" xbl:inherits="value=uri" crop="center" mousethrough="always"/>
         </xul:vbox>
+        <xul:vbox>
+          <xul:label class="bookmark-item-tags" xbl:inherits="value=tags"/>
+        </xul:vbox>
       </xul:hbox>
 
       <xul:hbox anonid="bookmark-manage" class="bookmark-manage" hidden="true" flex="1">
         <xul:image xbl:inherits="src"/>
         <xul:vbox flex="1">
           <xul:vbox flex="1">
             <xul:textbox anonid="name" xbl:inherits="value=title"/>
             <xul:textbox anonid="uri" xbl:inherits="value=uri"/>
@@ -1116,17 +1218,17 @@
             client.tabs.forEach(function({title, urlHistory, icon}) {
               let pageUrl = urlHistory[0];
 
               // Skip tabs that are already open
               if (engine.locallyOpenTabMatchesURL(pageUrl))
                 return;
 
               tabs.push({
-                title: title ? pageUrl : title,
+                title: title || pageUrl,
                 uri: pageUrl,
                 icon: Weave.Utils.getIcon(icon, "chrome://browser/skin/images/tab.png")
               });
             });
           };
 
           return tabs;
         ]]></body>
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -200,36 +200,41 @@ var BrowserUI = {
     if (this.isAutoCompleteOpen())
       this._edit.defaultValue = aCaption;
     else
       this._edit.value = aCaption;
   },
 
   _editURI: function _editURI(aEdit) {
     if (aEdit) {
+      // If the urlbar is not opened yet, inform the broadcaster and then
+      // save the current value as a default value to display once the awesome
+      // panel will be dismissed
       let isOpened = this._edit.hasAttribute("open");
       if (!isOpened) {
         Elements.urlbarState.setAttribute("mode", "edit");
         this._edit.defaultValue = this._edit.value;
+
+        // Now, replace the web page title by the url of the page
+        let urlString = this.getDisplayURI(Browser.selectedBrowser);
+        if (Util.isURLEmpty(urlString))
+          urlString = "";
+        this._edit.value = urlString;
       }
 
-      // Replace the web page title by the url of the page
-      let urlString = this.getDisplayURI(Browser.selectedBrowser);
-      if (Util.isURLEmpty(urlString))
-        urlString = "";
-      this._edit.value = urlString;
-
-      if (!this._edit.readOnly) {
+      // If the urlbar readOnly state is set to false or if the window is in
+      // portrait then we refresh the IME state to display the VKB if any
+      if (!this._edit.readOnly || Util.isPortrait()) {
         // This is a workaround needed to cycle focus for the IME state
         // to be set properly (bug 488420)
         this._edit.blur();
         gFocusManager.setFocus(this._edit, Ci.nsIFocusManager.FLAG_NOSCROLL);
       }
 
-      this._edit.readOnly = !isOpened;
+      this._edit.readOnly = false;
     }
     else if (!aEdit) {
       this._updateToolbar();
     }
   },
 
   updateAwesomeHeader: function updateAwesomeHeader(aVisible) {
     document.getElementById("awesome-header").hidden = aVisible;
@@ -387,16 +392,18 @@ var BrowserUI = {
     this._edit = document.getElementById("urlbar-edit");
     this._throbber = document.getElementById("urlbar-throbber");
     this._favicon = document.getElementById("urlbar-favicon");
     this._favicon.addEventListener("error", this, false);
 
     this._edit.addEventListener("click", this, false);
     this._edit.addEventListener("mousedown", this, false);
 
+    BadgeHandlers.register(this._edit.popup);
+
     let awesomePopup = document.getElementById("popup_autocomplete");
     awesomePopup.addEventListener("popupshown", this, false);
     awesomePopup.addEventListener("popuphidden", this, false);
 
     document.getElementById("toolbar-main").ignoreDrag = true;
 
     let tabs = document.getElementById("tabs");
     tabs.addEventListener("TabSelect", this, true);
@@ -561,29 +568,33 @@ var BrowserUI = {
   closeAutoComplete: function closeAutoComplete(aResetInput) {
     if (!this.isAutoCompleteOpen())
       return;
 
     if (aResetInput)
       this._edit.popup.close();
     else
       this._edit.popup.closePopup();
+
+    // Because the controller is not detached during a blur event for Meego
+    // compatibility with the VKB, we need to detach it manually
+    this._edit.detachController();
+    this.activePanel = null;
   },
 
   isAutoCompleteOpen: function isAutoCompleteOpen() {
     return this._edit.popup.popupOpen;
   },
 
   doOpenSearch: function doOpenSearch(aName) {
     // save the current value of the urlbar
     let searchValue = this._edit.value;
 
     // Give the new page lots of room
     Browser.hideSidebars();
-    this.activePanel = null;
     this.closeAutoComplete(false);
 
     // Make sure we're online before attempting to load
     Util.forceOnline();
 
     let engine = Services.search.getEngineByName(aName);
     let submission = engine.getSubmission(searchValue, null);
     Browser.loadURI(submission.uri.spec, { postData: submission.postData });
@@ -627,16 +638,17 @@ var BrowserUI = {
   },
 
   closeTab: function closeTab(aTab) {
     // If no tab is passed in, assume the current tab
     Browser.closeTab(aTab || Browser.selectedTab);
   },
 
   selectTab: function selectTab(aTab) {
+    this.activePanel = null;
     Browser.selectedTab = aTab;
   },
 
   undoCloseTab: function undoCloseTab(aIndex) {
     let tab = null;
     let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
     if (ss.getClosedTabCount(window) > (aIndex || 0)) {
       tab = ss.undoCloseTab(window, aIndex || 0);
@@ -922,17 +934,16 @@ var BrowserUI = {
         browser.reloadWithFlags(reloadFlags);
         break;
       }
       case "cmd_stop":
         browser.stop();
         break;
       case "cmd_go":
         this.goToURI();
-        this.activePanel = null;
         break;
       case "cmd_openLocation":
         this.showToolbar(true);
         break;
       case "cmd_star":
       {
         let bookmarkURI = browser.currentURI;
         let autoClose = false;
@@ -1375,18 +1386,18 @@ var AwesomePanel = function(aElementId, 
     command.removeAttribute("checked", "true");
     BrowserUI.popDialog();
   },
 
   this.openLink = function aw_openLink(aEvent) {
     let item = aEvent.originalTarget;
     let uri = item.getAttribute("url") || item.getAttribute("uri");
     if (uri != "") {
+      BrowserUI.goToURI(uri);
       BrowserUI.activePanel = null;
-      BrowserUI.goToURI(uri);
     }
   }
 };
 
 var BookmarkPopup = {
   get box() {
     delete this.box;
     this.box = document.getElementById("bookmark-popup");
@@ -2408,17 +2419,16 @@ var ContextCommands = {
   },
 
   removeBookmark: function cc_removeBookmark() {
     let target = ContextHelper.popupState.target;
     target.remove();
   }
 }
 
-
 var SharingUI = {
   _dialog: null,
 
   show: function show(aURL, aTitle) {
     this._dialog = importDialog(window, "chrome://browser/content/share.xul", null);
     document.getElementById("share-title").value = aTitle || aURL;
 
     BrowserUI.pushPopup(this, this._dialog);
@@ -2475,8 +2485,79 @@ var SharingUI = {
       callback: function callback(aURL, aTitle) {
         let url = "http://www.facebook.com/share.php?u=" + encodeURIComponent(aURL);
         Browser.addTab(url, true, Browser.selectedTab);
       }
     }
   ]
 };
 
+
+var BadgeHandlers = {
+  _handlers: [
+    {
+      _lastUpdate: 0,
+      _lastCount: 0,
+      url: "http://mail.google.com",
+      updateBadge: function(aItem) {
+        // Use the cache if possible
+        let now = Date.now();
+        if (this._lastCount && this._lastUpdate > now - 1000) {
+          aItem.setAttribute("badge", this._lastCount);
+          return;
+        }
+
+        this._lastUpdate = now;
+
+        // Use any saved username and password. If we don't have any login and we are not
+        // currently logged into Gmail, we won't get any count.
+        let login = BadgeHandlers.getLogin("https://www.google.com");
+
+        // Get the feed and read the count, passing any saved username and password
+        // but do not show any security dialogs if we fail
+        let req = new XMLHttpRequest();
+        req.mozBackgroundRequest = true;
+        req.open("GET", "https://mail.google.com/mail/feed/atom", true, login.username, login.password);
+        req.onreadystatechange = function(aEvent) {
+          if (req.readyState == 4) {
+            if (req.status == 200) {
+              this._lastCount = req.responseXML.getElementsByTagName("fullcount")[0].childNodes[0].nodeValue;
+            } else {
+              this._lastCount = 0;
+            }
+            this._lastCount = BadgeHandlers.setNumberBadge(aItem, this._lastCount);
+          }
+        };
+        req.send(null);
+      }
+    }
+  ],
+
+  register: function(aPopup) {
+    let handlers = this._handlers;
+    for (let i = 0; i < handlers.length; i++)
+      aPopup.registerBadgeHandler(handlers[i].url, handlers[i]);
+  },
+
+  getLogin: function(aURL) {
+    let lm = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
+    let logins = lm.findLogins({}, aURL, aURL, null);
+    let username = logins.length > 0 ? logins[0].username : "";
+    let password = logins.length > 0 ? logins[0].password : "";
+    return { username: username, password: password };
+  },
+
+  clampBadge: function(aValue) {
+    if (aValue > 100)
+      aValue = "99+";
+    return aValue;
+  },
+
+  setNumberBadge: function(aItem, aValue) {
+    if (parseInt(aValue) != 0) {
+      aValue = this.clampBadge(aValue);
+      aItem.setAttribute("badge", aValue);
+    } else {
+      aItem.removeAttribute("badge");
+    }
+    return aValue;
+  }
+};
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -51,17 +51,17 @@
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 function getBrowser() {
   return Browser.selectedBrowser;
 }
 
-const kDefaultBrowserWidth = 800;
+const kDefaultBrowserWidth = 980;
 const kBrowserFormZoomLevelMin = 1.0;
 const kBrowserFormZoomLevelMax = 2.0;
 const kBrowserViewZoomLevelPrecision = 10000;
 
 // Override sizeToContent in the main window. It breaks things (bug 565887)
 window.sizeToContent = function() {
   Components.utils.reportError("window.sizeToContent is not allowed in this window");
 }
@@ -163,20 +163,16 @@ var Browser = {
       messageManager.loadFrameScript("chrome://browser/content/Util.js", true);
       messageManager.loadFrameScript("chrome://browser/content/forms.js", true);
       messageManager.loadFrameScript("chrome://browser/content/content.js", true);
     } catch (e) {
       // XXX whatever is calling startup needs to dump errors!
       dump("###########" + e + "\n");
     }
 
-    let needOverride = Util.needHomepageOverride();
-    if (needOverride == "new profile")
-      this.initNewProfile();
-
     let container = document.getElementById("browsers");
     // XXX change
 
     /* handles dispatching clicks on browser into clicks in content or zooms */
     let inputHandlerOverlay = document.getElementById("inputhandler-overlay");
     inputHandlerOverlay.customClicker = new ContentCustomClicker();
     inputHandlerOverlay.customKeySender = new ContentCustomKeySender();
     inputHandlerOverlay.customDragger = new Browser.MainDragger();
@@ -297,55 +293,23 @@ var Browser = {
 
     // Login Manager and Form History initialization
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
     Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
     // Make sure we're online before attempting to load
     Util.forceOnline();
 
-    // Command line arguments/initial homepage
-    let whereURI = this.getHomePage();
-    if (needOverride == "new profile")
-        whereURI = "about:firstrun";
-
-    // If this is an intial window launch (was a nsICommandLine passed via window params)
-    // we execute some logic to load the initial launch page
-    if (window.arguments && window.arguments[0]) {
-      if (window.arguments[0] instanceof Ci.nsICommandLine) {
-        try {
-          var cmdLine = window.arguments[0];
+    // If this is an intial window launch the commandline handler passes us the default
+    // page as an argument
+    let defaultURL = this.getHomePage();
+    if (window.arguments && window.arguments[0])
+      defaultURL = window.arguments[0];
 
-          // Check for and use a single commandline parameter
-          if (cmdLine.length == 1) {
-            // Assume the first arg is a URI if it is not a flag
-            var uri = cmdLine.getArgument(0);
-            if (uri != "" && uri[0] != '-') {
-              whereURI = cmdLine.resolveURI(uri);
-              if (whereURI)
-                whereURI = whereURI.spec;
-            }
-          }
-
-          // Check for the "url" flag
-          var uriFlag = cmdLine.handleFlagWithParam("url", false);
-          if (uriFlag) {
-            whereURI = cmdLine.resolveURI(uriFlag);
-            if (whereURI)
-              whereURI = whereURI.spec;
-          }
-        } catch (e) {}
-      }
-      else {
-        // This window could have been opened by nsIBrowserDOMWindow.openURI
-        whereURI = window.arguments[0];
-      }
-    } 
-
-    this.addTab(whereURI, true);
+    this.addTab(defaultURL, true);
 
     // JavaScript Error Console
     if (Services.prefs.getBoolPref("browser.console.showInPanel")){
       let button = document.getElementById("tool-console");
       button.hidden = false;
     }
 
     // If some add-ons were disabled during during an application update, alert user
@@ -443,19 +407,16 @@ var Browser = {
     os.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
     os.removeObserver(MemoryObserver, "memory-pressure");
     os.removeObserver(BrowserSearch, "browser-search-engine-modified");
 
     window.controllers.removeController(this);
     window.controllers.removeController(BrowserUI);
   },
 
-  initNewProfile: function initNewProfile() {
-  },
-
   getHomePage: function () {
     let url = "about:home";
     try {
       url = Services.prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data;
     } catch (e) { }
 
     return url;
   },
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -344,20 +344,16 @@
         <pageaction id="pageaction-password" title="&pageactions.password.forget;"
           onclick="PageActions.forgetPassword(); PageActions.hideItem(this);"/>
         <pageaction id="pageaction-reset" title="&pageactions.reset;"
           onclick="PageActions.clearPagePermissions(); PageActions.hideItem(this);"/>
         <pageaction id="pageaction-search" title="&pageactions.search.addNew;"/>
       </hbox>
     </vbox>
 
-    <vbox id="newtab-popup" hidden="true" class="dialog-dark" onclick="NewTabPopup.selectTab()" align="center" left="21">
-      <label/>
-    </vbox>
-
     <vbox id="bookmark-popup" hidden="true" class="dialog-dark" align="center">
       <label value="&bookmarkPopup.label;"/>
       <separator class="thin"/>
       <vbox>
         <button id="bookmark-popup-edit" label="&bookmarkEdit.label;" class="button-dark" oncommand="BookmarkHelper.edit();"/>
         <spacer/>
         <button id="bookmark-popup-remove" label="&bookmarkRemove.label;" class="button-dark" oncommand="BookmarkPopup.hide(); BookmarkHelper.removeBookmarksForURI(getBrowser().currentURI);"/>
       </vbox>
@@ -510,16 +506,20 @@
 
       <!-- titlebar autocomplete results -->
       <vbox id="popup_autocomplete" class="panel-dark" flex="1" onshow="BrowserUI._edit.showHistoryPopup();" hidden="true"/>
       <placelist id="bookmarks-items" type="bookmarks" onopen="BookmarkList.openLink(event);" onhide="BrowserUI.updateStar();" flex="1" hidden="true"/>
       <historylist id="history-items" onopen="HistoryList.openLink(event);" flex="1" hidden="true"/>
       <remotetabslist id="remotetabs-items" onopen="RemoteTabsList.openLink(event)" flex="1" hidden="true"/>
     </vbox>
 
+    <vbox id="newtab-popup" hidden="true" class="dialog-dark" onclick="NewTabPopup.selectTab()" align="center" left="21">
+      <label/>
+    </vbox>
+
     <!-- options dialog for select form field -->
     <vbox id="select-container" hidden="true" pack="center">
       <spacer id="select-spacer" flex="1000"/>
       <vbox id="select-container-inner" class="dialog-dark" flex="1">
         <scrollbox id="select-list" flex="1" orient="vertical"/>
         <hbox id="select-buttons" pack="center">
           <button id="select-buttons-done" class="button-dark" label="&selectHelper.done;" oncommand="SelectHelperUI.hide();"/>
         </hbox>
--- a/mobile/chrome/content/config.js
+++ b/mobile/chrome/content/config.js
@@ -10,17 +10,17 @@
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Mozilla Mobile Browser.
  *
  * The Initial Developer of the Original Code is
  * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
+ * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
@@ -80,18 +80,16 @@ var ViewConfig = {
 
     let result = Utils.getPrefs(aValue);
     this._container.setItems(result.map(this._createItem, this));
   },
 
   open: function open(aType) {
     let buttons = document.getElementById("editor-buttons-add");
     buttons.setAttribute("hidden", "true");
-    let nameField = document.getElementById("editor-name");
-    nameField.value = "";
 
     let shouldFocus = false;
     let setting = document.getElementById("editor-setting");
     switch (aType) {
       case Ci.nsIPrefBranch.PREF_INT:
         setting.setAttribute("type", "integer");
         break;
       case Ci.nsIPrefBranch.PREF_BOOL:
@@ -103,34 +101,38 @@ var ViewConfig = {
     }
 
     setting.removeAttribute("title");
     setting.removeAttribute("pref");
     if (setting.input)
       setting.input.value = "";
 
     document.getElementById("editor-container").appendChild(this._editor);
+    let nameField = document.getElementById("editor-name");
+    nameField.value = "";
+
     this._editor.setAttribute("hidden", "false");
     this._currentItem = null;
     nameField.focus();
   },
 
   close: function close(aValid) {
     this._editor.setAttribute("hidden", "true");
     let buttons = document.getElementById("editor-buttons-add");
     buttons.setAttribute("hidden", "false");
 
     if (aValid) {
-      let name = document.getElementById("editor-name").value;
+      let name = document.getElementById("editor-name").inputField.value;
       if (name != "") {
         let setting = document.getElementById("editor-setting");
         setting.setAttribute("pref", name);
         setting.valueToPreference();
       }
     }
+
     document.getElementById("editor-container").appendChild(this._editor);
   },
 
   _currentItem: null,
   edit: function(aItem) {
     if (!aItem)
       return;
 
@@ -392,17 +394,17 @@ var Utils = {
     }
 
     let evt = document.createEvent("UIEvents");
     evt.initUIEvent(type, true, true, window, index);
     window.dispatchEvent(evt);
   },
 
   _generateRegexp: function _generateRegexp(aValue) {
-    if (aValue.charAt(0) == '/') {
+    if (aValue.charAt(0) == "/") {
       try {
         let rv = aValue.match(/^\/(.*)\/(i?)$/);
         return RegExp(rv[1], rv[2]);
       }
       catch (e) {
         return null; // Do nothing on incomplete or bad RegExp
       }
     }
--- a/mobile/chrome/content/config.xul
+++ b/mobile/chrome/content/config.xul
@@ -12,17 +12,17 @@
    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    - for the specific language governing rights and limitations under the
    - License.
    -
    - The Original Code is Mozilla Mobile Browser.
    -
    - The Initial Developer of the Original Code is
    - Mozilla Corporation.
-   - Portions created by the Initial Developer are Copyright (C) 2008
+   - Portions created by the Initial Developer are Copyright (C) 2010
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
@@ -64,19 +64,19 @@
       <richlistbox id="prefs-container" flex="1" onselect="ViewConfig.edit(this.selectedItem)" batch="25">
         <richlistitem id="editor-row">
           <vbox id="editor-container" flex="1">
 
             <hbox align="center" flex="1">
               <label value="&newpref.label;" flex="1"/>
               <spacer flex="1" />
               <hbox id="editor-buttons-add">
-                <button label="&integer.label;" oncommand="ViewConfig.open(Components.interfaces.nsIPrefBranch.PREF_INT)"/>
-                <button label="&boolean.label;" oncommand="ViewConfig.open(Components.interfaces.nsIPrefBranch.PREF_BOOL)"/>
-                <button label="&string.label;" oncommand="ViewConfig.open(Components.interfaces.nsIPrefBranch.PREF_STRING)"/>
+                <button label="&integer.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_INT)"/>
+                <button label="&boolean.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_BOOL)"/>
+                <button label="&string.label;" oncommand="ViewConfig.open(Ci.nsIPrefBranch.PREF_STRING)"/>
               </hbox>
             </hbox>
 
             <vbox id="editor" hidden="true">
               <hbox align="center">
                 <textbox id="editor-name" emptytext="&addpref.name;" flex="1"/>
                 <setting id="editor-setting" emptytext="&addpref.value;" onlabel="true" offlabel="false" flex="1"/>
               </hbox>
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -1,13 +1,13 @@
 // This stays here because otherwise it's hard to tell if there's a parsing error
 dump("###################################### content loaded\n");
 
 // how many milliseconds before the mousedown and the overlay of an element
-const kTapOverlayTimeout = 300;
+const kTapOverlayTimeout = 200;
 
 let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 let gFocusManager = Cc["@mozilla.org/focus-manager;1"]
--- a/mobile/chrome/content/extensions.js
+++ b/mobile/chrome/content/extensions.js
@@ -803,18 +803,20 @@ AddonInstallListener.prototype = {
     if (!host)
       host = (aInstall.sourceURI instanceof Ci.nsIStandardURL) && aInstall.sourceURI.host;
 
     let error = (host || aInstall.error == 0) ? "addonError" : "addonLocalError";
     if (aInstall.error != 0)
       error += aInstall.error;
     else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
       error += "Blocklisted";
+    else if (!aInstall.addon.isCompatible)
+      error += "Incompatible";
     else
-      error += "Incompatible";
+      return; // no need to show anything in this case
 
     let messageString = strings.getString(error);
     messageString = messageString.replace("#1", aInstall.name);
     if (host)
       messageString = messageString.replace("#2", host);
     messageString = messageString.replace("#3", brandShortName);
     messageString = messageString.replace("#4", Services.appinfo.version);
     
--- a/mobile/chrome/tests/Makefile.in
+++ b/mobile/chrome/tests/Makefile.in
@@ -74,12 +74,14 @@ include $(topsrcdir)/config/rules.mk
   browser_viewport_03.html \
   browser_viewport_04.html \
   browser_viewport_05.html \
   browser_viewport_06.html \
   browser_viewport_07.html \
   browser_viewport_08.html \
   browser_viewport_09.html \
   browser_viewport.js \
+  browser_no_title.html \
+  browser_english_title.html \
   $(NULL)
 
 libs:: $(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/tests/browser_english_title.html
@@ -0,0 +1,7 @@
+<html>
+<head><title>English Title Page</title>
+<link rel="shortcut icon" 
+href="data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==" />
+</head>
+<body>This is english title page</body>
+</html>
--- a/mobile/chrome/tests/browser_navigation.js
+++ b/mobile/chrome/tests/browser_navigation.js
@@ -1,10 +1,13 @@
 var testURL_01 = "chrome://mochikit/content/browser/mobile/chrome/browser_blank_01.html";
 var testURL_02 = "chrome://mochikit/content/browser/mobile/chrome/browser_blank_02.html";
+var testURL_03 = "chrome://mochikit/content/browser/mobile/chrome/browser_english_title.html";
+var testURL_04 = "chrome://mochikit/content/browser/mobile/chrome/browser_no_title.html";
+var pngURL = "data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==";
 
 // A queue to order the tests and a handle for each test
 var gTests = [];
 var gCurrentTest = null;
 
 function pageLoaded(url) {
   return function() {
     let tab = gCurrentTest._currentTab;
@@ -13,17 +16,16 @@ function pageLoaded(url) {
 }
 
 //------------------------------------------------------------------------------
 // Entry point (must be named "test")
 function test() {
   // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()"
   // We call "finish()" when the tests are finished
   waitForExplicitFinish();
-
   // Start the tests
   runNextTest();
 }
 
 //------------------------------------------------------------------------------
 // Iterating tests by shifting test out one by one as runNextTest is called.
 function runNextTest() {
   // Run the next test until all tests completed
@@ -46,17 +48,17 @@ function runNextTest() {
 
 //------------------------------------------------------------------------------
 // Case: Loading a page into the URLBar with VK_RETURN
 gTests.push({
   desc: "Loading a page into the URLBar with VK_RETURN",
   _currentTab: null,
 
   run: function() {
-    this._currentTab = Browser.addTab(testURL_01, true);
+    gCurrentTest._currentTab = Browser.addTab(testURL_01, true);
 
     // Wait for the tab to load, then do the test
     waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01));
   },
 
   onPageReady: function() {
     // Test the mode
     let urlIcons = document.getElementById("urlbar-icons");
@@ -75,32 +77,33 @@ gTests.push({
     EventUtils.synthesizeMouse(urlbarEdit, urlbarEdit.clientWidth / 2, urlbarEdit.clientHeight / 2, {});
 
     // Wait for the awesomebar to load, then do the test
     window.addEventListener("popupshown", gCurrentTest.onFocusReady, false);
   },
 
   onFocusReady: function() {
     window.removeEventListener("popupshown", gCurrentTest.onFocusReady, false);
+
     // Test mode
     let urlIcons = document.getElementById("urlbar-icons");
     is(urlIcons.getAttribute("mode"), "edit", "URL Mode is set to 'edit'");
 
     // Test back button state
     let back = document.getElementById("tool-back");
     is(back.disabled, !gCurrentTest._currentTab.browser.canGoBack, "Back button check");
 
     // Test forward button state
     let forward = document.getElementById("tool-forward");
     is(forward.disabled, !gCurrentTest._currentTab.browser.canGoForward, "Forward button check");
 
     // Check button states (url edit is focused)
-    let go = document.getElementById("tool-go");
-    let goStyle = window.getComputedStyle(go, null);
-    is(goStyle.visibility, "visible", "GO is visible");
+    let search = document.getElementById("tool-search");
+    let searchStyle = window.getComputedStyle(search, null);
+    is(searchStyle.visibility, "visible", "SEARCH is visible");
 
     let stop = document.getElementById("tool-stop");
     let stopStyle = window.getComputedStyle(stop, null);
     is(stopStyle.visibility, "collapse", "STOP is hidden");
 
     let reload = document.getElementById("tool-reload");
     let reloadStyle = window.getComputedStyle(reload, null);
     is(reloadStyle.visibility, "collapse", "RELOAD is hidden");
@@ -113,19 +116,19 @@ gTests.push({
     waitFor(gCurrentTest.onPageFinish, pageLoaded(testURL_02));
   },
 
   onPageFinish: function() {
     let urlIcons = document.getElementById("urlbar-icons");
     is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'");
 
     // Check button states (url edit is not focused)
-    let go = document.getElementById("tool-go");
-    let goStyle = window.getComputedStyle(go, null);
-    is(goStyle.visibility, "collapse", "GO is hidden");
+    let search = document.getElementById("tool-search");
+    let searchStyle = window.getComputedStyle(search, null);
+    is(searchStyle.visibility, "collapse", "SEARCH is hidden");
 
     let stop = document.getElementById("tool-stop");
     let stopStyle = window.getComputedStyle(stop, null);
     is(stopStyle.visibility, "collapse", "STOP is hidden");
 
     let reload = document.getElementById("tool-reload");
     let reloadStyle = window.getComputedStyle(reload, null);
     is(reloadStyle.visibility, "visible", "RELOAD is visible");
@@ -145,88 +148,122 @@ gTests.push({
     let back = document.getElementById("tool-back");
     is(back.disabled, !gCurrentTest._currentTab.browser.canGoBack, "Back button check");
 
     // Test forward button state
     let forward = document.getElementById("tool-forward");
     is(forward.disabled, !gCurrentTest._currentTab.browser.canGoForward, "Forward button check");
 
     Browser.closeTab(gCurrentTest._currentTab);
-
     runNextTest();
   }
 });
 
 //------------------------------------------------------------------------------
-// Case: Loading a page into the URLBar with GO button
+// Bug 570706 - --browser-chrome Mochitests on Fennec [post navigation]
+// Check for text in the url bar for no title, with title and title change after pageload
 gTests.push({
-  desc: "Loading a page into the URLBar with GO button",
+  desc: "Check for text in the url bar for no title, with title and title change after pageload",
   _currentTab: null,
 
   run: function() {
-    this._currentTab = Browser.addTab(testURL_01, true);
+    gCurrentTest._currentTab = Browser.addTab(testURL_03, true);
 
     // Wait for the tab to load, then do the test
-    waitFor(gCurrentTest.onPageReady, pageLoaded(testURL_01));
+    messageManager.addMessageListener("pageshow", function() {
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_03) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageReady();
+    }});
   },
 
   onPageReady: function() {
-    let urlIcons = document.getElementById("urlbar-icons");
-    is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'");
+    let urlbarEdit = document.getElementById("urlbar-edit");
+    is(urlbarEdit.value, "English Title Page", "The title must be displayed in urlbar");
+    Browser.closeTab(gCurrentTest._currentTab);
+    gCurrentTest._currentTab = Browser.addTab(testURL_04, true);
+
+    messageManager.addMessageListener("pageshow", function() {
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_04) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageReady2();
+    }});
+  },
 
-    // Focus the url edit
+  onPageReady2: function(){
     let urlbarEdit = document.getElementById("urlbar-edit");
+    is(urlbarEdit.value, testURL_04, "The url for no title must be displayed in urlbar");
+    Browser.closeTab(gCurrentTest._currentTab);
+
+    // Check whether title appears after a pageload
+    gCurrentTest._currentTab = Browser.addTab(testURL_01, true);
+    messageManager.addMessageListener("pageshow", function() {
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_01) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageReady3();
+    }});
+  },
+
+  onPageReady3: function(){
+    let urlbarEdit = document.getElementById("urlbar-edit");
+    is(urlbarEdit.value, "Browser Blank Page 01", "The title of the first page must be displayed");
     EventUtils.synthesizeMouse(urlbarEdit, urlbarEdit.clientWidth / 2, urlbarEdit.clientHeight / 2, {});
 
     // Wait for the awesomebar to load, then do the test
     window.addEventListener("popupshown", gCurrentTest.onFocusReady, false);
   },
 
   onFocusReady: function() {
     window.removeEventListener("popupshown", gCurrentTest.onFocusReady, false);
-    let urlIcons = document.getElementById("urlbar-icons");
-    is(urlIcons.getAttribute("mode"), "edit", "URL Mode is set to 'edit'");
-
-    // Check button states (url edit is focused)
-    let go = document.getElementById("tool-go");
-    let goStyle = window.getComputedStyle(go, null);
-    is(goStyle.visibility, "visible", "GO is visible");
+    EventUtils.synthesizeString(testURL_02, window);
+    EventUtils.synthesizeKey("VK_RETURN", {}, window)
 
-    let stop = document.getElementById("tool-stop");
-    let stopStyle = window.getComputedStyle(stop, null);
-    is(stopStyle.visibility, "collapse", "STOP is hidden");
-
-    let reload = document.getElementById("tool-reload");
-    let reloadStyle = window.getComputedStyle(reload, null);
-    is(reloadStyle.visibility, "collapse", "RELOAD is hidden");
-
-    EventUtils.synthesizeString(testURL_02, window);
-    EventUtils.synthesizeMouse(go, go.clientWidth / 2, go.clientHeight / 2, {});
-
-    // Wait for the tab to load, then do the test
-    waitFor(gCurrentTest.onPageFinish, pageLoaded(testURL_02));
+    messageManager.addMessageListener("pageshow", function() {
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_02) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageFinish();
+    }});
   },
 
   onPageFinish: function() {
-    let urlIcons = document.getElementById("urlbar-icons");
-    is(urlIcons.getAttribute("mode"), "view", "URL Mode is set to 'view'");
-
-    // Check button states (url edit is not focused)
-    let go = document.getElementById("tool-go");
-    let goStyle = window.getComputedStyle(go, null);
-    is(goStyle.visibility, "collapse", "GO is hidden");
-
-    let stop = document.getElementById("tool-stop");
-    let stopStyle = window.getComputedStyle(stop, null);
-    is(stopStyle.visibility, "collapse", "STOP is hidden");
-
-    let reload = document.getElementById("tool-reload");
-    let reloadStyle = window.getComputedStyle(reload, null);
-    is(reloadStyle.visibility, "visible", "RELOAD is visible");
-
-    let uri = gCurrentTest._currentTab.browser.currentURI.spec;
-    is(uri, testURL_02, "URL Matches newly created Tab");
-
+    let urlbarEdit = document.getElementById("urlbar-edit");
+    is(urlbarEdit.value, "Browser Blank Page 02", "The title of the second page must be displayed");
     Browser.closeTab(gCurrentTest._currentTab);
-
     runNextTest();
   }
 });
+
+// Case: Check for appearance of the favicon
+gTests.push({
+  desc: "Check for appearance of the favicon",
+  _currentTab: null,
+
+  run: function() {
+    gCurrentTest._currentTab = Browser.addTab(testURL_04, true);
+    messageManager.addMessageListener("pageshow", function() {
+
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_04) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageReady();
+    }});
+  },
+
+  onPageReady: function() {
+    let favicon = document.getElementById("urlbar-favicon");
+    is(favicon.src, "", "The default favicon must be loaded");
+    Browser.closeTab(gCurrentTest._currentTab);
+
+    gCurrentTest._currentTab = Browser.addTab(testURL_03, true);
+    messageManager.addMessageListener("pageshow", function() {
+    if (gCurrentTest._currentTab.browser.currentURI.spec == testURL_03) {
+      messageManager.removeMessageListener("pageshow", arguments.callee);
+      gCurrentTest.onPageFinish();
+    }});
+  },
+
+  onPageFinish: function(){
+    let favicon = document.getElementById("urlbar-favicon");
+    is(favicon.src, pngURL, "The page favicon must be loaded");
+    Browser.closeTab(gCurrentTest._currentTab);
+    runNextTest();
+  }
+});
+
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/tests/browser_no_title.html
@@ -0,0 +1,7 @@
+<html>
+<head>
+</head>
+<body>
+Hi this is a no title page
+</body>
+</html>
--- a/mobile/chrome/tests/browser_viewport.js
+++ b/mobile/chrome/tests/browser_viewport.js
@@ -50,17 +50,17 @@ function pageLoaded(url) {
   dump("------- pageLoaded: " + url + "\n")
   return function() {
     dump("------- waiting for pageLoaded: " + working_tab.browser.currentURI.spec + "\n")
     return !working_tab.isLoading() && working_tab.browser.currentURI.spec == url;
   }
 }
 
 let testData = [
-  { width: 800,     scale: 1 },
+  { width: 980,     scale: 800/980 },
   { width: 533.33,  scale: 1.5 },
   { width: 533.33,  scale: 1.5 },
   { width: 533.33,  scale: 1.5,    disableZoom: true },
   { width: 200,     scale: 4.00 },
   { width: 2000,    scale: 1.125,  minScale: 1.125 },
   { width: 266.67,  scale: 3,      maxScale: 3 },
   { width: 2000,    scale: 1.125 },
   { width: 10000,   scale: 4 },
@@ -87,17 +87,17 @@ function startTest(n) {
 function verifyBlank(n) {
   return function() {
     // Do sanity tests
     var uri = working_tab.browser.currentURI.spec;
     is(uri, testURL_blank, "URL Matches blank page "+n);
 
     // Check viewport settings
     let style = window.getComputedStyle(working_tab.browser, null);
-    is(style.width, "800px", "Normal 'browser' width is 800 pixels");
+    is(style.width, "980px", "Normal 'browser' width is 980 pixels");
 
     loadTest(n);
   }
 }
 
 function loadTest(n) {
   let url = testURL(n);
   BrowserUI.goToURI(url);
--- a/mobile/chrome/tests/browser_viewport_00.html
+++ b/mobile/chrome/tests/browser_viewport_00.html
@@ -1,14 +1,14 @@
 <html>
 <head>
     <title>Browser Viewport Page 00</title>
     <meta name="viewport" content=""/>
 
     <!-- Expected: treat page like a desktop webpage -->
-    <meta name="expected-width" content="800"/>
+    <meta name="expected-width" content="980"/>
     <meta name="expected-scale" content="1"/>
 </head>
 <body>
     <p>Browser Viewport Page 00</p>
     <p>default width, default initial-scale</p>
 </body>
 </html>
--- a/mobile/components/BrowserCLH.js
+++ b/mobile/components/BrowserCLH.js
@@ -37,18 +37,24 @@
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-function openWindow(aParent, aURL, aTarget, aFeatures) {
-  return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, null);
+function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) {
+  let argString = null;
+  if (aArgs) {
+    argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    argString.data = aArgs;
+  }
+  
+  return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, argString);
 }
 
 function resolveURIInternal(aCmdLine, aArgument) {
   let uri = aCmdLine.resolveURI(aArgument);
 
   if (!(uri instanceof Ci.nsIFileURL))
     return uri;
 
@@ -66,16 +72,53 @@ function resolveURIInternal(aCmdLine, aA
   }
   catch (e) {
     Cu.reportError(e);
   }
 
   return uri;
 }
 
+/**
+ * Determines whether a home page override is needed.
+ * Returns:
+ *  "new profile" if this is the first run with a new profile.
+ *  "new version" if this is the first run with a build with a different
+ *                      Gecko milestone (i.e. right after an upgrade).
+ *  "none" otherwise.
+ */
+function needHomepageOverride() {
+  let savedmstone = null;
+  try {
+    savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
+  } catch (e) {}
+
+  if (savedmstone == "ignore")
+    return "none";
+
+#expand    let ourmstone = "__MOZ_APP_VERSION__";
+
+  if (ourmstone != savedmstone) {
+    Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone);
+
+    return (savedmstone ? "new version" : "new profile");
+  }
+
+  return "none";
+}
+
+function getHomePage() {
+  let url = "about:home";
+  try {
+    url = Services.prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data;
+  } catch (e) { }
+
+  return url;
+}
+
 
 function BrowserCLH() { }
 
 BrowserCLH.prototype = {
   //
   // nsICommandLineHandler
   //
   handle: function fs_handle(aCmdLine) {
@@ -90,51 +133,90 @@ BrowserCLH.prototype = {
       let autoComplete = Cc["@mozilla.org/autocomplete/search;1?name=history"].
                          getService(Ci.nsIAutoCompleteSearch);
     }
 
     // Handle chrome windows loaded via commandline
     let chromeParam = aCmdLine.handleFlagWithParam("chrome", false);
     if (chromeParam) {
       try {
-        // only load URIs which do not inherit chrome privs
+        // Only load URIs which do not inherit chrome privs
         let features = "chrome,dialog=no,all";
         let uri = resolveURIInternal(aCmdLine, chromeParam);
         let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
         if (!netutil.URIChainHasFlags(uri, Ci.nsIHttpProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
-          openWindow(null, uri.spec, "_blank", features);
+          openWindow(null, uri.spec, "_blank", features, null);
+
+          // Stop the normal commandline processing from continuing
           aCmdLine.preventDefault = true;
         }
       }
       catch (e) {
         Cu.reportError(e);
       }
     }
 
-    let win;
-    try {
-      win = Services.wm.getMostRecentWindow("navigator:browser");
-      if (!win)
-        return;
+    // Keep an array of possible URL arguments
+    let uris = [];
 
-      win.focus();
-      aCmdLine.preventDefault = true;
-    } catch (e) { }
+    // Check for the "url" flag
+    let uriFlag = aCmdLine.handleFlagWithParam("url", false);
+    if (uriFlag) {
+      let uri = resolveURIInternal(aCmdLine, uriFlag);
+      if (uri)
+        uris.push(uri);
+    }
 
-    // Assumption:  All CLH arguments we've received have been sent remotely,
-    // or we wouldn't already have a window.  Therefore: open 'em all!
     for (let i = 0; i < aCmdLine.length; i++) {
       let arg = aCmdLine.getArgument(i);
       if (!arg || arg[0] == '-')
         continue;
 
       let uri = resolveURIInternal(aCmdLine, arg);
       if (uri)
-        win.browserDOMWindow.openURI(uri, null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, null);
+        uris.push(uri);
     }
+
+    // Open the main browser window, if we don't already have one
+    let win;
+    try {
+      win = Services.wm.getMostRecentWindow("navigator:browser");
+      if (!win) {
+        // Default to the saved homepage
+        let defaultURL = getHomePage();
+  
+        // Override the default if we have a new profile
+        if (needHomepageOverride() == "new profile")
+            defaultURL = "about:firstrun";
+  
+        // Override the default if we have a URL passed on command line
+        if (uris.length > 0) {
+          defaultURL = uris[0].spec;
+          uris = uris.slice(1);
+        }
+
+        win = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", defaultURL);
+      }
+
+      win.focus();
+
+      // Stop the normal commandline processing from continuing. We just opened the main browser window
+      aCmdLine.preventDefault = true;
+    } catch (e) { }
+
+    // Assumption: All remaining command line arguments have been sent remotely (browser is already running)
+    // Action: Open any URLs we find into an existing browser window
+
+    // First, get a browserDOMWindow object
+    while (!win.browserDOMWindow)
+      Services.tm.currentThread.processNextEvent(true);
+
+    // Open any URIs into new tabs
+    for (let i = 0; i < uris.length; i++)
+      win.browserDOMWindow.openURI(uris[i], null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, null);
   },
 
   // QI
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 
   // XPCOMUtils factory
   classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}"),
 };
rename from mobile/components/GeolocationPrompt.js
rename to mobile/components/ContentPermissionPrompt.js
--- a/mobile/components/GeolocationPrompt.js
+++ b/mobile/components/ContentPermissionPrompt.js
@@ -2,49 +2,52 @@ const Ci = Components.interfaces;
 const Cr = Components.results;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const kCountBeforeWeRemember = 5;
 
-function GeolocationPrompt() {}
+function ContentPermissionPrompt() {}
 
-GeolocationPrompt.prototype = {
+ContentPermissionPrompt.prototype = {
   classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationPrompt]),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
 
   prompt: function(aRequest) {
+    if (aRequest.type != "geolocation")
+      return;
+
     let pm = Services.perms;
-    let result = pm.testExactPermission(aRequest.requestingURI, "geo");
+    let result = pm.testExactPermission(aRequest.uri, "geo");
 
     if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
       aRequest.allow();
       return;
     } else if (result == Ci.nsIPermissionManager.DENY_ACTION) {
       aRequest.cancel();
       return;
     }
 
     function setPagePermission(aUri, aAllow) {
       let contentPrefs = Services.contentPrefs;
 
-      if (!contentPrefs.hasPref(aRequest.requestingURI, "geo.request.remember"))
-        contentPrefs.setPref(aRequest.requestingURI, "geo.request.remember", 0);
+      if (!contentPrefs.hasPref(aRequest.uri, "geo.request.remember"))
+        contentPrefs.setPref(aRequest.uri, "geo.request.remember", 0);
 
-      let count = contentPrefs.getPref(aRequest.requestingURI, "geo.request.remember");
+      let count = contentPrefs.getPref(aRequest.uri, "geo.request.remember");
 
       if (aAllow == false)
         count--;
       else
         count++;
 
-      contentPrefs.setPref(aRequest.requestingURI, "geo.request.remember", count);
+      contentPrefs.setPref(aRequest.uri, "geo.request.remember", count);
 
       if (count == kCountBeforeWeRemember)
         pm.add(aUri, "geo", Ci.nsIPermissionManager.ALLOW_ACTION);
       else if (count == -kCountBeforeWeRemember)
         pm.add(aUri, "geo", Ci.nsIPermissionManager.DENY_ACTION);
     }
 
     function getChromeWindow(aWindow) {
@@ -55,55 +58,55 @@ GeolocationPrompt.prototype = {
         .rootTreeItem
         .QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIDOMWindow)
         .QueryInterface(Ci.nsIDOMChromeWindow);
       return chromeWin;
     }
 
     let notificationBox = null;
-    if (aRequest.requestingWindow) {
-      let requestingWindow = aRequest.requestingWindow.top;
+    if (aRequest.window) {
+      let requestingWindow = aRequest.window.top;
       let chromeWin = getChromeWindow(requestingWindow).wrappedJSObject;
       notificationBox = chromeWin.getNotificationBox(requestingWindow);
     } else {
-      let chromeWin = aRequest.requestingElement.ownerDocument.defaultView;
+      let chromeWin = aRequest.element.ownerDocument.defaultView;
       notificationBox = chromeWin.Browser.getNotificationBox();
     }
 
     let notification = notificationBox.getNotificationWithValue("geolocation");
     if (!notification) {
       let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
 
       let buttons = [{
         label: browserBundle.GetStringFromName("geolocation.share"),
         accessKey: null,
         callback: function(notification) {
-          setPagePermission(aRequest.requestingURI, true);
+          setPagePermission(aRequest.uri, true);
           aRequest.allow();
         },
       },
       {
         label: browserBundle.GetStringFromName("geolocation.dontShare"),
         accessKey: null,
         callback: function(notification) {
-          setPagePermission(aRequest.requestingURI, false);
+          setPagePermission(aRequest.uri, false);
           aRequest.cancel();
         },
       }];
 
       let message = browserBundle.formatStringFromName("geolocation.siteWantsToKnow",
-                                                       [aRequest.requestingURI.host], 1);
+                                                       [aRequest.uri.host], 1);
 
       let newBar = notificationBox.appendNotification(message,
                                                       "geolocation",
                                                       "chrome://browser/skin/images/geo-16.png",
                                                       notificationBox.PRIORITY_WARNING_MEDIUM,
                                                       buttons);
       // Make this a geolocation notification.
       newBar.setAttribute("type", "geo");
     }
   }
 };
 
 
 //module initialization
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([GeolocationPrompt]);
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
--- a/mobile/components/HelperAppDialog.js
+++ b/mobile/components/HelperAppDialog.js
@@ -32,18 +32,24 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
+const Cr = Components.results;
 
 const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
+#ifdef ANDROID
+const URI_GENERIC_ICON_DOWNLOAD = "drawable://alertdownloads";
+#else
+const URI_GENERIC_ICON_DOWNLOAD = "chrome://browser/skin/images/alert-downloads-30.png";
+#endif
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 // -----------------------------------------------------------------------
 // HelperApp Launcher Dialog
 // -----------------------------------------------------------------------
 
@@ -54,23 +60,38 @@ HelperAppLauncherDialog.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
 
   show: function hald_show(aLauncher, aContext, aReason) {
     // Check to see if we can open this file or not
     if (aLauncher.MIMEInfo.hasDefaultHandler) {
       aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.useSystemDefault;
       aLauncher.launchWithApplication(null, false);
     } else {
-      aLauncher.saveToDisk(null, false);
+      let wasClicked = false;
+      let listener = {
+        observe: function(aSubject, aTopic, aData) {
+          if (aTopic == "alertclickcallback") {
+            wasClicked = true;
+            let win = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator).getMostRecentWindow("navigator:browser");
+            if (win)
+              win.BrowserUI.showPanel("downloads-container");
+  
+            aLauncher.saveToDisk(null, false);
+          } else {
+            if (!wasClicked)
+              aLauncher.cancel(Cr.NS_BINDING_ABORTED);
+          }
+        }
+      };
+      this._notify(aLauncher, listener);
     }
   },
 
   promptForSaveToFile: function hald_promptForSaveToFile(aLauncher, aContext, aDefaultFile, aSuggestedFileExt, aForcePrompt) {
     let file = null;
-
     let prefs = Services.prefs;
 
     if (!aForcePrompt) {
       // Check to see if the user wishes to auto save to the default download
       // folder without prompting. Note that preference might not be set.
       let autodownload = true;
       try {
         autodownload = prefs.getBoolPref(PREF_BD_USEDOWNLOADDIR);
@@ -89,17 +110,17 @@ HelperAppLauncherDialog.prototype = {
 
         // Check to make sure we have a valid directory, otherwise, prompt
         if (file)
           return file;
       }
     }
 
     // Use file picker to show dialog.
-    let picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+    let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
     let windowTitle = "";
     let parent = aContext.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal);
     picker.init(parent, windowTitle, Ci.nsIFilePicker.modeSave);
     picker.defaultString = aDefaultFile;
 
     if (aSuggestedFileExt) {
       // aSuggestedFileExtension includes the period, so strip it
       picker.defaultExtension = aSuggestedFileExt.substring(1);
@@ -192,30 +213,40 @@ HelperAppLauncherDialog.prototype = {
           else
             aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
         }
         else {
           // replace the last (n) in the filename with (n+1)
           aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
         }
       }
-      aLocalFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
+      aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
     }
     catch (e) {
       dump("*** exception in validateLeafName: " + e + "\n");
 
-      if (e.result == Components.results.NS_ERROR_FILE_ACCESS_DENIED)
+      if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
         throw e;
 
       if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
         aLocalFile.append("unnamed");
         if (aLocalFile.exists())
-          aLocalFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
+          aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0600);
       }
     }
   },
 
   isUsableDirectory: function hald_isUsableDirectory(aDirectory) {
     return aDirectory.exists() && aDirectory.isDirectory() && aDirectory.isWritable();
+  },
+
+  _notify: function hald_notify(aLauncher, aCallback) {
+    let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+
+    let notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
+    notifier.showAlertNotification(URI_GENERIC_ICON_DOWNLOAD,
+                                   bundle.GetStringFromName("alertDownloads"),
+                                   bundle.GetStringFromName("alertCantOpenDownload"),
+                                   true, "", aCallback, "downloadopen-fail");
   }
 };
 
 const NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppLauncherDialog]);
--- a/mobile/components/Makefile.in
+++ b/mobile/components/Makefile.in
@@ -47,30 +47,30 @@ MODULE = MobileComponents
 XPIDL_MODULE = MobileComponents
 
 XPIDLSRCS = \
         SessionStore.idl \
         $(NULL)
 
 EXTRA_PP_COMPONENTS = \
         AboutRedirector.js \
+        BrowserCLH.js \
         DirectoryProvider.js\
+        HelperAppDialog.js \
         Sidebar.js \
         SessionStore.js \
         $(NULL)
 
 EXTRA_COMPONENTS = \
         MobileComponents.manifest \
         BrowserStartup.js \
-        GeolocationPrompt.js \
+        ContentPermissionPrompt.js \
         XPIDialogService.js \
         DownloadManagerUI.js \
-        HelperAppDialog.js \
         PromptService.js \
-        BrowserCLH.js \
         ContentDispatchChooser.js \
         AutoCompleteCache.js \
         AddonUpdateService.js \
         FormAutoComplete.js \
         LoginManager.js \
         BlocklistPrompt.js \
 	$(NULL)
 
--- a/mobile/components/MobileComponents.manifest
+++ b/mobile/components/MobileComponents.manifest
@@ -32,19 +32,19 @@ category app-startup SessionStore servic
 
 # BrowserStartup.js
 component {1d542abc-c88b-4636-a4ef-075b49806317} BrowserStartup.js
 contract @mozilla.org/browser/browser-startup;1 {1d542abc-c88b-4636-a4ef-075b49806317}
 category app-startup BrowserStartup service,@mozilla.org/browser/browser-startup;1
 category agent-style-sheets browser-content-stylesheet chrome://browser/content/content.css
 category agent-style-sheets browser-cursor-stylesheet chrome://browser/content/cursor.css
 
-# GeolocationPrompt.js
-component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} GeolocationPrompt.js
-contract @mozilla.org/geolocation/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
+# ContentPermissionPrompt.js
+component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} ContentPermissionPrompt.js
+contract @mozilla.org/content-permission/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
 
 # AlertsService.js
 component {fe33c107-82a4-41d6-8c64-5353267e04c9} AlertsService.js
 contract @mozilla.org/system-alerts-service;1 {fe33c107-82a4-41d6-8c64-5353267e04c9}
 
 # XPIDialogService.js
 component {c1242012-27d8-477e-a0f1-0b098ffc329b} XPIDialogService.js
 contract @mozilla.org/addons/web-install-prompt;1 {c1242012-27d8-477e-a0f1-0b098ffc329b}
--- a/mobile/components/PromptService.js
+++ b/mobile/components/PromptService.js
@@ -55,22 +55,21 @@ function PromptService() {
     // Setup listener for child messages. We don't need to call
     // addMessageListener as the wakeup service will do that for us.
     this.receiveMessage = function(aMessage) {
       var json = aMessage.json;
       switch (aMessage.name) {
         case "Prompt:Call":
           // List of methods we remote - to check against malicious data.
           // For example, it would be dangerous to allow content to show
-          // auth prompts. We allow only the methods that web content
-          // is allowed to show.
-          const ALL_METHODS = ['alert', 'confirm', 'prompt'];
+          // auth prompts.
+          const ALL_METHODS = ["alert", "alertCheck", "confirm", "prompt", "confirmEx", "confirmCheck", "select"];
           var method = aMessage.json.method;
           if (ALL_METHODS.indexOf(method) == -1)
-            throw 'PromptServiceRemoter received an invalid method';
+            throw "PromptServiceRemoter received an invalid method "+method;
           var arguments = aMessage.json.arguments;
           arguments.unshift(null); // No need for window, child is already on top
                                    // (see mobile browser's PromptService.js)
           var ret = this[method].apply(this, arguments);
           // Return multiple return values in objects of form { value: ... },
           // and also with the actual return value at the end
           arguments.push(ret);
           return arguments;
--- a/mobile/locales/en-US/chrome/browser.properties
+++ b/mobile/locales/en-US/chrome/browser.properties
@@ -84,16 +84,17 @@ alertLockScreen.unlocked=Unlocked
 # LOCALIZATION NOTE (alertAddonsDisabled): Semi-colon list of plural forms.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 number of add-ons
 alertAddonsDisabled=#1 incompatible add-on was disabled;#1 incompatible add-ons were disabled
 
 alertDownloads=Downloads
 alertDownloadsStart=Downloading: %S
 alertDownloadsDone=%S has finished downloading
+alertCantOpenDownload=Can't open file. Tap to save it.
 
 # Notifications
 notificationRestart.normal=Restart to complete changes.
 notificationRestart.update=Add-ons updated. Restart to complete changes.
 notificationRestart.blocked=Unsafe add-ons installed. Restart to disable.
 notificationRestart.button=Restart
 
 # Popup Blocker
--- a/mobile/themes/core/browser.css
+++ b/mobile/themes/core/browser.css
@@ -664,17 +664,17 @@ placeitem[type="folder"] {
 placeitem[type="folder"]:-moz-locale-dir(rtl) {
   background: url(images/arrowleft-16.png) no-repeat 2% 50%;
 }
 
 placelist[ui="manage"] placeitem[type="folder"] {
   background-image: none;
 }
 
-placeitem[type="folder"] > .bookmark-item-label > image,
+placeitem[type="folder"] > .bookmark-item-container > image,
 placeitem[type="folder"] > .bookmark-manage > image {
   list-style-image: url(images/folder-32.png);
   margin-top: 0;
 }
 
 placeitem[type="folder"] .bookmark-item-url {
   display: none;
 }
@@ -752,89 +752,120 @@ placeitem {
 autocompleteresult:active,
 placelist placeitem:active:not([selected="true"]),
 historylist placeitem:active:not([selected="true"]):not([class="history-item-title"]),
 historylist placeitem:active:not([selected="true"]):not([class="remotetabs-item-title"]),
 .autocompleteresult-selected {
   background-color: #8db8d8;
 }
 
+.autocomplete-item-container,
+.bookmark-item-container {
+  margin: 0;
+  padding: 0;
+}
+
 .autocomplete-item-label,
 .bookmark-item-label {
-  margin: 0;
-  padding: 0;
   font-size: 24px !important;
   font-weight: normal;
   -moz-margin-end: 8px;
 }
 
-.autocomplete-item-label > image,
-.bookmark-item-label > image,
+.autocomplete-item-container > image,
+.bookmark-item-container > image,
 placeitem > .bookmark-manage > image {
   width: 32px;
   height: 32px;
   max-height: 32px;
   /* margin-top = (1 - title's line-height) * title's font-size */
   margin-top: 5px;
   margin-bottom: 0;
   -moz-margin-end: 16px;
   -moz-margin-start: 8px;
 }
 
-.autocomplete-item-label > image[src=""],
-placeitem[src=""] .bookmark-item-label > image {
+.autocomplete-item-container > image[src=""],
+placeitem[src=""] .bookmark-item-container > image {
   list-style-image: url(chrome://mozapps/skin/places/defaultFavicon.png);
 }
 
-.autocomplete-item-label > vbox > label,
-.bookmark-item-label > vbox > label {
+.autocomplete-item-container > vbox > label,
+.bookmark-item-container > vbox > label {
   -moz-margin-start: 1px;
 }
 
-.autocomplete-item-label[favorite="true"] {
-  -moz-padding-end: 30px;
+.autocomplete-item-container[favorite="true"] {
   background: url(images/star-24.png) no-repeat 100% 2px;
 }
 
-.autocomplete-item-label[favorite="true"]:-moz-locale-dir(rtl) {
+.autocomplete-item-container[favorite="true"]:-moz-locale-dir(rtl) {
   background: url(images/star-24.png) no-repeat left 2px;
 }
 
-.autocomplete-item-label:not([tags=""]):after,
-.bookmark-item-label:not([tags=""]):after {
-  float: right;
-  content: attr(tags);
-  font-size: 18px !important;
-  font-weight: lighter;
-  padding-top: 4px;
-  -moz-margin-start: 8px;
-}
-
 .autocomplete-item-url,
 .bookmark-item-url {
   color: blue;
   font-size: 18px !important;
   -moz-margin-end: 24px;
 }
 
+.autocomplete-item-container[favorite="true"] .autocomplete-item-label {
+  -moz-padding-end: 30px;
+}
+
+.autocomplete-item-tags,
+.bookmark-item-tags {
+  content: attr(tags);
+  font-size: 18px !important;
+  font-weight: lighter;
+  margin: 2px 0 4px 0px;
+  -moz-margin-start: 8px;
+  -moz-padding-end: 32px;
+}
+
+.autocomplete-item-tags[value=""] {
+  visibility: hidden;
+}
+
+.autocomplete-item-badge {
+  opacity: 1;
+  -moz-transition: opacity 1s ease;
+  background-color: #c90707;
+  border: 1px solid #951919;
+  -moz-border-radius: 2px;
+  content: attr(badge);
+  font-size: 12px !important;
+  font-weight: bolder;
+  margin: 4px 0 0 0;
+  padding: 4px 6px;
+  color: white;
+}
+
+autocompleteresult:not([badge]) .autocomplete-item-badge,
+.autocomplete-item-badge[value=""] {
+  opacity: 0;
+  -moz-transition: none;
+}
+
 /* special "no results", "awesome header row" and "title rows" items */
 autocompleteresult[class="history-item-title"],
 autocompleteresult[class="remotetabs-item-title"] {
   -moz-box-pack: center;
   background-color: #E9E9E9;
   min-height: 0px;
 }
 
 autocompleteresult[class="history-item-title"] .bookmark-item-url,
 autocompleteresult[class="remotetabs-item-title"] .bookmark-item-url {
   display: none;
 }
 
-autocompleteresult[class="history-item-title"] .bookmark-item-label,
-autocompleteresult[class="remotetabs-item-title"] .bookmark-item-label {
+autocompleteresult[class="history-item-title"] .bookmark-item-container,
+autocompleteresult[class="remotetabs-item-title"] .bookmark-item-container {
   font-size: 24px !important;
 }
 
 autocompleteresult[class="history-item-title"] image,
 autocompleteresult[class="remotetabs-item-title"] image {
   display: none;
 }
 
@@ -842,17 +873,17 @@ autocompleteresult.noresults {
   font-style: italic;
   border-bottom: none;
 }
 
 autocompleteresult.noresults:active {
   background-color: white;
 }
 
-autocompleteresult.noresults > .autocomplete-item-label {
+autocompleteresult.noresults > .autocomplete-item-container {
   text-align: center;
   color: grey;
 }
 
 #awesome-header {
   min-height: 70px; /* row size */
 }