merge fx-team to mozilla-central
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 20 Feb 2014 12:55:32 +0100
changeset 169658 cf9666cc3f36ec029d906a62168e22cff368c13d
parent 169641 bc918b6de20e14687370aee12f832a0ce76b1005 (current diff)
parent 169657 1d91384b87772dbb08238e6c6d0765e2eac5ed2a (diff)
child 169665 065154d862431ed5b85ce163cc2d43e6bce80660
child 169671 698f220114f996ad2d6069f6258eb006429e0baa
child 169676 03598731cb2abc11911f14bb5c9153475b410d30
push id26260
push usercbook@mozilla.com
push dateThu, 20 Feb 2014 11:55:50 +0000
treeherdermozilla-central@cf9666cc3f36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.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 fx-team to mozilla-central
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -778,17 +778,16 @@ toolbarbutton[sdk-button="true"][cui-are
 
 .urlbar-textbox-container {
   -moz-appearance: none;
   -moz-box-align: stretch;
 }
 
 .urlbar-input-box {
   -moz-margin-start: 0;
-  min-width: 4em;
 }
 
 .urlbar-history-dropmarker {
   -moz-appearance: toolbarbutton-dropdown;
 }
 
 #urlbar-container {
   -moz-box-orient: horizontal;
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1725,17 +1725,16 @@ toolbarbutton[sdk-button="true"][cui-are
 
 #identity-icon-labels {
   -moz-margin-start: 4px;
 }
 
 .urlbar-input-box {
   -moz-margin-start: 0;
   padding: 3px 0 2px;
-  min-width: 4em;
 }
 
 .urlbar-history-dropmarker {
   padding: 0 3px;
   list-style-image: url("chrome://browser/skin/urlbar-history-dropmarker.png");
   -moz-image-region: rect(0px, 11px, 14px, 0px);
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -968,17 +968,16 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
 }
 
 .urlbar-textbox-container {
   -moz-box-align: stretch;
 }
 
 .urlbar-input-box {
   -moz-margin-start: 0;
-  min-width: 4em;
 }
 
 #urlbar-icons {
   -moz-box-align: center;
 }
 
 .urlbar-icon {
   padding: 0 3px;
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -2175,16 +2175,17 @@ abstract public class BrowserApp extends
             MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, false);
             MenuUtils.safeSetEnabled(aMenu, R.id.site_settings, false);
             MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, false);
 
             return true;
         }
 
         bookmark.setEnabled(!AboutPages.isAboutReader(tab.getURL()));
+        bookmark.setVisible(!GeckoProfile.get(this).inGuestMode());
         bookmark.setCheckable(true);
         bookmark.setChecked(tab.isBookmark());
         bookmark.setIcon(tab.isBookmark() ? R.drawable.ic_menu_bookmark_remove : R.drawable.ic_menu_bookmark_add);
 
         back.setEnabled(tab.canDoBack());
         forward.setEnabled(tab.canDoForward());
         desktopMode.setChecked(tab.getDesktopMode());
         desktopMode.setIcon(tab.getDesktopMode() ? R.drawable.ic_menu_desktop_mode_on : R.drawable.ic_menu_desktop_mode_off);
--- a/mobile/android/base/db/BrowserProvider.java
+++ b/mobile/android/base/db/BrowserProvider.java
@@ -697,27 +697,31 @@ public class BrowserProvider extends Tra
             // using disjoint flags, so we can simply use SUM and DISTINCT to get the
             // flags we need.
             // We turn parents into flags according to the three kinds, above.
             //
             // When this query is extended to support queries across multiple tables, simply
             // extend it to look like
             //
             // SELECT COALESCE((SELECT ...), 0) | COALESCE(...) | ...
+
+            final boolean includeDeleted = shouldShowDeleted(uri);
             final String query = "SELECT COALESCE(SUM(flag), 0) AS flags " +
                 "FROM ( SELECT DISTINCT CASE" +
                 " WHEN " + Bookmarks.PARENT + " = " + Bookmarks.FIXED_READING_LIST_ID +
                 " THEN " + Bookmarks.FLAG_READING +
 
                 " WHEN " + Bookmarks.PARENT + " = " + Bookmarks.FIXED_PINNED_LIST_ID +
                 " THEN " + Bookmarks.FLAG_PINNED +
 
                 " ELSE " + Bookmarks.FLAG_BOOKMARK +
                 " END flag " +
-                "FROM " + TABLE_BOOKMARKS + " WHERE " + Bookmarks.URL + " = ? " +
+                "FROM " + TABLE_BOOKMARKS + " WHERE " +
+                Bookmarks.URL + " = ? " +
+                (includeDeleted ? "" : ("AND " + Bookmarks.IS_DELETED + " = 0")) +
                 ")";
 
             return db.rawQuery(query, selectionArgs);
         }
 
         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
         String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT);
         String groupBy = null;
--- a/mobile/android/base/prompts/Prompt.java
+++ b/mobile/android/base/prompts/Prompt.java
@@ -98,17 +98,17 @@ public class Prompt implements OnClickLi
             mInitialized = true;
         }
     }
 
     private View applyInputStyle(View view, PromptInput input) {
         // Don't add padding to color picker views
         if (input.canApplyInputStyle()) {
             view.setPadding(mInputPaddingSize, 0, mInputPaddingSize, 0);
-	}
+        }
         return view;
     }
 
     public void show(JSONObject message) {
         processMessage(message);
     }
 
     public void show(String title, String text, PromptListItem[] listItems, boolean multipleSelection) {
@@ -309,16 +309,30 @@ public class Prompt implements OnClickLi
      *        The items to add.
      */
     private void addMenuList(AlertDialog.Builder builder, PromptListItem[] listItems) {
         PromptListAdapter adapter = new PromptListAdapter(mContext, android.R.layout.simple_list_item_1, listItems);
         builder.setAdapter(adapter, this);
         mSelected = null;
     }
 
+
+    /* Wraps an input in a linearlayout. We do this so that we can set padding that appears outside the background
+     * drawable for the view.
+     */
+    private View wrapInput(final PromptInput input) {
+        final LinearLayout linearLayout = new LinearLayout(mContext);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        applyInputStyle(linearLayout, input);
+
+        linearLayout.addView(input.getView(mContext));
+
+        return linearLayout;
+    }
+
     /* Add the requested input elements to the dialog.
      *
      * @param builder
      *        the alert builder currently building this dialog.
      * @return 
      *         return true if the inputs were added successfully. This may fail
      *         if the requested input is compatible with this Android verison
      */
@@ -328,28 +342,28 @@ public class Prompt implements OnClickLi
             return true;
         }
 
         try {
             View root = null;
             boolean scrollable = false; // If any of the innuts are scrollable, we won't wrap this in a ScrollView
 
             if (length == 1) {
-                root = mInputs[0].getView(mContext);
-                applyInputStyle(root, mInputs[0]);
+                root = wrapInput(mInputs[0]);
                 scrollable |= mInputs[0].getScrollable();
             } else if (length > 1) {
                 LinearLayout linearLayout = new LinearLayout(mContext);
                 linearLayout.setOrientation(LinearLayout.VERTICAL);
+
                 for (int i = 0; i < length; i++) {
-                    View content = mInputs[i].getView(mContext);
-                    applyInputStyle(content, mInputs[i]);
+                    View content = wrapInput(mInputs[i]);
                     linearLayout.addView(content);
                     scrollable |= mInputs[i].getScrollable();
                 }
+
                 root = linearLayout;
             }
 
             if (scrollable) {
                 builder.setView(root);
             } else {
                 ScrollView view = new ScrollView(mContext);
                 view.addView(root);
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..72fca192131d9aaa905795729c3caa98d178559e
GIT binary patch
literal 1223
zc$@*p1UUPNP)<h;3K|Lk000e1NJLTq002+`002Y?1^@s67FMz#000DzNkl<Zc-rk;
zS!)wf6mDGVR;^nR6&FNQP+YO%@=)+WswAXo(k!)5C`4S*Czq;3R1g&r7gSos1q4Ne
z7HvT(C`hYStD@N24ZG!U#P8G-nb@Yy%w(Bl&cH`P(aF8vz2~0oo|Bbj>?fpvIUkqH
zH5QmzTwJ`;>2%_&s}i4g@mUWv1HXVCAgB@pz;B=xXaZ{R-W$N-l9G}g9*<{nSy|Z>
z48f9)yjkpa`*chyA2@(X-RDWR0eu?CQUh9yA3y_s_X<AUSiB{Lg@qFg&ssr2!8i<f
zK6Zc?c!2L;l0evK=mOpXXMoMTD~<I80)a6QnRyss1&d~Pib;zm^51}~*pZvc%gZMk
zf;^keHWh;^0&4k83K|>(EE%Usv}y5Ew(Br}6%f^H7)(bR5cfa&fmay6HR-#N4rKhe
z4S2&V8cbufLD`)2dcCugLSAWU=`^g`5jG!!8G>HS=^lx6qHVf7tk$J8IqS5XjkO?g
zbwX@Mhr=-!KXAtYW=Wz+eC>9-*T<DaoDXxb#c$G9&tUSDB-WAV6c_Tyqk!06$WXD3
zs-ZFGCy=^Dy2vB-ju#zFQ!_=kOGvIDZ6M8d9>jJhUi8(3<b}}=68HH1{_&~_#6h|Y
zFL;>&cAj1|k`JxcT*(3R=S`wCV)0n2i;9Y7sUdJ1`-?%rUvGu{eKq#pb0KXA8i1w4
zM9d=<2SnFHho=xW1Qep%OA+>{1hT>WRLF`7ighlGMxX`c**QlcWDSo_piJTBg(3o@
z5Z_xu(#W7xg~GTFDK+m};G>W<D#$v?k06kg2ma_cnZK*q#ltQ<#L6TT-hH|FW0jB-
zyBPa?z8OjamjmyFoS4zX;jX^~vi5BiVq*79z*(`9z@y^#s?MRDP!f1sNKt(bRw>WG
z7eb0^)F}!4AcUw!vywnjAQ}`&n81+6`+24}sFef`2qEgzpRxnvv;*Y~)OiMq7LJ1!
z7CTUn9VniNPESO9Vg0_aL}T<sV<aA^8t)_GffA9{8IhKph|ZjdWaV^b<s>hx3J-_P
z3(L&}oi`KYZjAoBG0NLn9YWU7+gadd--x%f=;5kMxgV(Ieqi_k(_8S5KMQI9@RMo-
zW4_{RwOS`rX}$zn2SJrt*HxE0K$I6?Cq9;N|6u9YDouS4@E<pFxx87)qY8JM=Avxw
zfv^i`F=LSpOuGHLn^oXN*?<rDZX)u!K;9|x&f->~ju-AW35ng9>sg9W#k<%#8%o8I
z;Q<G7AS$UUKVgj~usU1WrRmSG8euA`tVl)!3JdiX;BFnA8Di(vL%Oz;(oAMgtQ?9=
zu$j}Brn`<jjEmG~D`mZ7xGeS@2O85wtf?K;Gp>i8WP}cF*<^HMK$r3TlYvvDbmY{q
z<m4HyhZY^cAaV@`cZ@RkTqc_8UD?BqKsDf`n5W@e;!(_u%4VsL9}wX1SPPp8i6*p{
z7p{?-=}-(0N^f1<jN)WJ)Ng=R9TVC>qC-Y1CiRG%bPk!d>k#=KCW{(5)=_E}?>^3{
l3CeZnrmVS`v;d9m`2#LR4Dx=eit7LX002ovPDHLkV1gcYJS+eJ
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..aefa5c4125b8a094d9cfad4c131a1547e5ff35c5
GIT binary patch
literal 717
zc$@*v0y6!HP)<h;3K|Lk000e1NJLTq001fg002Y?1^@s6_dTa^0007%Nkl<Zc-rln
z%}X0m6vflp(u!y+THIL?!9|PEE)>@;ghIvALRYR_hzjDiwMwMBE~L<If?_ZvnMp7S
zagl-|!HtRwKR{Hh4Na^58{;|YjHCr^{G59+4-Ri;_v5~g`|f+k<N4F90_1*+L?VZ$
z=)g41pU^hGm!Kr{75{_i+YQ603j_jXmSx>?8}uY)qtWOl`gv#!-*02FSbZv$x+e|v
zFCoG|&@Z4L1#~N;ED|(-ssMBYz@ITKTKs<heW{?wz|b0?M>r+CUhi$GppN#TS?J}3
zqkF}mj&`6A;c&QGIw<uEn&ecF4(iO^8AP_}%zN)OgF3Kt*cqOm3DyNrXB$f)vQMOg
zIy*un6be0-4w_5FOu>mn;-Pd<rr%wt$LI6i6%A@@k!J)Ap!<mGL_8j^k`9{7UWn=|
z4WQIKU>p8Hv?PLN0NM+cNC&090kl>F=pI13^3tnVP--eK35W(|b<nH<l&N*VUR0t%
zbHk4VOQi<TCHojC9+Y*~YYm{RvEFL{rN&i&vRu&;(G@MAI}WHN95ky1^gvxi)y&c2
zs=sOb=y);L-?-Bg=I64O^QejwzM7gzM-^(CW<Wz-ujZyi#obc|!``RiHc!R<=oTP5
zq~AFI#*lwG^%+M9D4!gkihdQLV}e8eU-N<6k74Nh3o^~P2uZ`ta59-Jm;4r*fj(l$
zA4q;({tm#QU@%xA)mT77!8#zj&t-(Uu6>d@+%Sx`bUJ-UqNjvW+`_{7L?53>JCVJr
zr=b@Z?ox>ctv$LTd8ULONwd7s{kY0Ecl2*iJ=R>hRr3Ou1FX9jX}aPW5_9lb!JGFL
zfo5%}72XB$ngx0Xb>hE~oA#xc1Pf@gEyHL>^VDj8g){To00000NkvXXu0mjfk=s#u
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable-v19/toast_button.xml
@@ -0,0 +1,20 @@
+<!--
+  Copyright 2012 Roman Nurik
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/toast_button_pressed" android:state_pressed="true"/>
+    <item android:drawable="@drawable/toast_button_pressed" android:state_focused="true"/>
+    <item android:drawable="@android:color/transparent"/>
+</selector>
\ No newline at end of file
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..77e69c72ab9afccc0afa1772c9087ad3333189d4
GIT binary patch
literal 2090
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
UA4kTif&c&j07*qoM6N<$g6?_+uK)l5
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..94cc59789d1da2526016767827019a4fac2f7b95
GIT binary patch
literal 808
zc$@(!1K0eCP)<h;3K|Lk000e1NJLTq001`t003GD1^@s69I?*A0008-Nkl<Zc-rlp
zO-mb56o$1*saP!9jY74eRR4rpjDJHH)#9!@o7#=0OWoOBL5zgNd}q-r3JO`ZxM>$n
z6f8DT{P-Kw_l#GWN;HX@$=sJa@N#FC5BJ`4&zy75X=u23tSY3}lT0S9cszbyMyIh@
z>@UVW=m)fc?`4dEL?ST(`S3k}@u`k*x9J2>d5qi8Dl~)d*H9<aVp&$B&TvkhK?NuW
zeFfZXG#VYwWHQeg;7TbMyLjFJv=_jSnc(ah1>7HuTY#HRr_+6bK;RJz+?4=%q#&mN
z*;P|Wx8WRn^8i{CODl$_CUA8C`%eJ-B}WQo@#TZhV!h#%ide1@v8>r_wwVpiUaFYI
zU5w-5aJY>P?oz)Ye<TuVXM{UfuHFKcY4^Q6952Et9YUYwxVST*hv7uW&=LS&Fv8h0
zh-JD6W7EM1XYWD4y@#IB!8xqxcva`1MsVWI>_S5odont~DW5b9z#c|8+f{?+D{{6q
zgcJRQM$0ZwP2of<Wse74;pBLL-rX>JmhLkr#${7N7L0Iq$O3v>BIu+)oYJO5)hOX4
zswQDW)|r#N7rkaVY2a+XQ`|Dge;*Z`$R7*_pRmG7ZlaSFE+^R~RyfHn&9K6W)m#mQ
zLamH&qU}^F^@<fv_MMLv?nL4&tZ))%nWKe+pZSFr4q9hkmfxA-@|SQH;j%0+!<`y9
z-Ipb`K`}>xImC_oWgKVo%X5>ZWd2#D4Kq*&h^Rw*)InM5a5`-wgf@l6n|x$X8*?W7
znXhWdUfZI)WW#<viuPg~?Uh8@%cS--V5!(L7r4#Udv6pjePAq_pe=WyEmYzxF=H+c
zq%7+^Q|H)3)mG7zQrD>n9$=rCir}x>7htx=nA#T{I~z}6Y^qt~3Abj-*)jz0{jRhO
zaU+H=onA0by58)i279Tfl7Qdv{t+6fTbrJTNYyHs9m$WWl4qYM8Z1?M<w)hf_Di+K
mQWkH}bFHzeY-*-Wle2&Eg>ctjfTPX;0000<MNUMnLSTZ9IekU|
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..edecb6320de52da7e822c84484454fce5ed41a59
GIT binary patch
literal 2323
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..44919451ae0da8733be1fc6d32da918386b09b2f
GIT binary patch
literal 1016
zc$@+F0|)$xP)<h;3K|Lk000e1NJLTq002_}004#v1^@s6p+UBs000BONkl<Zc-rlq
zO>0v@6o#)>7b*yT)gK^!{0vcx_<^7sDJXOySnW#cP76VFBi5o+F<=!-(|i!FLO?_p
z5tVL4sg_c0HB#I9H?HT_6l<|2P2L-m%ro$CLzWM7@0>YvX2$b=wLkzZZ0U6RN0m&a
zQmF}hj%G5Myghwm!2Y{xoVWju7`yZN{2FBHm^PjpeMWmWo81`%!760x7&H2<2cPhL
ze+x2o%o<tyBy<?tkf~$Fdh0`z+GeyMQ^z}_YiMX_BQix;Po1=9%)YIy$ka*wYR?{f
z{Wl|1$0wsR9*?g@rj8NorTdVn<<5VPRhvj=$hdJBnc6|BcW`iU12RR}cl1>_|3{{d
zFr#%8nL6f-?wVw%9FV!dt;l0ihh&DNBORC=lNk<7xyX_xuE{J4eHw{S7iAWOJ~7rI
zQy1K)q=S;nGK=)f!X{+Sa{-ycz&>2xN2YLDr0TgmBL7T|<Z`+7$kg@F>&Vm!J%mhQ
z*-k~PpNLzQ+sG7>OeXgtQ^%VXO*au%axgkuhQ<JyWmb+P5{XU7)CKdGkg4NKi2__?
zu8_;f)baTrOC89p;M;i)nL3$oW3kw3Wa?%``;n;&;_o9<$M?Tvl#p4)xAQbIbuu%^
z6z-r~Qa_K(DtqT~WD0k8AXCT3MP)U}6vUi6kg1~`nZo@>$kg!+nK}x^Q*n?fdewI!
zQ^!GM>U!oGWa_wrOl`6lnIf{t)MbzI$kZ{qATvNl^@Ux?6rQ$#Od-fbCa<|O0}!E+
zFf>9YK|9k)5*<Jaj^r@Q7W7OO)I@w^sh1*zy5uG@Dcqu@u$dX7*p)JDHV8EJ)|KJm
z;jPGIQx)6&*oX=x8DNVvoA)_ZqM2oK;E8A+KFLu$IyfXs1jm=vs8=F$C52fW`KY6l
z!$>uhdrU4e%b4wOfU^jW7FVtBaOk~mw!?J{B5rU|h$fN26*j6w2A3;on3G(PjL3Pq
zxsXl+S0#!_bBU*B<mP%=kw`8+7K!9aZdHvCm&J>+K+?g+QJHhbMOpacu*@lYvyXYT
zYE3Nib#eEYhs^4d7QK-UG>*s|mn1A)muV93E~zs|W(ABG2fTV{ja+FF76?QhJ2tt@
zg3(ja>LD_JFDuwHX5Yo_UcI&km`}gAXIEs&2?u1(7>`V3o6+JmN~<G*vxaZ-I!Y9l
zB6GPQ+qh@)PWryz>NR?+p}1+|h0$l63fHJ>lF4Z>nFSkZC#-jUu-`9@$HoKWS~zfo
m(>oKlr>^3`2wM;#&a|IyDyd~yx!bb<0000<MNUMnLSTX?cij8{
--- a/mobile/android/base/resources/values-large-land-v11/styles.xml
+++ b/mobile/android/base/resources/values-large-land-v11/styles.xml
@@ -23,26 +23,24 @@
     <style name="Widget.BookmarksListView" parent="Widget.HomeListView">
         <item name="android:paddingTop">30dp</item>
         <item name="android:paddingLeft">120dp</item>
         <item name="android:paddingRight">120dp</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
         <item name="topDivider">true</item>
     </style>
 
-    <style name="Widget.HomeGridView" parent="Widget.GridView">
+    <style name="Widget.TopSitesGridView" parent="Widget.GridView">
         <item name="android:paddingLeft">55dp</item>
         <item name="android:paddingRight">55dp</item>
         <item name="android:paddingBottom">30dp</item>
         <item name="android:horizontalSpacing">20dp</item>
         <item name="android:verticalSpacing">20dp</item>
     </style>
 
-    <style name="Widget.TopSitesGridView" parent="Widget.HomeGridView" />
-
     <style name="Widget.Home.HistoryListView">
         <item name="android:paddingLeft">50dp</item>
         <item name="android:paddingRight">100dp</item>
         <item name="android:paddingTop">30dp</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
         <item name="topDivider">true</item>
     </style>
 
--- a/mobile/android/base/resources/values-large-v11/styles.xml
+++ b/mobile/android/base/resources/values-large-v11/styles.xml
@@ -72,26 +72,24 @@
     <style name="Widget.BookmarksListView" parent="Widget.HomeListView">
         <item name="android:paddingTop">30dp</item>
         <item name="android:paddingLeft">32dp</item>
         <item name="android:paddingRight">32dp</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
         <item name="topDivider">true</item>
     </style>
 
-    <style name="Widget.HomeGridView" parent="Widget.GridView">
+    <style name="Widget.TopSitesGridView" parent="Widget.GridView">
         <item name="android:paddingLeft">5dp</item>
         <item name="android:paddingRight">5dp</item>
         <item name="android:paddingBottom">30dp</item>
         <item name="android:horizontalSpacing">10dp</item>
         <item name="android:verticalSpacing">10dp</item>
     </style>
 
-    <style name="Widget.TopSitesGridView" parent="Widget.HomeGridView" />
-
     <style name="Widget.TopSitesListView" parent="Widget.BookmarksListView">
         <item name="topDivider">false</item>
     </style>
 
     <style name="Widget.ReadingListView" parent="Widget.BookmarksListView"/>
 
     <style name="Widget.Home.HistoryPanelTitle" parent="Widget.Home.HistoryTabIndicator">
         <item name="android:layout_marginLeft">32dp</item>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/values-v19/styles.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <style name="ToastMessage">
+        <item name="android:textSize">16sp</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:shadowColor">#BB000000</item>
+        <item name="android:shadowRadius">2.75</item>
+        <item name="android:layout_width">0dp</item>
+        <item name="android:layout_weight">1</item>
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_gravity">center_vertical</item>
+        <item name="android:paddingLeft">@dimen/toast_button_padding</item>
+        <item name="android:layout_marginLeft">8dp</item>
+    </style>
+
+    <style name="ToastButton">
+        <item name="android:background">@drawable/toast_button</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+        <item name="android:textColor">#ffffff</item>
+        <item name="android:shadowColor">#BB000000</item>
+        <item name="android:shadowRadius">2.75</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">match_parent</item>
+        <item name="android:paddingLeft">16dp</item>
+        <item name="android:maxWidth">160dp</item>
+        <item name="android:layout_gravity">center_vertical</item>
+    </style>
+
+</resources>
--- a/mobile/android/base/resources/values-xlarge-land-v11/styles.xml
+++ b/mobile/android/base/resources/values-xlarge-land-v11/styles.xml
@@ -1,25 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <resources>
 
-    <style name="Widget.HomeGridView" parent="Widget.GridView">
+    <style name="Widget.TopSitesGridView" parent="Widget.GridView">
         <item name="android:paddingLeft">55dp</item>
         <item name="android:paddingRight">55dp</item>
         <item name="android:paddingBottom">30dp</item>
         <item name="android:horizontalSpacing">56dp</item>
         <item name="android:verticalSpacing">20dp</item>
     </style>
 
-    <style name="Widget.TopSitesGridView" parent="Widget.HomeGridView" />
-
     <style name="Widget.Home.HistoryListView">
         <item name="android:paddingLeft">50dp</item>
         <item name="android:paddingRight">100dp</item>
         <item name="android:paddingTop">30dp</item>
         <item name="android:scrollbarStyle">outsideOverlay</item>
         <item name="topDivider">true</item>
     </style>
 
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -30,19 +30,16 @@
         <attr name="menuItemShareActionButtonStyle" format="reference"/>
 
         <!-- Default style for the BookmarksListView -->
         <attr name="bookmarksListViewStyle" format="reference" />
 
         <!-- Default style for the TopSitesGridItemView -->
         <attr name="topSitesGridItemViewStyle" format="reference" />
 
-        <!-- Default style for the HomeGridView -->
-        <attr name="homeGridViewStyle" format="reference" />
-
         <!-- Style for the PanelGridView -->
         <attr name="panelGridViewStyle" format="reference" />
 
         <!-- Default style for the TopSitesGridView -->
         <attr name="topSitesGridViewStyle" format="reference" />
 
         <!-- Default style for the TopSitesThumbnailView -->
         <attr name="topSitesThumbnailViewStyle" format="reference" />
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -140,40 +140,39 @@
 
     <style name="Widget.PanelItemView.Description">
         <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
         <item name="android:includeFontPadding">false</item>
         <item name="android:maxLines">2</item>
         <item name="android:ellipsize">end</item>
     </style>
 
-    <style name="Widget.HomeGridView" parent="Widget.GridView">
+    <style name="Widget.TopSitesGridView" parent="Widget.GridView">
         <item name="android:padding">7dp</item>
         <item name="android:horizontalSpacing">0dp</item>
         <item name="android:verticalSpacing">7dp</item>
     </style>
 
-    <style name="Widget.TopSitesGridView" parent="Widget.HomeGridView" />
-
     <style name="Widget.TopSitesGridItemView">
       <item name="android:layout_width">fill_parent</item>
       <item name="android:layout_height">fill_parent</item>
       <item name="android:padding">5dip</item>
       <item name="android:orientation">vertical</item>
     </style>
 
     <style name="Widget.PanelGridView" parent="Widget.GridView">
         <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">fill_parent</item>
         <item name="android:paddingTop">0dp</item>
         <item name="android:stretchMode">columnWidth</item>
         <item name="android:numColumns">auto_fit</item>
         <item name="android:columnWidth">@dimen/panel_grid_view_column_width</item>
         <item name="android:horizontalSpacing">2dp</item>
         <item name="android:verticalSpacing">2dp</item>
+        <item name="android:drawSelectorOnTop">true</item>
     </style>
 
     <style name="Widget.BookmarkItemView" parent="Widget.TwoLineRow"/>
 
     <style name="Widget.BookmarksListView" parent="Widget.HomeListView"/>
 
     <style name="Widget.TopSitesThumbnailView">
       <item name="android:padding">0dip</item>
--- a/mobile/android/chrome/content/SelectionHandler.js
+++ b/mobile/android/chrome/content/SelectionHandler.js
@@ -53,34 +53,48 @@ var SelectionHandler = {
   _addObservers: function sh_addObservers() {
     Services.obs.addObserver(this, "Gesture:SingleTap", false);
     Services.obs.addObserver(this, "Tab:Selected", false);
     Services.obs.addObserver(this, "after-viewport-change", false);
     Services.obs.addObserver(this, "TextSelection:Move", false);
     Services.obs.addObserver(this, "TextSelection:Position", false);
     Services.obs.addObserver(this, "TextSelection:End", false);
     Services.obs.addObserver(this, "TextSelection:Action", false);
-    BrowserApp.deck.addEventListener("compositionend", this, false);
+
+    BrowserApp.deck.addEventListener("pagehide", this, false);
+    BrowserApp.deck.addEventListener("blur", this, true);
   },
 
   _removeObservers: function sh_removeObservers() {
     Services.obs.removeObserver(this, "Gesture:SingleTap");
     Services.obs.removeObserver(this, "Tab:Selected");
     Services.obs.removeObserver(this, "after-viewport-change");
     Services.obs.removeObserver(this, "TextSelection:Move");
     Services.obs.removeObserver(this, "TextSelection:Position");
     Services.obs.removeObserver(this, "TextSelection:End");
     Services.obs.removeObserver(this, "TextSelection:Action");
-    BrowserApp.deck.removeEventListener("compositionend", this);
+
+    BrowserApp.deck.removeEventListener("pagehide", this);
+    BrowserApp.deck.removeEventListener("blur", this);
   },
 
   observe: function sh_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
+      // Update caret position on keyboard activity
+      case "TextSelection:UpdateCaretPos":
+        // Generated by IME close, autoCorrection / styling
+        this._positionHandles();
+        break;
+
       case "Gesture:SingleTap": {
-        if (this._activeType == this.TYPE_CURSOR) {
+        if (this._activeType == this.TYPE_SELECTION) {
+          let data = JSON.parse(aData);
+          if (!this._pointInSelection(data.x, data.y))
+            this._closeSelection();
+        } else if (this._activeType == this.TYPE_CURSOR) {
           // attachCaret() is called in the "Gesture:SingleTap" handler in BrowserEventHandler
           // We're guaranteed to call this first, because this observer was added last
           this._deactivate();
         }
         break;
       }
       case "Tab:Selected":
       case "TextSelection:End":
@@ -166,26 +180,28 @@ var SelectionHandler = {
         });
         break;
     }
   },
 
   handleEvent: function sh_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "pagehide":
-      // We only add keydown and blur listeners for TYPE_CURSOR
-      case "keydown":
       case "blur":
         this._closeSelection();
         break;
 
+      // Update caret position on keyboard activity
+      case "keyup":
+        // Not generated by Swiftkeyboard
+      case "compositionupdate":
       case "compositionend":
-        // compositionend messages normally terminate caret display
-        if (this._activeType == this.TYPE_CURSOR && !this._ignoreCompositionChanges) {
-          this._deactivate();
+        // Generated by SwiftKeyboard, et. al.
+        if (!this._ignoreCompositionChanges) {
+          this._positionHandles();
         }
         break;
     }
   },
 
   /** Returns true if the provided element can be selected in text selection, false otherwise. */
   canSelect: function sh_canSelect(aElement) {
     return !(aElement instanceof Ci.nsIDOMHTMLButtonElement ||
@@ -488,38 +504,46 @@ var SelectionHandler = {
    */
   attachCaret: function sh_attachCaret(aElement) {
     // See if its an input element, and it isn't disabled, nor handled by Android native dialog
     if (aElement.disabled ||
         InputWidgetHelper.hasInputWidget(aElement) ||
         !((aElement instanceof HTMLInputElement && aElement.mozIsTextField(false)) ||
           (aElement instanceof HTMLTextAreaElement)))
       return;
+
     this._initTargetInfo(aElement);
 
-    this._contentWindow.addEventListener("keydown", this, false);
-    this._contentWindow.addEventListener("blur", this, true);
+    // Caret-specific observer/listeners
+    Services.obs.addObserver(this, "TextSelection:UpdateCaretPos", false);
+    BrowserApp.deck.addEventListener("keyup", this, false);
+    BrowserApp.deck.addEventListener("compositionupdate", this, false);
+    BrowserApp.deck.addEventListener("compositionend", this, false);
 
     this._activeType = this.TYPE_CURSOR;
     this._positionHandles();
 
     this._sendMessage("TextSelection:ShowHandles", [this.HANDLE_TYPE_MIDDLE]);
   },
 
+  // Target initialization for both TYPE_CURSOR and TYPE_SELECTION
   _initTargetInfo: function sh_initTargetInfo(aElement) {
     this._targetElement = aElement;
     if (aElement instanceof Ci.nsIDOMNSEditableElement) {
+      // Blur the targetElement to force IME code to undo previous style compositions
+      // (visible underlines / etc generated by autoCorrection, autoSuggestion)
+      aElement.blur();
+      // Ensure targetElement is now focused normally
       aElement.focus();
     }
 
     this._contentWindow = aElement.ownerDocument.defaultView;
     this._isRTL = (this._contentWindow.getComputedStyle(aElement, "").direction == "rtl");
 
     this._addObservers();
-    this._contentWindow.addEventListener("pagehide", this, false);
   },
 
   _getSelection: function sh_getSelection() {
     if (this._targetElement instanceof Ci.nsIDOMNSEditableElement)
       return this._targetElement.QueryInterface(Ci.nsIDOMNSEditableElement).editor.selection;
     else
       return this._contentWindow.getSelection();
   },
@@ -740,30 +764,36 @@ var SelectionHandler = {
       // Clear selection without clearing the anchorNode or focusNode
       if (selection.rangeCount != 0) {
         selection.collapseToStart();
       }
     }
   },
 
   _deactivate: function sh_deactivate() {
-    this._activeType = this.TYPE_NONE;
-
     sendMessageToJava({ type: "TextSelection:HideHandles" });
 
     this._removeObservers();
-    this._contentWindow.removeEventListener("pagehide", this, false);
-    this._contentWindow.removeEventListener("keydown", this, false);
-    this._contentWindow.removeEventListener("blur", this, true);
+
+    // Only observed for caret positioning
+    if (this._activeType == this.TYPE_CURSOR) {
+      Services.obs.removeObserver(this, "TextSelection:UpdateCaretPos");
+      BrowserApp.deck.removeEventListener("keyup", this);
+      BrowserApp.deck.removeEventListener("compositionupdate", this);
+      BrowserApp.deck.removeEventListener("compositionend", this);
+    }
+
     this._contentWindow = null;
     this._targetElement = null;
     this._isRTL = false;
     this._cache = null;
     this._ignoreSelectionChanges = false;
     this._ignoreCompositionChanges = false;
+
+    this._activeType = this.TYPE_NONE;
   },
 
   _getViewOffset: function sh_getViewOffset() {
     let offset = { x: 0, y: 0 };
     let win = this._contentWindow;
 
     // Recursively look through frames to compute the total position offset.
     while (win.frameElement) {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -567,17 +567,17 @@ var BrowserApp = {
         let url = NativeWindow.contextmenus._getLinkURL(aTarget);
         sendMessageToJava({
           type: "Contact:Add",
           phone: url
         });
       });
 
     NativeWindow.contextmenus.add(Strings.browser.GetStringFromName("contextmenu.bookmarkLink"),
-      NativeWindow.contextmenus.linkBookmarkableContext,
+      NativeWindow.contextmenus._disableInGuest(NativeWindow.contextmenus.linkBookmarkableContext),
       function(aTarget) {
         let url = NativeWindow.contextmenus._getLinkURL(aTarget);
         let title = aTarget.textContent || aTarget.title || url;
         sendMessageToJava({
           type: "Bookmark:Insert",
           url: url,
           title: title
         });
--- a/mobile/android/components/PromptService.js
+++ b/mobile/android/components/PromptService.js
@@ -134,16 +134,32 @@ InternalPrompt.prototype = {
         label: PromptUtils.cleanUpLabel(aCheckMsg),
         checked: aCheckState.value
       });
     }
 
     return aPrompt;
   },
 
+  addTextbox: function(prompt, value, autofocus, hint) {
+    prompt.addTextbox({
+      value: (value !== null) ? value : "",
+      autofocus: autofocus,
+      hint: hint
+    });
+  },
+
+  addPassword: function(prompt, value, autofocus, hint) {
+    prompt.addPassword({
+      value: (value !== null) ? value : "",
+      autofocus: autofocus,
+      hint: hint
+    });
+  },
+
   /* Shows a native prompt, and then spins the event loop for this thread while we wait
    * for a response
    */
   showPrompt: function showPrompt(aPrompt) {
     if (this._domWin) {
       PromptUtils.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog");
       let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
       winUtils.enterModalState();
@@ -283,61 +299,48 @@ InternalPrompt.prototype = {
     if (aCheckState && data.button > -1)
       aCheckState.value = data.checkbox0 == "true";
     return data.button;
   },
 
   nsIPrompt_prompt: function nsIPrompt_prompt(aTitle, aText, aValue, aCheckMsg, aCheckState) {
     let p = this._getPrompt(aTitle, aText, null, aCheckMsg, aCheckState);
     p.setHint("prompt");
-    p.addTextbox({
-      value: aValue.value,
-      autofocus: true
-    });
+    this.addTextbox(p, aValue.value, true);
     this.addCheckbox(p, aCheckMsg, aCheckState);
     let data = this.showPrompt(p);
 
     let ok = data.button == 0;
     if (aCheckState && data.button > -1)
       aCheckState.value = data.checkbox0 == "true";
     if (ok)
       aValue.value = data.textbox0;
     return ok;
   },
 
   nsIPrompt_promptPassword: function nsIPrompt_promptPassword(
       aTitle, aText, aPassword, aCheckMsg, aCheckState) {
     let p = this._getPrompt(aTitle, aText, null);
-    p.addPassword({
-      value: aPassword.value || "",
-      autofocus: true,
-      hint: PromptUtils.getLocaleString("password", "passwdmgr")
-    });
+    this.addPassword(p, aPassword.value, true, PromptUtils.getLocaleString("password", "passwdmgr"));
     this.addCheckbox(p, aCheckMsg, aCheckState);
     let data = this.showPrompt(p);
 
     let ok = data.button == 0;
     if (aCheckState && data.button > -1)
       aCheckState.value = data.checkbox0 == "true";
     if (ok)
       aPassword.value = data.password0;
     return ok;
   },
 
   nsIPrompt_promptUsernameAndPassword: function nsIPrompt_promptUsernameAndPassword(
       aTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) {
     let p = this._getPrompt(aTitle, aText, null);
-    p.addTextbox({
-      value: aUsername.value,
-      autofocus: true,
-      hint: PromptUtils.getLocaleString("username", "passwdmgr")
-    }).addPassword({
-      value: aPassword.value,
-      hint: PromptUtils.getLocaleString("password", "passwdmgr")
-    });
+    this.addTextbox(p, aUsername.value, true, PromptUtils.getLocaleString("username", "passwdmgr"));
+    this.addPassword(p, aPassword.value, true, PromptUtils.getLocaleString("password", "passwdmgr"));
     this.addCheckbox(p, aCheckMsg, aCheckState);
     let data = this.showPrompt(p);
 
     let ok = data.button == 0;
     if (aCheckState && data.button > -1)
       aCheckState.value = data.checkbox0 == "true";
     if (ok) {
       aUsername.value = data.textbox0;
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -123,16 +123,17 @@
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_base.xpt
 @BINPATH@/components/content_events.xpt
 @BINPATH@/components/content_canvas.xpt
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
+@BINPATH@/components/content_webrtc.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
 @BINPATH@/components/dom_apps.xpt
 @BINPATH@/components/dom_base.xpt
 @BINPATH@/components/dom_canvas.xpt
--- a/toolkit/devtools/Loader.jsm
+++ b/toolkit/devtools/Loader.jsm
@@ -62,16 +62,17 @@ BuiltinProvider.prototype = {
         "devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
         "devtools/app-actor-front": "resource://gre/modules/devtools/app-actor-front.js",
         "devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
         "devtools/css-color": "resource://gre/modules/devtools/css-color",
         "devtools/output-parser": "resource://gre/modules/devtools/output-parser",
         "devtools/touch-events": "resource://gre/modules/devtools/touch-events",
         "devtools/client": "resource://gre/modules/devtools/client",
         "devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js",
+        "devtools/async-utils": "resource://gre/modules/devtools/async-utils",
 
         "acorn": "resource://gre/modules/devtools/acorn",
         "acorn/util/walk": "resource://gre/modules/devtools/acorn/walk.js",
 
         // Allow access to xpcshell test items from the loader.
         "xpcshell-test": "resource://test"
       },
       globals: loaderGlobals,
@@ -109,16 +110,17 @@ SrcdirProvider.prototype = {
     let webconsoleURI = this.fileURI(OS.Path.join(toolkitDir, "webconsole"));
     let appActorURI = this.fileURI(OS.Path.join(toolkitDir, "apps", "app-actor-front.js"));
     let cssLogicURI = this.fileURI(OS.Path.join(toolkitDir, "styleinspector", "css-logic"));
     let cssColorURI = this.fileURI(OS.Path.join(toolkitDir, "css-color"));
     let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser"));
     let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events"));
     let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client"));
     let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js");
+    let asyncUtilsURI = this.fileURI(OS.Path.join(toolkitDir), "async-utils.js");
     let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn"));
     let acornWalkURI = OS.Path.join(acornURI, "walk.js");
     this.loader = new loader.Loader({
       modules: {
         "toolkit/loader": loader,
         "source-map": SourceMap,
       },
       paths: {
@@ -129,16 +131,17 @@ SrcdirProvider.prototype = {
         "devtools/toolkit/webconsole": webconsoleURI,
         "devtools/app-actor-front": appActorURI,
         "devtools/styleinspector/css-logic": cssLogicURI,
         "devtools/css-color": cssColorURI,
         "devtools/output-parser": outputParserURI,
         "devtools/touch-events": touchEventsURI,
         "devtools/client": clientURI,
         "devtools/pretty-fast": prettyFastURI,
+        "devtools/async-utils": asyncUtilsURI,
 
         "acorn": acornURI,
         "acorn/util/walk": acornWalkURI
       },
       globals: loaderGlobals,
       invisibleToDebugger: this.invisibleToDebugger
     });
 
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/async-utils.js
@@ -0,0 +1,100 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+/**
+ * Helpers for async functions. Async functions are generator functions that are
+ * run by Tasks. An async function returns a Promise for the resolution of the
+ * function. When the function returns, the promise is resolved with the
+ * returned value. If it throws the promise rejects with the thrown error.
+ *
+ * See Task documentation at https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Task.jsm.
+ */
+
+let {Cu} = require("chrome");
+let {Task} = require("resource://gre/modules/Task.jsm");
+let {Promise} = require("resource://gre/modules/Promise.jsm");
+
+/**
+ * Create an async function from a generator function.
+ *
+ * @param Function func
+ *        The generator function that to wrap as an async function.
+ * @return Function
+ *         The async function.
+ */
+exports.async = function async(func) {
+  return function(...args) {
+    return Task.spawn(func.apply(this, args));
+  };
+};
+
+/**
+ * Create an async function that only executes once per instance of an object.
+ * Once called on a given object, the same promise will be returned for any
+ * future calls for that object.
+ *
+ * @param Function func
+ *        The generator function that to wrap as an async function.
+ * @return Function
+ *         The async function.
+ */
+exports.asyncOnce = function asyncOnce(func) {
+  const promises = new WeakMap();
+  return function(...args) {
+    let promise = promises.get(this);
+    if (!promise) {
+      promise = Task.spawn(func.apply(this, args));
+      promises.set(this, promise);
+    }
+    return promise;
+  };
+};
+
+
+/**
+ * Call a function that expects a callback as the last argument and returns a
+ * promise for the result. This simplifies using callback APIs from tasks and
+ * async functions.
+ *
+ * @param Any obj
+ *        The |this| value to call the function on.
+ * @param Function func
+ *        The callback-expecting function to call.
+ * @param Array args
+ *        Additional arguments to pass to the method.
+ * @return Promise
+ *         The promise for the result. If the callback is called with only one
+ *         argument, it is used as the resolution value. If there's multiple
+ *         arguments, an array containing the arguments is the resolution value.
+ *         If the method throws, the promise is rejected with the thrown value.
+ */
+function promisify(obj, func, args) {
+  return new Promise(resolve => {
+    args.push((...results) => {
+      resolve(results.length > 1 ? results : results[0]);
+    });
+    func.apply(obj, args);
+  });
+}
+
+/**
+ * Call a method that expects a callback as the last argument and returns a
+ * promise for the result.
+ *
+ * @see promisify
+ */
+exports.promiseInvoke = function promiseInvoke(obj, func, ...args) {
+  return promisify(obj, func, args);
+};
+
+/**
+ * Call a function that expects a callback as the last argument.
+ *
+ * @see promisify
+ */
+exports.promiseCall = function promiseCall(func, ...args) {
+  return promisify(undefined, func, args);
+};
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/tests/unit/test_async-utils.js
@@ -0,0 +1,153 @@
+/* -*- Mode: js; js-indent-level: 2; -*- */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test async-utils.js
+
+const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
+const {Promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
+const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
+const {async, asyncOnce, promiseInvoke, promiseCall} = require("devtools/async-utils");
+
+function run_test() {
+  do_test_pending();
+  Task.spawn(function*() {
+    for (let helper of [async, asyncOnce]) {
+      yield test_async_args(helper);
+      yield test_async_return(helper);
+      yield test_async_throw(helper);
+    }
+    yield test_async_once();
+    yield test_async_invoke();
+    do_test_finished();
+  }).then(null, error => {
+    do_throw(error);
+  });
+}
+
+// Test that arguments are correctly passed through to the async function.
+function test_async_args(async) {
+  let obj = {
+    method: async(function*(a, b) {
+      do_check_eq(this, obj);
+      do_check_eq(a, "foo");
+      do_check_eq(b, "bar");
+    })
+  };
+
+  return obj.method("foo", "bar");
+}
+
+// Test that the return value from the async function is resolution value of
+// the promise.
+function test_async_return(async) {
+  let obj = {
+    method: async(function*(a, b) {
+      return a + b;
+    })
+  };
+
+  return obj.method("foo", "bar").then(ret => {
+    do_check_eq(ret, "foobar");
+  });
+}
+
+// Test that the throwing from an async function rejects the promise.
+function test_async_throw(async) {
+  let obj = {
+    method: async(function*() {
+      throw "boom";
+    })
+  };
+
+  return obj.method().then(null, error => {
+    do_check_eq(error, "boom");
+  });
+}
+
+// Test that asyncOnce only runs the async function once per instance and
+// returns the same promise for that instance.
+function test_async_once() {
+  let counter = 0;
+
+  function Foo() {}
+  Foo.prototype = {
+    ran: false,
+    method: asyncOnce(function*() {
+      yield Promise.resolve();
+      if (this.ran) {
+        do_throw("asyncOnce function unexpectedly ran twice on the same object");
+      }
+      this.ran = true;
+      return counter++;
+    })
+  };
+
+  let foo1 = new Foo();
+  let foo2 = new Foo();
+  let p1 = foo1.method();
+  let p2 = foo2.method();
+
+  do_check_neq(p1, p2);
+
+  let p3 = foo1.method();
+  do_check_eq(p1, p3);
+  do_check_false(foo1.ran);
+
+  let p4 = foo2.method();
+  do_check_eq(p2, p4);
+  do_check_false(foo2.ran);
+
+  return p1.then(ret => {
+    do_check_true(foo1.ran);
+    do_check_eq(ret, 0);
+    return p2;
+  }).then(ret => {
+    do_check_true(foo2.ran);
+    do_check_eq(ret, 1);
+  });
+}
+
+// Test invoke and call.
+function test_async_invoke() {
+  return Task.spawn(function*() {
+    function func(a, b, expectedThis, callback) {
+      "use strict";
+      do_check_eq(a, "foo");
+      do_check_eq(b, "bar");
+      do_check_eq(this, expectedThis);
+      callback(a + b);
+    }
+
+    // Test call.
+    let callResult = yield promiseCall(func, "foo", "bar", undefined);
+    do_check_eq(callResult, "foobar");
+
+
+    // Test invoke.
+    let obj = { method: func };
+    let invokeResult = yield promiseInvoke(obj, obj.method, "foo", "bar", obj);
+    do_check_eq(invokeResult, "foobar");
+
+
+    // Test passing multiple values to the callback.
+    function multipleResults(callback) {
+      callback("foo", "bar");
+    }
+
+    let results = yield promiseCall(multipleResults);
+    do_check_eq(results.length, 2);
+    do_check_eq(results[0], "foo");
+    do_check_eq(results[1], "bar");
+
+
+    // Test throwing from the function.
+    function thrower() {
+      throw "boom";
+    }
+
+    yield promiseCall(thrower).then(null, error => {
+      do_check_eq(error, "boom");
+    });
+  });
+}
--- a/toolkit/devtools/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/tests/unit/xpcshell.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 head = head_devtools.js
 tail =
 
 [test_independent_loaders.js]
 [test_invisible_loader.js]
 [test_safeErrorString.js]
 [test_defineLazyPrototypeGetter.js]
+[test_async-utils.js]
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1955,16 +1955,23 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *
             }
 
             selEvent.mOffset = std::min(start, end);
             selEvent.mLength = std::max(start, end) - selEvent.mOffset;
             selEvent.mReversed = start > end;
             selEvent.mExpandToClusterBoundary = false;
 
             DispatchEvent(&selEvent);
+
+            // Notify SelectionHandler of final caret position
+            // Required after IME hide via 'Back' button
+            AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent(
+                NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"),
+                NS_LITERAL_CSTRING(""));
+            nsAppShell::gAppShell->PostEvent(broadcastEvent);
         }
         break;
     case AndroidGeckoEvent::IME_ADD_COMPOSITION_RANGE:
         {
             TextRange range;
             range.mStartOffset = ae->Start();
             range.mEndOffset = ae->End();
             range.mRangeType = ae->RangeType();
@@ -2042,16 +2049,23 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *
             const NS_ConvertUTF16toUTF8 theText8(event.theText);
             const char* text = theText8.get();
             ALOGIME("IME: IME_SET_TEXT: text=\"%s\", length=%u, range=%u",
                     text, event.theText.Length(), mIMERanges.Length());
 #endif // DEBUG_ANDROID_IME
 
             DispatchEvent(&event);
             mIMERanges.Clear();
+
+            // Notify SelectionHandler of final caret position
+            // Required in cases of keyboards providing autoCorrections
+            AndroidGeckoEvent* broadcastEvent = AndroidGeckoEvent::MakeBroadcastEvent(
+                NS_LITERAL_CSTRING("TextSelection:UpdateCaretPos"),
+                NS_LITERAL_CSTRING(""));
+            nsAppShell::gAppShell->PostEvent(broadcastEvent);
         }
         break;
     case AndroidGeckoEvent::IME_REMOVE_COMPOSITION:
         {
             /*
              *  Remove any previous composition.  This is only used for
              *    visual indication and does not affect the text content.
              *