Bug 1249201 Part 2 - Show carets continuously when panning or zooming. r=mats,sebastian
authorTing-Yu Lin <tlin@mozilla.com>
Thu, 21 Apr 2016 16:53:40 +0800
changeset 332407 989e882615274ea8b22570a53a404244ab46467e
parent 332406 533b9287d572d9541ae5a03e8d1331bd1794d26b
child 332408 642e7a61200e8a38781bb54e743474a7686c4bd1
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats, sebastian
bugs1249201
milestone48.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
Bug 1249201 Part 2 - Show carets continuously when panning or zooming. r=mats,sebastian Add a pref "layout.accessiblecaret.always_show_when_scrolling" defaults to true on all platforms except b2g. When it is set to false, the carets will be hidden during scrolling, which is the current behavior before applying this change. The pref "layout.accessiblecaret.extendedvisibility" was added for Fennec to keep ActionBar open when carets temporarily hiding during panning or zooming. Now we make carets always show by default, so the pref can be removed. However, the floating toolbar still need to be notified when the scrolling begins, so we dispatch "scroll" instead. In gtest, the preference changes were in the middle of the test function. To make the preference change clearer, I add new pref changes or move the existing ones to the beginning of the test functions. The 250ms transition effect added in ua.css is per request of UX designer in bug 1249201 comment 12. MozReview-Commit-ID: 8NGvDLPbtNY
b2g/app/b2g.js
layout/base/AccessibleCaretManager.cpp
layout/base/AccessibleCaretManager.h
layout/base/gtest/TestAccessibleCaretManager.cpp
layout/style/res/ua.css
mobile/android/app/mobile.js
mobile/android/chrome/content/ActionBarHandler.js
modules/libpref/init/all.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1015,16 +1015,19 @@ pref("layout.accessiblecaret.enabled", t
 // by the spec in bug 921965.
 pref("layout.accessiblecaret.bar.enabled", true);
 
 // APZ on real devices supports long tap events.
 #ifdef MOZ_WIDGET_GONK
 pref("layout.accessiblecaret.use_long_tap_injector", false);
 #endif
 
+// Hide carets and text selection dialog during scrolling.
+pref("layout.accessiblecaret.always_show_when_scrolling", false);
+
 // Enable sync and mozId with Firefox Accounts.
 pref("services.sync.fxaccounts.enabled", true);
 pref("identity.fxaccounts.enabled", true);
 
 // Mobile Identity API.
 pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
 
 pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -67,19 +67,19 @@ std::ostream& operator<<(std::ostream& a
 }
 #undef AC_PROCESS_ENUM_TO_STREAM
 
 /*static*/ bool
 AccessibleCaretManager::sSelectionBarEnabled = false;
 /*static*/ bool
 AccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent = false;
 /*static*/ bool
-AccessibleCaretManager::sCaretsExtendedVisibility = false;
+AccessibleCaretManager::sCaretsAlwaysTilt = false;
 /*static*/ bool
-AccessibleCaretManager::sCaretsAlwaysTilt = false;
+AccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = true;
 /*static*/ bool
 AccessibleCaretManager::sCaretsScriptUpdates = false;
 /*static*/ bool
 AccessibleCaretManager::sCaretsAllowDraggingAcrossOtherCaret = true;
 /*static*/ bool
 AccessibleCaretManager::sHapticFeedback = false;
 /*static*/ bool
 AccessibleCaretManager::sExtendSelectionForPhoneNumber = false;
@@ -97,20 +97,20 @@ AccessibleCaretManager::AccessibleCaretM
   mCaretTimeoutTimer = do_CreateInstance("@mozilla.org/timer;1");
 
   static bool addedPrefs = false;
   if (!addedPrefs) {
     Preferences::AddBoolVarCache(&sSelectionBarEnabled,
                                  "layout.accessiblecaret.bar.enabled");
     Preferences::AddBoolVarCache(&sCaretShownWhenLongTappingOnEmptyContent,
       "layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content");
-    Preferences::AddBoolVarCache(&sCaretsExtendedVisibility,
-                                 "layout.accessiblecaret.extendedvisibility");
     Preferences::AddBoolVarCache(&sCaretsAlwaysTilt,
                                  "layout.accessiblecaret.always_tilt");
+    Preferences::AddBoolVarCache(&sCaretsAlwaysShowWhenScrolling,
+      "layout.accessiblecaret.always_show_when_scrolling", true);
     Preferences::AddBoolVarCache(&sCaretsScriptUpdates,
       "layout.accessiblecaret.allow_script_change_updates");
     Preferences::AddBoolVarCache(&sCaretsAllowDraggingAcrossOtherCaret,
       "layout.accessiblecaret.allow_dragging_across_other_caret", true);
     Preferences::AddBoolVarCache(&sHapticFeedback,
                                  "layout.accessiblecaret.hapticfeedback");
     Preferences::AddBoolVarCache(&sExtendSelectionForPhoneNumber,
       "layout.accessiblecaret.extend_selection_for_phone_number");
@@ -197,28 +197,16 @@ AccessibleCaretManager::HideCarets()
     mFirstCaret->SetAppearance(Appearance::None);
     mSecondCaret->SetAppearance(Appearance::None);
     DispatchCaretStateChangedEvent(CaretChangedReason::Visibilitychange);
     CancelCaretTimeoutTimer();
   }
 }
 
 void
-AccessibleCaretManager::DoNotShowCarets()
-{
-  if (mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible()) {
-    AC_LOG("%s", __FUNCTION__);
-    mFirstCaret->SetAppearance(Appearance::NormalNotShown);
-    mSecondCaret->SetAppearance(Appearance::NormalNotShown);
-    DispatchCaretStateChangedEvent(CaretChangedReason::Visibilitychange);
-    CancelCaretTimeoutTimer();
-  }
-}
-
-void
 AccessibleCaretManager::UpdateCarets(UpdateCaretsHint aHint)
 {
   FlushLayout();
   if (IsTerminated()) {
     return;
   }
 
   mLastUpdateCaretMode = GetCaretMode();
@@ -621,36 +609,44 @@ AccessibleCaretManager::SelectWordOrShor
   return rv;
 }
 
 void
 AccessibleCaretManager::OnScrollStart()
 {
   AC_LOG("%s", __FUNCTION__);
 
-  mFirstCaretAppearanceOnScrollStart = mFirstCaret->GetAppearance();
-  mSecondCaretAppearanceOnScrollStart = mSecondCaret->GetAppearance();
+  if (!sCaretsAlwaysShowWhenScrolling) {
+    // Backup the appearance so that we can restore them after the scrolling
+    // ends.
+    mFirstCaretAppearanceOnScrollStart = mFirstCaret->GetAppearance();
+    mSecondCaretAppearanceOnScrollStart = mSecondCaret->GetAppearance();
+    HideCarets();
+    return;
+  }
 
-  // Hide the carets. (Extended visibility makes them "NormalNotShown").
-  if (sCaretsExtendedVisibility) {
-    DoNotShowCarets();
-  } else {
-    HideCarets();
+  if (mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible()) {
+    // Dispatch the event only if one of the carets is logically visible like in
+    // HideCarets().
+    DispatchCaretStateChangedEvent(CaretChangedReason::Scroll);
   }
 }
 
 void
 AccessibleCaretManager::OnScrollEnd()
 {
   if (mLastUpdateCaretMode != GetCaretMode()) {
     return;
   }
 
-  mFirstCaret->SetAppearance(mFirstCaretAppearanceOnScrollStart);
-  mSecondCaret->SetAppearance(mSecondCaretAppearanceOnScrollStart);
+  if (!sCaretsAlwaysShowWhenScrolling) {
+    // Restore the appearance which is saved before the scrolling is started.
+    mFirstCaret->SetAppearance(mFirstCaretAppearanceOnScrollStart);
+    mSecondCaret->SetAppearance(mSecondCaretAppearanceOnScrollStart);
+  }
 
   if (GetCaretMode() == CaretMode::Cursor) {
     if (!mFirstCaret->IsLogicallyVisible()) {
       // If the caret is hidden (Appearance::None) due to timeout or blur, no
       // need to update it.
       return;
     }
   }
--- a/layout/base/AccessibleCaretManager.h
+++ b/layout/base/AccessibleCaretManager.h
@@ -130,20 +130,16 @@ protected:
   // Update carets based on current selection status. This function will flush
   // layout, so caller must ensure the PresShell is still valid after calling
   // this method.
   void UpdateCarets(UpdateCaretsHint aHint = UpdateCaretsHint::Default);
 
   // Force hiding all carets regardless of the current selection status.
   void HideCarets();
 
-  // Force carets to be "present" logically, but not visible. Allows ActionBar
-  // to stay open when carets visibility is supressed during scroll.
-  void DoNotShowCarets();
-
   void UpdateCaretsForCursorMode(UpdateCaretsHint aHint);
   void UpdateCaretsForSelectionMode(UpdateCaretsHint aHint);
 
   // Provide haptic / touch feedback, primarily for select on longpress.
   void ProvideHapticFeedback();
 
   // Get the nearest enclosing focusable frame of aFrame.
   // @return focusable frame if there is any; nullptr otherwise.
@@ -293,24 +289,25 @@ protected:
   static bool sExtendSelectionForPhoneNumber;
 
   // Preference to show caret in cursor mode when long tapping on an empty
   // content. This also changes the default update behavior in cursor mode,
   // which is based on the emptiness of the content, into something more
   // heuristic. See UpdateCaretsForCursorMode() for the details.
   static bool sCaretShownWhenLongTappingOnEmptyContent;
 
-  // Android specific visibility extensions correct compatibility issues
-  // with ActionBar visibility during page scroll.
-  static bool sCaretsExtendedVisibility;
-
   // Preference to make carets always tilt in selection mode. By default, the
   // carets become tilt only when they are overlapping.
   static bool sCaretsAlwaysTilt;
 
+  // Preference to allow carets always show when scrolling (either panning or
+  // zooming) the page. When set to false, carets will hide during scrolling,
+  // and show again after the user lifts the finger off the screen.
+  static bool sCaretsAlwaysShowWhenScrolling;
+
   // By default, javascript content selection changes closes AccessibleCarets and
   // UI interactions. Optionally, we can try to maintain the active UI, keeping
   // carets and ActionBar available.
   static bool sCaretsScriptUpdates;
 
   // Preference to allow one caret to be dragged across the other caret without
   // any limitation. When set to false, one caret cannot be dragged across the
   // other one.
--- a/layout/base/gtest/TestAccessibleCaretManager.cpp
+++ b/layout/base/gtest/TestAccessibleCaretManager.cpp
@@ -55,18 +55,18 @@ public:
 
   class MockAccessibleCaretManager : public AccessibleCaretManager
   {
   public:
     using CaretMode = AccessibleCaretManager::CaretMode;
     using AccessibleCaretManager::UpdateCarets;
     using AccessibleCaretManager::HideCarets;
     using AccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent;
-    using AccessibleCaretManager::sCaretsExtendedVisibility;
     using AccessibleCaretManager::sCaretsAlwaysTilt;
+    using AccessibleCaretManager::sCaretsAlwaysShowWhenScrolling;
 
     MockAccessibleCaretManager()
       : AccessibleCaretManager(nullptr)
     {
       mFirstCaret = MakeUnique<MockAccessibleCaret>();
       mSecondCaret = MakeUnique<MockAccessibleCaret>();
     }
 
@@ -345,16 +345,21 @@ TEST_F(AccessibleCaretManagerTester, Tes
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 
   mManager.OnScrollPositionChanged();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionMode)
 {
+  // Simulate B2G preference.
+  AutoRestore<bool> savesCaretsAlwaysShowWhenScrolling(
+    MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling);
+  MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Selection));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
     InSequence dummy;
 
     // Initially, first caret is out of scrollport, and second caret is visible.
@@ -417,111 +422,112 @@ TEST_F(AccessibleCaretManagerTester, Tes
   EXPECT_EQ(SecondCaretAppearance(), Appearance::None);
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
   check.Call("scrollend2");
 }
 
-TEST_F(AccessibleCaretManagerTester,
-       TestScrollInSelectionModeWithExtendedVisibilityAndAlwaysTilt)
+TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref)
 {
+  // Simulate Firefox Android preference.
+  AutoRestore<bool> saveCaretsAlwaysTilt(
+    MockAccessibleCaretManager::sCaretsAlwaysTilt);
+  MockAccessibleCaretManager::sCaretsAlwaysTilt = true;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Selection));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
     InSequence dummy;
 
     // Initially, first caret is out of scrollport, and second caret is visible.
     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
       .WillOnce(Return(PositionChangedResult::Invisible));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("updatecarets"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
-                  CaretChangedReason::Visibilitychange));
+                  CaretChangedReason::Scroll));
     EXPECT_CALL(check, Call("scrollstart1"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("reflow1"));
 
     // After scroll ended, first caret is visible and second caret is out of
     // scroll port.
     EXPECT_CALL(mManager.SecondCaret(), SetPosition(_, _))
       .WillOnce(Return(PositionChangedResult::Invisible));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("scrollend1"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
-                  CaretChangedReason::Visibilitychange));
+                  CaretChangedReason::Scroll));
     EXPECT_CALL(check, Call("scrollstart2"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("reflow2"));
 
     // After the scroll ended, both carets are visible.
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("scrollend2"));
   }
 
-  // Simulate Firefox Android preferences.
-  AutoRestore<bool> saveCaretsExtendedVisibility(
-    MockAccessibleCaretManager::sCaretsExtendedVisibility);
-  MockAccessibleCaretManager::sCaretsExtendedVisibility = true;
-  AutoRestore<bool> saveCaretsAlwaysTilt(
-    MockAccessibleCaretManager::sCaretsAlwaysTilt);
-  MockAccessibleCaretManager::sCaretsAlwaysTilt = true;
-
   mManager.UpdateCarets();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
   check.Call("updatecarets");
 
   mManager.OnScrollStart();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
-  EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
+  EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
   check.Call("scrollstart1");
 
   mManager.OnReflow();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
-  EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
+  EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
   check.Call("reflow1");
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
   check.Call("scrollend1");
 
   mManager.OnScrollStart();
-  EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
+  EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
   check.Call("scrollstart2");
 
   mManager.OnReflow();
-  EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
+  EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
   check.Call("reflow2");
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible)
 {
+  // Simulate B2G preference.
+  AutoRestore<bool> savesCaretsAlwaysShowWhenScrolling(
+    MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling);
+  MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
@@ -572,16 +578,21 @@ TEST_F(AccessibleCaretManagerTester, Tes
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden)
 {
+  // Simulate B2G preference.
+  AutoRestore<bool> savesCaretsAlwaysShowWhenScrolling(
+    MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling);
+  MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
@@ -626,16 +637,21 @@ TEST_F(AccessibleCaretManagerTester, Tes
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeOnEmptyContent)
 {
+  // Simulate B2G preference.
+  AutoRestore<bool> savesCaretsAlwaysShowWhenScrolling(
+    MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling);
+  MockAccessibleCaretManager::sCaretsAlwaysShowWhenScrolling = false;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(false));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
@@ -695,18 +711,23 @@ TEST_F(AccessibleCaretManagerTester, Tes
   mManager.OnScrollStart();
   check.Call("scrollstart3");
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
   check.Call("scrollend3");
 }
 
 TEST_F(AccessibleCaretManagerTester,
-       TestScrollInCursorModeOnEmptyContentWithSpecialPreference)
+       TestScrollInCursorModeWithCaretShownWhenLongTappingOnEmptyContentPref)
 {
+  // Simulate Firefox Android preference.
+  AutoRestore<bool> savesCaretShownWhenLongTappingOnEmptyContent(
+    MockAccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent);
+  MockAccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent = true;
+
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(false));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
@@ -716,46 +737,42 @@ TEST_F(AccessibleCaretManagerTester,
                    CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("singletap updatecarets"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("longtap updatecarets"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
-                  CaretChangedReason::Visibilitychange));
+                  CaretChangedReason::Scroll));
     EXPECT_CALL(check, Call("longtap scrollstart1"));
 
     EXPECT_CALL(mManager.FirstCaret(), SetPosition(_, _))
       .WillOnce(Return(PositionChangedResult::Invisible));
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("longtap scrollend1"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
-                  CaretChangedReason::Visibilitychange));
+                  CaretChangedReason::Scroll));
     EXPECT_CALL(check, Call("longtap scrollstart2"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("longtap scrollend2"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
-                  CaretChangedReason::Visibilitychange));
+                  CaretChangedReason::Scroll));
     EXPECT_CALL(check, Call("longtap scrollstart3"));
 
     EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                   CaretChangedReason::Updateposition));
     EXPECT_CALL(check, Call("longtap scrollend3"));
   }
 
-  AutoRestore<bool> savePref(
-    MockAccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent);
-  MockAccessibleCaretManager::sCaretShownWhenLongTappingOnEmptyContent = true;
-
   // Simulate a single tap on an empty input.
   mManager.FirstCaret().SetAppearance(Appearance::None);
   mManager.UpdateCarets();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
   check.Call("singletap updatecarets");
 
   // Scroll the caret within the viewport.
   mManager.OnScrollStart();
--- a/layout/style/res/ua.css
+++ b/layout/style/res/ua.css
@@ -337,16 +337,22 @@ parsererror|sourcetext {
   font-family: -moz-fixed;
   margin-top: 2em;
   margin-bottom: 1em;
   color: red;
   font-weight: bold;
   font-size: 12pt;
 }
 
+div:-moz-native-anonymous.moz-accessiblecaret {
+  /* Add transition effect to make caret size changing smoother. */
+  transition-duration: 250ms;
+  transition-property: width, height, margin-left;
+}
+
 div:-moz-native-anonymous.moz-accessiblecaret,
 div:-moz-native-anonymous.moz-accessiblecaret > div.image,
 div:-moz-native-anonymous.moz-accessiblecaret > div.bar {
   position: absolute;
   z-index: 2147483647;
 }
 
 div:-moz-native-anonymous.moz-accessiblecaret > div.image {
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -884,21 +884,16 @@ pref("layout.accessiblecaret.margin-left
 pref("layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content", true);
 
 // Android needs persistent carets and actionbar. Turn off the caret timeout.
 pref("layout.accessiblecaret.timeout_ms", 0);
 
 // Android generates long tap (mouse) events.
 pref("layout.accessiblecaret.use_long_tap_injector", false);
 
-// AccessibleCarets behaviour is extended to support Android specific
-// requirements to hide carets while maintaining ActionBar visiblity during page
-// scroll.
-pref("layout.accessiblecaret.extendedvisibility", true);
-
 // Androids carets are always tilt to match the text selection guideline.
 pref("layout.accessiblecaret.always_tilt", true);
 
 // Selection change notifications generated by Javascript changes
 // update active AccessibleCarets / UI interactions.
 pref("layout.accessiblecaret.allow_script_change_updates", true);
 
 // Optionally provide haptic feedback on longPress selection events.
--- a/mobile/android/chrome/content/ActionBarHandler.js
+++ b/mobile/android/chrome/content/ActionBarHandler.js
@@ -60,17 +60,18 @@ var ActionBarHandler = {
       this._init(e.boundingClientRect);
       return;
     }
 
     // Else, update an open ActionBar.
     if (this._selectionID) {
       let [element, win] = this._getSelectionTargets();
       if (this._targetElement === element && this._contentWindow === win) {
-        if (e.reason == 'visibilitychange' || e.reason == 'presscaret') {
+        if (e.reason == 'visibilitychange' || e.reason == 'presscaret' ||
+            e.reason == 'scroll' ) {
           this._updateVisibility();
         } else {
           let forceUpdate = e.reason == 'updateposition' || e.reason == 'releasecaret';
           this._sendActionBarActions(forceUpdate, e.boundingClientRect);
         }
       } else {
         // We have a new focused window/element pair.
         this._uninit(false);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5059,22 +5059,23 @@ pref("layout.accessiblecaret.caret_shown
 // Timeout in milliseconds to hide the accessiblecaret under cursor mode while
 // no one touches it. Set the value to 0 to disable this feature.
 pref("layout.accessiblecaret.timeout_ms", 3000);
 
 // Simulate long tap to select words on the platforms where APZ is not enabled
 // or long tap events does not fired by APZ.
 pref("layout.accessiblecaret.use_long_tap_injector", true);
 
-// Use AccessibleCaret default behaviours.
-pref("layout.accessiblecaret.extendedvisibility", false);
-
 // By default, carets become tilt only when they are overlapping.
 pref("layout.accessiblecaret.always_tilt", false);
 
+// By default, carets always show when scrolling (either panning for zooming)
+// the page.
+pref("layout.accessiblecaret.always_show_when_scrolling", true);
+
 // Selection change notifications generated by Javascript hide
 // AccessibleCarets and close UI interaction by default.
 pref("layout.accessiblecaret.allow_script_change_updates", false);
 
 // Allow one caret to be dragged across the other caret without any limitation.
 // This matches the built-in convention for all desktop platforms.
 pref("layout.accessiblecaret.allow_dragging_across_other_caret", true);