author | Wes Kocher <wkocher@mozilla.com> |
Wed, 29 Apr 2015 16:46:00 -0700 | |
changeset 241647 | 4b9b12c248dcad6c574ccd9e824d93ae3298ec32 |
parent 241616 | a86ed85747d8d36c0fe4ee98b8f039877dfa3096 (current diff) |
parent 241646 | 36d234c6d4b8737b6e5158d65bf927345fa9397e (diff) |
child 241648 | ef9aacc12777facab6b95a334c06bcd61fc4bde4 |
child 241698 | fba992940a64dfc85f5f2ae61610129163f00cc2 |
child 241710 | 02dad33cf2a0888239d7e4563fea4bfad71ee83a |
push id | 28666 |
push user | kwierso@gmail.com |
push date | Wed, 29 Apr 2015 23:46:05 +0000 |
treeherder | mozilla-central@4b9b12c248dc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 40.0a1 |
first release with | nightly linux32
4b9b12c248dc
/
40.0a1
/
20150430030201
/
files
nightly linux64
4b9b12c248dc
/
40.0a1
/
20150430030201
/
files
nightly mac
4b9b12c248dc
/
40.0a1
/
20150430030201
/
files
nightly win32
4b9b12c248dc
/
40.0a1
/
20150430030201
/
files
nightly win64
4b9b12c248dc
/
40.0a1
/
20150430030201
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
40.0a1
/
20150430030201
/
pushlog to previous
nightly linux64
40.0a1
/
20150430030201
/
pushlog to previous
nightly mac
40.0a1
/
20150430030201
/
pushlog to previous
nightly win32
40.0a1
/
20150430030201
/
pushlog to previous
nightly win64
40.0a1
/
20150430030201
/
pushlog to previous
|
--- a/browser/components/places/tests/browser/browser_bookmarksProperties.js +++ b/browser/components/places/tests/browser/browser_bookmarksProperties.js @@ -245,17 +245,16 @@ gTests.push({ PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["testTag"]); PlacesUtils.bookmarks.removeItem(this._itemId); } }); //------------------------------------------------------------------------------ // Bug 475529 - Add button in new folder dialog not default anymore -/* gTests.push({ desc: "Bug 475529 - Add button in new folder dialog not default anymore", sidebar: SIDEBAR_BOOKMARKS_ID, action: ACTION_ADD, itemType: TYPE_FOLDER, window: null, _itemId: null, @@ -281,16 +280,17 @@ gTests.push({ self.window.removeEventListener("unload", arguments.callee, false); executeSoon(function () { self.finish(); }); }, false); info("About to focus the namePicker field"); namePicker.focus(); + namePicker.select(); EventUtils.synthesizeKey("n", {}, this.window); EventUtils.synthesizeKey("VK_RETURN", {}, this.window); }, finish: function() { // Window is already closed. SidebarUI.hide(); runNextTest(); @@ -300,17 +300,16 @@ gTests.push({ // Check that folder name has been changed. is(PlacesUtils.bookmarks.getItemTitle(this._itemId), "n", "Folder name has been edited"); // Cleanup. PlacesUtils.bookmarks.removeItem(this._itemId); } }); -*/ //------------------------------------------------------------------------------ // Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel gTests.push({ desc: "Bug 476020 - Pressing Esc while having the tag autocomplete open closes the bookmarks panel", sidebar: SIDEBAR_BOOKMARKS_ID, action: ACTION_EDIT,
--- a/browser/components/preferences/in-content/main.js +++ b/browser/components/preferences/in-content/main.js @@ -1,15 +1,16 @@ /* 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/. */ Components.utils.import("resource://gre/modules/Downloads.jsm"); Components.utils.import("resource://gre/modules/FileUtils.jsm"); Components.utils.import("resource://gre/modules/Task.jsm"); +Components.utils.import("resource:///modules/TransientPrefs.jsm"); var gMainPane = { /** * Initialization of this. */ init: function () { function setEventListener(aId, aEventType, aCallback) @@ -42,16 +43,25 @@ var gMainPane = { let sysInfo = Cc["@mozilla.org/system-info;1"]. getService(Ci.nsIPropertyBag2); let ver = parseFloat(sysInfo.getProperty("version")); let showTabsInTaskbar = document.getElementById("showTabsInTaskbar"); showTabsInTaskbar.hidden = ver < 6.1; } catch (ex) {} #endif + // The "closing multiple tabs" and "opening multiple tabs might slow down + // &brandShortName;" warnings provide options for not showing these + // warnings again. When the user disabled them, we provide checkboxes to + // re-enable the warnings. + if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnClose")) + document.getElementById("warnCloseMultiple").hidden = true; + if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnOpen")) + document.getElementById("warnOpenMany").hidden = true; + setEventListener("browser.privatebrowsing.autostart", "change", gMainPane.updateBrowserStartupLastSession); setEventListener("browser.download.dir", "change", gMainPane.displayDownloadDirPref); #ifdef HAVE_SHELL_SERVICE setEventListener("setDefaultButton", "command", gMainPane.setDefaultBrowser); #endif
--- a/browser/components/preferences/tabs.js +++ b/browser/components/preferences/tabs.js @@ -21,32 +21,41 @@ var gTabsPane = { * allowed to cancel the action, false to just close the window * browser.tabs.warnOnOpen * - true if the user should be warned if he attempts to open a lot of tabs at * once (e.g. a large folder of bookmarks), false otherwise * browser.taskbar.previews.enable * - true if tabs are to be shown in the Windows 7 taskbar */ + init: function () { #ifdef XP_WIN - /** - * Initialize any platform-specific UI. - */ - init: function () { const Cc = Components.classes; const Ci = Components.interfaces; try { let sysInfo = Cc["@mozilla.org/system-info;1"]. getService(Ci.nsIPropertyBag2); let ver = parseFloat(sysInfo.getProperty("version")); let showTabsInTaskbar = document.getElementById("showTabsInTaskbar"); showTabsInTaskbar.hidden = ver < 6.1; } catch (ex) {} +#endif + + // The "closing multiple tabs" and "opening multiple tabs might slow down + // &brandShortName;" warnings provide options for not showing these + // warnings again. When the user disabled them, we provide checkboxes to + // re-enable the warnings. + let TransientPrefs = + Components.utils.import("resource:///modules/TransientPrefs.jsm", {}) + .TransientPrefs; + if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnClose")) + document.getElementById("warnCloseMultiple").hidden = true; + if (!TransientPrefs.prefShouldBeVisible("browser.tabs.warnOnOpen")) + document.getElementById("warnOpenMany").hidden = true; }, -#endif /** * Determines where a link which opens a new window will open. * * @returns |true| if such links should be opened in new tabs */ readLinkTarget: function() { var openNewWindow = document.getElementById("browser.link.open_newwindow");
--- a/browser/components/preferences/tabs.xul +++ b/browser/components/preferences/tabs.xul @@ -11,19 +11,17 @@ <!ENTITY % tabsDTD SYSTEM "chrome://browser/locale/preferences/tabs.dtd"> %tabsDTD; ]> <overlay id="TabsPaneOverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <prefpane id="paneTabs" -#ifdef XP_WIN onpaneload="gTabsPane.init();" -#endif helpTopic="prefs-tabs"> <preferences id="tabsPreferences"> <preference id="browser.link.open_newwindow" name="browser.link.open_newwindow" type="int"/> <preference id="browser.tabs.loadInBackground" name="browser.tabs.loadInBackground" type="bool" inverted="true"/> <preference id="browser.tabs.warnOnClose" name="browser.tabs.warnOnClose" type="bool"/> <preference id="browser.tabs.warnOnOpen" name="browser.tabs.warnOnOpen" type="bool"/> <preference id="browser.sessionstore.restore_on_demand" name="browser.sessionstore.restore_on_demand" type="bool"/>
--- a/browser/devtools/debugger/test/browser_dbg_breakpoints-contextmenu.js +++ b/browser/devtools/debugger/test/browser_dbg_breakpoints-contextmenu.js @@ -96,42 +96,53 @@ function test() { ok(isCaretPos(gPanel, 9), "The editor location is correct before pausing."); sendMouseClickToTab(gTab, content.document.querySelector("button")); return finished; } - function initialChecks() { + let initialChecks = Task.async(function*() { for (let source of gSources) { for (let breakpoint of source) { ok(gBreakpoints._getAdded(breakpoint.attachment), "All breakpoint items should have corresponding promises (1)."); ok(!gBreakpoints._getRemoving(breakpoint.attachment), "All breakpoint items should have corresponding promises (2)."); ok(breakpoint.attachment.actor, "All breakpoint items should have corresponding promises (3)."); is(!!breakpoint.attachment.disabled, false, "All breakpoints should initially be enabled."); let prefix = "bp-cMenu-"; // "breakpoints context menu" let identifier = gBreakpoints.getIdentifier(breakpoint.attachment); let enableSelfId = prefix + "enableSelf-" + identifier + "-menuitem"; let disableSelfId = prefix + "disableSelf-" + identifier + "-menuitem"; + // Check to make sure that only the bp context menu is shown when right clicking + // this node (Bug 1159276). + let menu = gDebugger.document.getElementById("bp-mPop-" + identifier); + let contextMenuShown = once(gDebugger.document, "popupshown"); + EventUtils.synthesizeMouseAtCenter(breakpoint.prebuiltNode, {type: 'contextmenu', button: 2}, gDebugger); + let event = yield contextMenuShown; + is (event.originalTarget.id, menu.id, "The correct context menu was shown"); + let contextMenuHidden = once(gDebugger.document, "popuphidden"); + menu.hidePopup(); + yield contextMenuHidden; + is(gDebugger.document.getElementById(enableSelfId).getAttribute("hidden"), "true", "The 'Enable breakpoint' context menu item should initially be hidden'."); ok(!gDebugger.document.getElementById(disableSelfId).hasAttribute("hidden"), "The 'Disable breakpoint' context menu item should initially not be hidden'."); is(breakpoint.attachment.view.checkbox.getAttribute("checked"), "true", "All breakpoints should initially have a checked checkbox."); } } - } + }); function checkBreakpointToggleSelf(aIndex) { let deferred = promise.defer(); EventUtils.sendMouseEvent({ type: "click" }, gDebugger.document.querySelectorAll(".dbg-breakpoint")[aIndex], gDebugger);
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm +++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm @@ -395,16 +395,25 @@ SideMenuWidget.prototype = { /** * Shows the contextMenu element. */ _showContextMenu: function(e) { if (!this._contextMenu) { return; } + // Don't show the menu if a descendant node is going to be visible also. + let node = e.originalTarget; + while (node && node !== this._list) { + if (node.hasAttribute("contextmenu")) { + return; + } + node = node.parentNode; + } + this._contextMenu.openPopupAtScreen(e.screenX, e.screenY, true); }, window: null, document: null, _showArrows: false, _showItemCheckboxes: false, _showGroupCheckboxes: false,
--- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -1,13 +1,9 @@ [DEFAULT] -skip-if = e10s # Bug 942707 - PDF viewer doesn't work with e10s. +skip-if = e10s # Bug 1159385 support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] -skip-if = debug # bug 1058695 [browser_pdfjs_navigation.js] -skip-if = debug # bug 1058695 [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] -skip-if = debug # bug 1058695 [browser_pdfjs_zoom.js] -skip-if = debug # bug 1058695
new file mode 100644 --- /dev/null +++ b/browser/modules/TransientPrefs.jsm @@ -0,0 +1,24 @@ +/* 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"; + +this.EXPORTED_SYMBOLS = ["TransientPrefs"]; + +Components.utils.import("resource://gre/modules/Preferences.jsm"); + +let prefVisibility = new Map; + +/* Use for preferences that should only be visible when they've been modified. + When reset to their default state, they remain visible until restarting the + application. */ + +this.TransientPrefs = { + prefShouldBeVisible: function (prefName) { + if (Preferences.isSet(prefName)) + prefVisibility.set(prefName, true); + + return !!prefVisibility.get(prefName); + } +};
--- a/browser/modules/moz.build +++ b/browser/modules/moz.build @@ -34,16 +34,17 @@ EXTRA_JS_MODULES += [ 'PluginContent.jsm', 'ProcessHangMonitor.jsm', 'ReaderParent.jsm', 'RecentWindow.jsm', 'RemotePrompt.jsm', 'SelfSupportBackend.jsm', 'SitePermissions.jsm', 'Social.jsm', + 'TransientPrefs.jsm', 'WebappManager.jsm', 'webrtcUI.jsm', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXTRA_JS_MODULES += [ 'Windows8WindowFrameColor.jsm', 'WindowsJumpLists.jsm',
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -9410,71 +9410,84 @@ namespace { #ifdef MOZ_PLACES // Callback used by CopyFavicon to inform the favicon service that one URI // (mNewURI) has the same favicon URI (OnComplete's aFaviconURI) as another. class nsCopyFaviconCallback final : public nsIFaviconDataCallback { public: NS_DECL_ISUPPORTS - nsCopyFaviconCallback(nsIURI* aNewURI, bool aInPrivateBrowsing) - : mNewURI(aNewURI) + nsCopyFaviconCallback(mozIAsyncFavicons* aSvc, + nsIURI* aNewURI, + bool aInPrivateBrowsing) + : mSvc(aSvc) + , mNewURI(aNewURI) , mInPrivateBrowsing(aInPrivateBrowsing) { } NS_IMETHODIMP OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen, const uint8_t* aData, const nsACString& aMimeType) override { // Continue only if there is an associated favicon. if (!aFaviconURI) { return NS_OK; } - NS_ASSERTION(aDataLen == 0, - "We weren't expecting the callback to deliver data."); - nsCOMPtr<mozIAsyncFavicons> favSvc = - do_GetService("@mozilla.org/browser/favicon-service;1"); - NS_ENSURE_STATE(favSvc); - - return favSvc->SetAndFetchFaviconForPage( + MOZ_ASSERT(aDataLen == 0, + "We weren't expecting the callback to deliver data."); + + return mSvc->SetAndFetchFaviconForPage( mNewURI, aFaviconURI, false, mInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE : nsIFaviconService::FAVICON_LOAD_NON_PRIVATE, nullptr); } private: ~nsCopyFaviconCallback() {} + nsCOMPtr<mozIAsyncFavicons> mSvc; nsCOMPtr<nsIURI> mNewURI; bool mInPrivateBrowsing; }; NS_IMPL_ISUPPORTS(nsCopyFaviconCallback, nsIFaviconDataCallback) #endif -// Tell the favicon service that aNewURI has the same favicon as aOldURI. +} // anonymous namespace + void -CopyFavicon(nsIURI* aOldURI, nsIURI* aNewURI, bool aInPrivateBrowsing) -{ +nsDocShell::CopyFavicon(nsIURI* aOldURI, + nsIURI* aNewURI, + bool aInPrivateBrowsing) +{ + if (XRE_GetProcessType() == GeckoProcessType_Content) { + dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); + if (contentChild) { + mozilla::ipc::URIParams oldURI, newURI; + SerializeURI(aOldURI, oldURI); + SerializeURI(aNewURI, newURI); + contentChild->SendCopyFavicon(oldURI, newURI, aInPrivateBrowsing); + } + return; + } + #ifdef MOZ_PLACES nsCOMPtr<mozIAsyncFavicons> favSvc = do_GetService("@mozilla.org/browser/favicon-service;1"); if (favSvc) { nsCOMPtr<nsIFaviconDataCallback> callback = - new nsCopyFaviconCallback(aNewURI, aInPrivateBrowsing); + new nsCopyFaviconCallback(favSvc, aNewURI, aInPrivateBrowsing); favSvc->GetFaviconURLForPage(aOldURI, callback); } #endif } -} // anonymous namespace - class InternalLoadEvent : public nsRunnable { public: InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI, nsIURI* aReferrer, uint32_t aReferrerPolicy, nsISupports* aOwner, uint32_t aFlags, const char* aTypeHint, nsIInputStream* aPostData, nsIInputStream* aHeadersData, uint32_t aLoadType,
--- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -272,16 +272,21 @@ public: void AddProfileTimelineMarker(const char* aName, TracingMetadata aMetaData); void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>&& aMarker); // Global counter for how many docShells are currently recording profile // timeline markers static unsigned long gProfileTimelineRecordingsCount; + // Tell the favicon service that aNewURI has the same favicon as aOldURI. + static void CopyFavicon(nsIURI* aOldURI, + nsIURI* aNewURI, + bool aInPrivateBrowsing); + protected: // Object Management virtual ~nsDocShell(); virtual void DestroyChildren() override; // Content Viewer Management nsresult EnsureContentViewer(); // aPrincipal can be passed in if the caller wants. If null is
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -149,16 +149,17 @@ #include "SandboxHal.h" #include "ScreenManagerParent.h" #include "SourceSurfaceRawData.h" #include "StructuredCloneUtils.h" #include "TabParent.h" #include "URIUtils.h" #include "nsIWebBrowserChrome.h" #include "nsIDocShell.h" +#include "nsDocShell.h" #include "mozilla/net/NeckoMessageUtils.h" #include "gfxPrefs.h" #include "prio.h" #include "private/pprio.h" #include "ContentProcessManager.h" #include "mozilla/psm/PSMContentListener.h" #include "nsIBidiKeyboard.h" @@ -4565,16 +4566,34 @@ ContentParent::RecvNotifyKeywordSearchLo } } } #endif return true; } bool +ContentParent::RecvCopyFavicon(const URIParams& aOldURI, + const URIParams& aNewURI, + const bool& aInPrivateBrowsing) +{ + nsCOMPtr<nsIURI> oldURI = DeserializeURI(aOldURI); + if (!oldURI) { + return true; + } + nsCOMPtr<nsIURI> newURI = DeserializeURI(aNewURI); + if (!newURI) { + return true; + } + + nsDocShell::CopyFavicon(oldURI, newURI, aInPrivateBrowsing); + return true; +} + +bool ContentParent::ShouldContinueFromReplyTimeout() { nsRefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get(); return !monitor || !monitor->ShouldTimeOutCPOWs(); } bool ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -788,16 +788,20 @@ private: virtual bool RecvKeywordToURI(const nsCString& aKeyword, nsString* aProviderName, OptionalInputStreamParams* aPostData, OptionalURIParams* aURI) override; virtual bool RecvNotifyKeywordSearchLoading(const nsString &aProvider, const nsString &aKeyword) override; + virtual bool RecvCopyFavicon(const URIParams& aOldURI, + const URIParams& aNewURI, + const bool& aInPrivateBrowsing) override; + virtual void ProcessingError(Result aCode, const char* aMsgName) override; virtual bool RecvAllocateLayerTreeId(uint64_t* aId) override; virtual bool RecvDeallocateLayerTreeId(const uint64_t& aId) override; virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature, int32_t* aStatus, bool* aSuccess) override;
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -893,16 +893,18 @@ parent: async CreateFakeVolume(nsString fsName, nsString mountPoint); async SetFakeVolumeState(nsString fsName, int32_t fsState); sync KeywordToURI(nsCString keyword) returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri); sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword); + async CopyFavicon(URIParams oldURI, URIParams newURI, bool isPrivate); + // Tell the compositor to allocate a layer tree id for nested remote mozbrowsers. sync AllocateLayerTreeId() returns (uint64_t id); async DeallocateLayerTreeId(uint64_t id); sync SpeakerManagerForceSpeaker(bool aEnable); sync SpeakerManagerGetSpeakerStatus()
--- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -144,18 +144,16 @@ <!ENTITY pref_search_restore_defaults_summary "Restore defaults"> <!-- Localization note (pref_search_hint) : "TIP" as in "hint", "clue" etc. Displayed as an advisory message on the customise search providers settings page explaining how to add new search providers. The &formatI; in the string will be replaced by a small image of the icon described, and can be moved to wherever it is applicable. --> <!ENTITY pref_search_hint "TIP: Add any website to your list of search providers by long-pressing on its search field and then tapping the &formatI; icon."> <!ENTITY pref_category_devtools "Developer tools"> -<!ENTITY pref_category_devtools_summary "Remote debugging, paint flashing"> -<!ENTITY pref_developer_paint_flashing "Paint flashing"> <!ENTITY pref_developer_remotedebugging "Remote debugging"> <!ENTITY pref_category_logins "Logins"> <!ENTITY pref_remember_signons "Remember passwords"> <!ENTITY pref_manage_logins "Manage logins"> <!ENTITY pref_category_home "Home"> <!ENTITY pref_category_home_summary "Customize your homepage"> <!ENTITY pref_category_home_panels "Panels">
--- a/mobile/android/base/resources/xml-v11/preferences.xml +++ b/mobile/android/base/resources/xml-v11/preferences.xml @@ -49,15 +49,15 @@ <PreferenceScreen android:title="@string/pref_category_vendor" android:summary="@string/pref_category_vendor_summary" android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment" > <extra android:name="resource" android:value="preferences_vendor"/> </PreferenceScreen> <PreferenceScreen android:title="@string/pref_category_devtools" - android:summary="@string/pref_category_devtools_summary" + android:summary="@string/pref_developer_remotedebugging" android:fragment="org.mozilla.gecko.preferences.GeckoPreferenceFragment" > <extra android:name="resource" android:value="preferences_devtools"/> </PreferenceScreen> </PreferenceScreen>
--- a/mobile/android/base/resources/xml/preferences.xml +++ b/mobile/android/base/resources/xml/preferences.xml @@ -67,17 +67,17 @@ android:targetPackage="@string/android_package_name" android:targetClass="org.mozilla.gecko.preferences.GeckoPreferences" > <extra android:name="resource" android:value="preferences_vendor" /> </intent> </PreferenceScreen> <PreferenceScreen android:title="@string/pref_category_devtools" - android:summary="@string/pref_category_devtools_summary" > + android:summary="@string/pref_developer_remotedebugging" > <intent android:action="android.intent.action.VIEW" android:targetPackage="@string/android_package_name" android:targetClass="org.mozilla.gecko.preferences.GeckoPreferences" > <extra android:name="resource" android:value="preferences_devtools" /> </intent> </PreferenceScreen>
--- a/mobile/android/base/resources/xml/preferences_devtools.xml +++ b/mobile/android/base/resources/xml/preferences_devtools.xml @@ -3,20 +3,16 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:gecko="http://schemas.android.com/apk/res-auto" android:title="@string/pref_category_devtools" android:enabled="false"> - <org.mozilla.gecko.preferences.CustomCheckBoxPreference - android:key="nglayout.debug.paint_flashing" - android:title="@string/pref_developer_paint_flashing" /> - <CheckBoxPreference android:key="devtools.debugger.remote-enabled" android:title="@string/pref_developer_remotedebugging" /> <org.mozilla.gecko.preferences.AlignRightLinkPreference android:key="android.not_a_preference.remote_debugging.link" android:title="@string/pref_learn_more" android:persistent="false" url="https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_Firefox_for_Android_with_WebIDE" />
--- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -145,18 +145,16 @@ <string name="pref_search_hint">&pref_search_hint;</string> <string name="pref_category_language">&pref_category_language;</string> <string name="pref_category_language_summary">&pref_category_language_summary;</string> <string name="pref_browser_locale">&pref_browser_locale;</string> <string name="locale_system_default">&locale_system_default;</string> <string name="pref_category_devtools">&pref_category_devtools;</string> - <string name="pref_category_devtools_summary">&pref_category_devtools_summary;</string> - <string name="pref_developer_paint_flashing">&pref_developer_paint_flashing;</string> <string name="pref_developer_remotedebugging">&pref_developer_remotedebugging;</string> <string name="pref_category_home">&pref_category_home;</string> <string name="pref_category_home_summary">&pref_category_home_summary;</string> <string name="pref_category_home_panels">&pref_category_home_panels;</string> <string name="home_add_panel_title">&home_add_panel_title;</string> <string name="home_add_panel_empty">&home_add_panel_empty;</string> <string name="home_add_panel_installed">&home_add_panel_installed;</string>
--- a/mobile/android/base/tests/StringHelper.java +++ b/mobile/android/base/tests/StringHelper.java @@ -154,17 +154,16 @@ public class StringHelper { public final String ABOUT_LABEL = "About " + BRAND_NAME ; public final String FAQS_LABEL; public final String FEEDBACK_LABEL; public final String LOCATION_SERVICES_LABEL = "Mozilla Location Service"; public final String HEALTH_REPORT_LABEL = BRAND_NAME + " Health Report"; public final String MY_HEALTH_REPORT_LABEL; // Developer tools - public final String PAINT_FLASHING_LABEL; public final String REMOTE_DEBUGGING_LABEL; public final String LEARN_MORE_LABEL; // Labels for the about:home tabs public final String HISTORY_LABEL; public final String TOP_SITES_LABEL; public final String BOOKMARKS_LABEL; public final String READING_LIST_LABEL; @@ -331,17 +330,16 @@ public class StringHelper { CLEAR_PRIVATE_DATA_LABEL = res.getString(R.string.pref_clear_private_data); // Mozilla FAQS_LABEL = res.getString(R.string.pref_vendor_faqs); FEEDBACK_LABEL = res.getString(R.string.pref_vendor_feedback); MY_HEALTH_REPORT_LABEL = res.getString(R.string.datareporting_abouthr_title); // Developer tools - PAINT_FLASHING_LABEL = res.getString(R.string.pref_developer_paint_flashing); REMOTE_DEBUGGING_LABEL = res.getString(R.string.pref_developer_remotedebugging); LEARN_MORE_LABEL = res.getString(R.string.pref_learn_more); // Labels for the about:home tabs HISTORY_LABEL = res.getString(R.string.home_history_title); TOP_SITES_LABEL = res.getString(R.string.home_top_sites_title); BOOKMARKS_LABEL = res.getString(R.string.bookmarks_title); READING_LIST_LABEL = res.getString(R.string.reading_list_title);
--- a/mobile/android/base/tests/robocop.ini +++ b/mobile/android/base/tests/robocop.ini @@ -77,18 +77,16 @@ skip-if = android_version == "18" [testPictureLinkContextMenu] # disabled on 4.3, bug 1031496 skip-if = android_version == "18" [testPrefsObserver] [testPrivateBrowsing] [testPromptGridInput] # bug 1001657 for 2.3 and 4.3 skip-if = android_version == "10" || android_version == "18" -# [testReaderMode] # see bug 913254, 936224 -[testReadingListCache] [testReadingListProvider] [testSearchHistoryProvider] [testSearchSuggestions] # disabled on 2.3, bug 907768; on 4.3, bug 1145867 skip-if = android_version == "10" || android_version == "18" [testSessionOOMSave] # disabled on 2.3, bug 945395; on 4.3, bug 1144888 skip-if = android_version == "10" || android_version == "18" @@ -117,22 +115,25 @@ skip-if = android_version == "18" [testDebuggerServer] [testDeviceSearchEngine] [testFilePicker] [testHistoryService] # disabled on 4.3, bug 1116036 skip-if = android_version == "18" [testJNI] # [testMozPay] # see bug 945675 +[testMigrateUI] [testNetworkManager] [testOfflinePage] [testOrderedBroadcast] [testOSLocale] # disabled on 2.3 and 4.3: Bug 1124494 skip-if = android_version == "10" || android_version == "18" +[testReaderView] +[testReadingListCache] [testResourceSubstitutions] [testRestrictedProfiles] [testSessionFormData] [testSharedPreferences] [testSimpleDiscovery] [testTrackingProtection] # disabled on 4.3, bug 1158363 skip-if = android_version == "18"
new file mode 100644 --- /dev/null +++ b/mobile/android/base/tests/testMigrateUI.java @@ -0,0 +1,11 @@ +/* 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/. */ + +package org.mozilla.gecko.tests; + +public class testMigrateUI extends JavascriptTest { + public testMigrateUI() { + super("testMigrateUI.js"); + } +}
new file mode 100644 --- /dev/null +++ b/mobile/android/base/tests/testMigrateUI.js @@ -0,0 +1,22 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +/* 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/. */ + +Components.utils.import("resource://gre/modules/Services.jsm"); + +add_task(function* test_migrateUI() { + Services.prefs.clearUserPref("browser.migration.version"); + Services.prefs.setBoolPref("nglayout.debug.paint_flashing", true); + + let BrowserApp = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp; + BrowserApp._migrateUI(); + + // Check that migration version increased. + do_check_eq(Services.prefs.getIntPref("browser.migration.version"), 1); + + // Check that user pref value was reset. + do_check_eq(Services.prefs.prefHasUserValue("nglayout.debug.paint_flashing"), false); +}); + +run_next_test();
deleted file mode 100644 --- a/mobile/android/base/tests/testReaderMode.java +++ /dev/null @@ -1,203 +0,0 @@ -/* 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/. */ - -package org.mozilla.gecko.tests; - -import org.json.JSONException; -import org.json.JSONObject; -import org.mozilla.gecko.Actions; -import org.mozilla.gecko.home.HomePager; -import org.mozilla.gecko.R; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; - -import com.jayway.android.robotium.solo.Condition; -import com.jayway.android.robotium.solo.Solo; - -/** - * This patch tests the Reader Mode feature by adding and removing items in reading list - * checks the reader toolbar functionality(share, add/remove to reading list, go to reading list) - * accessing a page from reading list menu, checks that the reader icon is associated in History tab - * and that the reading list is properly populated after adding or removing reader items - */ -public class testReaderMode extends AboutHomeTest { - static final int EVENT_CLEAR_DELAY_MS = 3000; - static final int READER_ICON_MAX_WAIT_MS = 15000; - - public void testReaderMode() { - blockForGeckoReady(); - - Actions.EventExpecter contentEventExpecter; - Actions.EventExpecter contentReaderAddedExpecter; - Actions.EventExpecter faviconExpecter; - Actions.EventExpecter contentPageShowExpecter; - Actions.RepeatedEventExpecter paintExpecter; - ListView list; - View child; - View readerIcon; - String textUrl = getAbsoluteUrl(mStringHelper.ROBOCOP_TEXT_PAGE_URL); - String devType = mDevice.type; - int childNo; - int height; - int width; - - loadAndPaint(textUrl); - - // Add the page to the Reading List using long click on the reader icon - readerIcon = getReaderIcon(); - contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added"); - mSolo.clickLongOnView(readerIcon); - String eventData = contentReaderAddedExpecter.blockForEventData(); - isAdded(eventData); - contentReaderAddedExpecter.unregisterListener(); - - // Try to add the page to the Reading List using long click on the reader icon a second time - readerIcon = getReaderIcon(); - contentReaderAddedExpecter = mActions.expectGeckoEvent("Reader:Added"); - mSolo.clickLongOnView(readerIcon); - eventData = contentReaderAddedExpecter.blockForEventData(); - isAdded(eventData); - contentReaderAddedExpecter.unregisterListener(); - - // Waiting for the favicon since is the last element loaded usually - faviconExpecter = mActions.expectGeckoEvent("Reader:FaviconRequest"); - contentPageShowExpecter = mActions.expectGeckoEvent("Content:PageShow"); - readerIcon = getReaderIcon(); - paintExpecter = mActions.expectPaint(); - mSolo.clickOnView(readerIcon); - - // Changing devices orientation to be sure that all devices are in portrait when will access the reader toolbar - mSolo.setActivityOrientation(Solo.PORTRAIT); - faviconExpecter.blockForEvent(); - faviconExpecter.unregisterListener(); - contentPageShowExpecter.blockForEvent(); - contentPageShowExpecter.unregisterListener(); - paintExpecter.blockUntilClear(EVENT_CLEAR_DELAY_MS); - paintExpecter.unregisterListener(); - verifyUrlBarTitle(mStringHelper.ROBOCOP_TEXT_PAGE_URL); - - // Open the share menu for the reader toolbar - height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10; - width = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() - 10; - mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height)); - mSolo.clickOnScreen(width,height); - mAsserter.ok(mSolo.waitForText("Share via"), "Waiting for the share menu", "The share menu is present"); - mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Close the share menu - - // Remove page from the Reading List using reader toolbar - height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10; - width = mDriver.getGeckoLeft() + 50; - mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height)); - mSolo.clickOnScreen(width,height); - mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List"); - - //Add page to the Reading List using reader toolbar - mSolo.clickOnScreen(width,height); - mAsserter.ok(mSolo.waitForText("Page added to your Reading List"), "Waiting for the page to be added to your Reading List", "The page was added to your Reading List"); - - // Open the Reading List menu for the toolbar - height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10; - width = mDriver.getGeckoLeft() + mDriver.getGeckoWidth()/2 - 10; - mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height)); - contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded"); - mSolo.clickOnScreen(width,height); - contentEventExpecter.blockForEvent(); - contentEventExpecter.unregisterListener(); - - // Check if the page is present in the Reading List - mAsserter.ok(mSolo.waitForText(mStringHelper.ROBOCOP_TEXT_PAGE_TITLE), - "Verify if the page is added to your Reading List", - mStringHelper.ROBOCOP_TEXT_PAGE_TITLE); - - // Check if the page is added in History tab like a Reading List item - openAboutHomeTab(AboutHomeTabs.HISTORY); - list = findListViewWithTag(HomePager.LIST_TAG_HISTORY); - child = list.getChildAt(1); - mAsserter.ok(child != null, "item can be retrieved", child != null ? child.toString() : "null!"); - mSolo.clickLongOnView(child); - mAsserter.ok(mSolo.waitForText("Open in Reader"), "Verify if the page is present in history as a Reading List item", "The page is present in history as a Reading List item"); - mActions.sendSpecialKey(Actions.SpecialKey.BACK); // Dismiss the context menu - mSolo.waitForText(mStringHelper.ROBOCOP_TEXT_PAGE_TITLE); - - // Verify separately the Reading List entries for tablets and phone because for tablets there is an extra child in UI design - if (devType.equals("phone")) { - childNo = 1; - } - else { - childNo = 2; - } - // Verify if the page is present to your Reading List - openAboutHomeTab(AboutHomeTabs.READING_LIST); - list = findListViewWithTag(HomePager.LIST_TAG_READING_LIST); - child = list.getChildAt(childNo-1); - mAsserter.ok(child != null, "Verify if the page is present to your Reading List", "The page is present in your Reading List"); - contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded"); - mSolo.clickOnView(child); - contentEventExpecter.blockForEvent(); - contentEventExpecter.unregisterListener(); - verifyUrlBarTitle(mStringHelper.ROBOCOP_TEXT_PAGE_URL); - - // Verify that we are in reader mode and remove the page from Reading List - height = mDriver.getGeckoTop() + mDriver.getGeckoHeight() - 10; - width = mDriver.getGeckoLeft() + 50; - mAsserter.dumpLog("Long Clicking at width = " + String.valueOf(width) + " and height = " + String.valueOf(height)); - mSolo.clickOnScreen(width,height); - mAsserter.ok(mSolo.waitForText("Page removed from your Reading List"), "Waiting for the page to removed from your Reading List", "The page is removed from your Reading List"); - verifyUrlBarTitle(mStringHelper.ROBOCOP_TEXT_PAGE_URL); - - //Check if the Reading List is empty - openAboutHomeTab(AboutHomeTabs.READING_LIST); - list = findListViewWithTag(HomePager.LIST_TAG_READING_LIST); - child = list.getChildAt(childNo-1); - mAsserter.ok(child == null, "Verify if the Reading List is empty", "The Reading List is empty"); - } - - // Get the reader icon method - protected View getReaderIcon() { - View pageActionLayout = mSolo.getView(R.id.page_action_layout); - final ViewGroup actionLayoutEntry = (ViewGroup)pageActionLayout; - View icon = actionLayoutEntry.getChildAt(1); - if (icon == null || icon.getVisibility() != View.VISIBLE) { - // wait for the view to be visible, otherwise it may not respond - // to clicks -- see bug 927578 - mAsserter.dumpLog("reader icon not visible -- waiting for visibility"); - Condition visibilityCondition = new Condition() { - @Override - public boolean isSatisfied() { - View conditionIcon = actionLayoutEntry.getChildAt(1); - if (conditionIcon == null || - conditionIcon.getVisibility() != View.VISIBLE) - return false; - return true; - } - }; - waitForCondition(visibilityCondition, READER_ICON_MAX_WAIT_MS); - icon = actionLayoutEntry.getChildAt(1); - mAsserter.ok(icon != null, "checking reader icon view", "reader icon view not null"); - mAsserter.ok(icon.getVisibility() == View.VISIBLE, "checking reader icon visible", "reader icon visible"); - } - return icon; - } - - // This method check to see if a reader item is added to the reader list - private boolean isAdded(String eventData) { - try { - JSONObject data = new JSONObject(eventData); - if (data.getInt("result") == 0) { - mAsserter.ok(true, "Waiting for the page to be added to your Reading List", "The page was added to your Reading List"); - } - else { - if (data.getInt("result") == 2) { - mAsserter.ok(true, "Trying to add a second time the page in your Reading List", "The page is already in your Reading List"); - } - } - } catch (JSONException e) { - mAsserter.ok(false, "Error parsing the event data", e.toString()); - return false; - } - return true; - } -}
new file mode 100644 --- /dev/null +++ b/mobile/android/base/tests/testReaderView.java @@ -0,0 +1,12 @@ +/* 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/. */ + +package org.mozilla.gecko.tests; + + +public class testReaderView extends JavascriptTest { + public testReaderView() { + super("testReaderView.js"); + } +}
new file mode 100644 --- /dev/null +++ b/mobile/android/base/tests/testReaderView.js @@ -0,0 +1,67 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +/* 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/. */ + +const { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +Cu.import("resource://gre/modules/Services.jsm"); + +function promiseBrowserEvent(browser, eventType) { + return new Promise((resolve) => { + function handle(event) { + // Since we'll be redirecting, don't make assumptions about the given URL and the loaded URL + if (event.target != browser.contentDocument || event.target.location.href == "about:blank") { + do_print("Skipping spurious '" + eventType + "' event" + " for " + event.target.location.href); + return; + } + do_print("Received event " + eventType + " from browser"); + browser.removeEventListener(eventType, handle, true); + resolve(event); + } + + browser.addEventListener(eventType, handle, true); + do_print("Now waiting for " + eventType + " event from browser"); + }); +} + +function promiseWaitForCondition(win, condition) { + return new Promise((resolve, reject) => { + var tries = 0; + var interval = win.setInterval(function() { + if (tries >= 30) { + do_print("Condition didn't pass. Moving on."); + moveOn(); + } + if (condition()) { + moveOn(); + } + tries++; + }, 200); + var moveOn = function() { win.clearInterval(interval); resolve(); }; + }); +} + +add_task(function* test_reader_view_visibility() { + let gWin = Services.wm.getMostRecentWindow("navigator:browser"); + let BrowserApp = gWin.BrowserApp; + + let url = "http://mochi.test:8888/tests/robocop/reader_mode_pages/basic_article.html"; + let browser = BrowserApp.addTab("about:reader?url=" + url).browser; + + yield promiseBrowserEvent(browser, "load"); + + do_register_cleanup(function cleanup() { + BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser)); + }); + + let doc = browser.contentDocument; + let title = doc.getElementById("reader-title"); + + // We need to wait for reader content to appear because AboutReader.jsm + // asynchronously fetches the content after about:reader loads. + yield promiseWaitForCondition(gWin, () => title.textContent); + do_check_eq(title.textContent, "Article title"); +}); + +run_next_test();
--- a/mobile/android/base/tests/testSettingsMenuItems.java +++ b/mobile/android/base/tests/testSettingsMenuItems.java @@ -113,17 +113,16 @@ public class testSettingsMenuItems exten { mStringHelper.FEEDBACK_LABEL }, { "Data choices" }, { mStringHelper.HEALTH_REPORT_LABEL, "Shares data with Mozilla about your browser health and helps you understand your browser performance" }, { mStringHelper.MY_HEALTH_REPORT_LABEL }, }; PATH_DEVELOPER = new String[] { mStringHelper.DEVELOPER_TOOLS_SECTION_LABEL }; OPTIONS_DEVELOPER = new String[][] { - { mStringHelper.PAINT_FLASHING_LABEL }, { mStringHelper.REMOTE_DEBUGGING_LABEL }, { mStringHelper.LEARN_MORE_LABEL }, }; settingsMap.put(PATH_CUSTOMIZE, new ArrayList<String[]>(Arrays.asList(OPTIONS_CUSTOMIZE))); settingsMap.put(PATH_HOME, new ArrayList<String[]>(Arrays.asList(OPTIONS_HOME))); settingsMap.put(PATH_DISPLAY, new ArrayList<String[]>(Arrays.asList(OPTIONS_DISPLAY))); settingsMap.put(PATH_PRIVACY, new ArrayList<String[]>(Arrays.asList(OPTIONS_PRIVACY)));
--- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -907,47 +907,70 @@ var BrowserApp = { }); }, onAppUpdated: function() { // initialize the form history and passwords databases on upgrades Services.obs.notifyObservers(null, "FormHistory:Init", ""); Services.obs.notifyObservers(null, "Passwords:Init", ""); - // Migrate user-set "plugins.click_to_play" pref. See bug 884694. - // Because the default value is true, a user-set pref means that the pref was set to false. - if (Services.prefs.prefHasUserValue("plugins.click_to_play")) { - Services.prefs.setIntPref("plugin.default.state", Ci.nsIPluginTag.STATE_ENABLED); - Services.prefs.clearUserPref("plugins.click_to_play"); - } - - // Migrate the "privacy.donottrackheader.value" pref. See bug 1042135. - if (Services.prefs.prefHasUserValue("privacy.donottrackheader.value")) { - // Make sure the doNotTrack value conforms to the conversion from - // three-state to two-state. (This reverts a setting of "please track me" - // to the default "don't say anything"). - if (Services.prefs.getBoolPref("privacy.donottrackheader.enabled") && - (Services.prefs.getIntPref("privacy.donottrackheader.value") != 1)) { - Services.prefs.clearUserPref("privacy.donottrackheader.enabled"); - } - - // This pref has been removed, so always clear it. - Services.prefs.clearUserPref("privacy.donottrackheader.value"); - } - - // Set the search activity default pref on app upgrade if it has not been set already. - if (this._startupStatus === "upgrade" && - !Services.prefs.prefHasUserValue("searchActivity.default.migrated")) { - Services.prefs.setBoolPref("searchActivity.default.migrated", true); - SearchEngines.migrateSearchActivityDefaultPref(); - } - if (this._startupStatus === "upgrade") { + this._migrateUI(); + } + }, + + _migrateUI: function() { + const UI_VERSION = 1; + let currentUIVersion = 0; + try { + currentUIVersion = Services.prefs.getIntPref("browser.migration.version"); + } catch(ex) {} + if (currentUIVersion >= UI_VERSION) { + return; + } + + if (currentUIVersion < 1) { + // Migrate user-set "plugins.click_to_play" pref. See bug 884694. + // Because the default value is true, a user-set pref means that the pref was set to false. + if (Services.prefs.prefHasUserValue("plugins.click_to_play")) { + Services.prefs.setIntPref("plugin.default.state", Ci.nsIPluginTag.STATE_ENABLED); + Services.prefs.clearUserPref("plugins.click_to_play"); + } + + // Migrate the "privacy.donottrackheader.value" pref. See bug 1042135. + if (Services.prefs.prefHasUserValue("privacy.donottrackheader.value")) { + // Make sure the doNotTrack value conforms to the conversion from + // three-state to two-state. (This reverts a setting of "please track me" + // to the default "don't say anything"). + if (Services.prefs.getBoolPref("privacy.donottrackheader.enabled") && + (Services.prefs.getIntPref("privacy.donottrackheader.value") != 1)) { + Services.prefs.clearUserPref("privacy.donottrackheader.enabled"); + } + + // This pref has been removed, so always clear it. + Services.prefs.clearUserPref("privacy.donottrackheader.value"); + } + + // Set the search activity default pref on app upgrade if it has not been set already. + if (!Services.prefs.prefHasUserValue("searchActivity.default.migrated")) { + Services.prefs.setBoolPref("searchActivity.default.migrated", true); + SearchEngines.migrateSearchActivityDefaultPref(); + } + Reader.migrateCache().catch(e => Cu.reportError("Error migrating Reader cache: " + e)); - } + + // We removed this pref from user visible settings, so we should reset it. + // Power users can go into about:config to re-enable this if they choose. + if (Services.prefs.prefHasUserValue("nglayout.debug.paint_flashing")) { + Services.prefs.clearUserPref("nglayout.debug.paint_flashing"); + } + } + + // Update the migration version. + Services.prefs.setIntPref("browser.migration.version", UI_VERSION); }, // This function returns false during periods where the browser displayed document is // different from the browser content document, so user actions and some kinds of viewport // updates should be ignored. This period starts when we start loading a new page or // switch tabs, and ends when the new browser content document has been drawn and handed // off to the compositor. isBrowserContentDocumentDisplayed: function() {
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SearchBar.java +++ b/mobile/android/search/java/org/mozilla/search/autocomplete/SearchBar.java @@ -79,17 +79,18 @@ public class SearchBar extends FrameLayo updateClearButtonVisibility(); } }); // Attach a listener for the "search" key on the keyboard. editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (listener != null && actionId == EditorInfo.IME_ACTION_SEARCH) { + if (listener != null && + (actionId == EditorInfo.IME_ACTION_UNSPECIFIED || actionId == EditorInfo.IME_ACTION_SEARCH)) { // The user searched without using search engine suggestions. Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH, TelemetryContract.Method.ACTIONBAR, "text"); listener.onSubmit(v.getText().toString()); return true; } return false; } });
--- a/storage/src/mozStoragePrivateHelpers.cpp +++ b/storage/src/mozStoragePrivateHelpers.cpp @@ -91,32 +91,28 @@ checkAndLogStatementPerformance(sqlite3_ return; const char *sql = ::sqlite3_sql(aStatement); // Check to see if this is marked to not warn if (::strstr(sql, "/* do not warn (bug ")) return; - nsAutoCString message; + nsAutoCString message("Suboptimal indexes for the SQL statement "); +#ifdef MOZ_STORAGE_SORTWARNING_SQL_DUMP + message.Append('`'); + message.Append(sql); + message.AppendLiteral("` ["); message.AppendInt(count); - if (count == 1) - message.AppendLiteral(" sort operation has "); - else - message.AppendLiteral(" sort operations have "); - message.AppendLiteral("occurred for the SQL statement '"); -#ifdef MOZ_STORAGE_SORTWARNING_SQL_DUMP - message.AppendLiteral("SQL command: "); - message.Append(sql); + message.AppendLiteral(" sort operation(s)]"); #else nsPrintfCString address("0x%p", aStatement); message.Append(address); #endif - message.Append("'. See https://developer.mozilla.org/En/Storage/Warnings " - "details."); + message.AppendLiteral(" (http://mzl.la/1FuID0j)."); NS_WARNING(message.get()); } nsIVariant * convertJSValToVariant( JSContext *aCtx, JS::Value aValue) {
--- a/toolkit/components/passwordmgr/LoginManagerParent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerParent.jsm @@ -1,9 +1,8 @@ -/* vim: set ts=2 sts=2 sw=2 et tw=80: */ /* 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"; const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; @@ -403,16 +402,25 @@ var LoginManagerParent = { prompterSvc.init(target.isRemoteBrowser ? target.ownerDocument.defaultView : target.contentWindow); if (target.isRemoteBrowser) prompterSvc.setE10sData(target, opener); return prompterSvc; } + function recordLoginUse(login) { + // Update the lastUsed timestamp and increment the use count. + let propBag = Cc["@mozilla.org/hash-property-bag;1"]. + createInstance(Ci.nsIWritablePropertyBag); + propBag.setProperty("timeLastUsed", Date.now()); + propBag.setProperty("timesUsedIncrement", 1); + Services.logins.modifyLogin(login, propBag); + } + if (!Services.logins.getLoginSavingEnabled(hostname)) { log("(form submission ignored -- saving is disabled for:", hostname, ")"); return; } var formLogin = Cc["@mozilla.org/login-manager/loginInfo;1"]. createInstance(Ci.nsILoginInfo); formLogin.init(hostname, formSubmitURL, null, @@ -426,16 +434,24 @@ var LoginManagerParent = { // If we didn't find a username field, but seem to be changing a // password, allow the user to select from a list of applicable // logins to update the password for. if (!usernameField && oldPasswordField && logins.length > 0) { var prompter = getPrompter(); if (logins.length == 1) { var oldLogin = logins[0]; + + if (oldLogin.password == formLogin.password) { + recordLoginUse(oldLogin); + log("(Not prompting to save/change since we have no username and the " + + "only saved password matches the new password)"); + return; + } + formLogin.username = oldLogin.username; formLogin.usernameField = oldLogin.usernameField; prompter.promptToChangePassword(oldLogin, formLogin); } else { prompter.promptToChangePasswordWithUsernames( logins, logins.length, formLogin); } @@ -476,22 +492,17 @@ var LoginManagerParent = { log("Found an existing login matching this form submission"); // Change password if needed. if (existingLogin.password != formLogin.password) { log("...passwords differ, prompting to change."); prompter = getPrompter(); prompter.promptToChangePassword(existingLogin, formLogin); } else { - // Update the lastUsed timestamp. - var propBag = Cc["@mozilla.org/hash-property-bag;1"]. - createInstance(Ci.nsIWritablePropertyBag); - propBag.setProperty("timeLastUsed", Date.now()); - propBag.setProperty("timesUsedIncrement", 1); - Services.logins.modifyLogin(existingLogin, propBag); + recordLoginUse(existingLogin); } return; } // Prompt user to save login (via dialog or notification bar) prompter = getPrompter();
--- a/toolkit/components/passwordmgr/test/subtst_notifications_2pw_0un.html +++ b/toolkit/components/passwordmgr/test/subtst_notifications_2pw_0un.html @@ -7,17 +7,17 @@ <form id="form" action="formsubmit.sjs"> <input id="pass1" name="pass1" type="password" value="staticpw"> <input id="pass" name="pass" type="password"> <button type="submit">Submit</button> </form> <script> function submitForm() { - pass.value = "notifyp2"; + pass.value = "notifyp1"; form.submit(); } window.onload = submitForm; var form = document.getElementById("form"); var pass = document.getElementById("pass"); </script>
--- a/toolkit/components/passwordmgr/test/test_notifications.html +++ b/toolkit/components/passwordmgr/test/test_notifications.html @@ -46,16 +46,18 @@ var subtests = [ "subtst_notifications_9.html", // 19 "subtst_notifications_10.html", // 20 "http://test1.example.org:80" + testpath + "subtst_notifications_1.html", // 21 "http://test1.example.org:80" + testpath + "subtst_notifications_7.html", // 22 "http://test1.example.org:80" + testpath + "subtst_notifications_6.html", // 23 "subtst_notifications_2pw_0un.html", // 24 "subtst_notifications_2pw_0un.html", // 25 "subtst_notifications_2pw_0un.html", // 26 + "subtst_notifications_2pw_0un.html", // 27 + "subtst_notifications_2pw_0un.html", // 28 ]; var ignoreLoad = false; function handleLoad(aEvent) { // ignore every other load event ... We get one for loading the subtest (which // we want to ignore), and another when the subtest's form submits itself // (which we want to handle, to start the next test). @@ -142,17 +144,17 @@ function checkTest() { case 5: // Same subtest, make sure we didn't prompt for an existing login. is(gotUser, "notifyu1", "Checking submitted username"); is(gotPass, "notifyp1", "Checking submitted password"); popup = getPopup(popupNotifications, "password-save"); ok(!popup, "checking for no notification popup"); // Check to make sure we updated the timestamps and use count on the - // existing loging that was submitted for this form. + // existing login that was submitted for this form. var logins = pwmgr.getAllLogins(); is(logins.length, 1, "Should only have 1 login"); ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI"); is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission"); ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped"); ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated"); // remove that login @@ -380,50 +382,99 @@ function checkTest() { ok(expectedText.test(notificationText), "Checking text: " + notificationText); popup.remove(); break; case 24: // Check for notification popup when a form with 2 password fields (no username) is // submitted and there are no saved logins. is(gotUser, "null", "Checking submitted username"); - is(gotPass, "notifyp2", "Checking submitted password"); + is(gotPass, "notifyp1", "Checking submitted password"); popup = getPopup(popupNotifications, "password-save"); ok(popup, "got notification popup"); popup.remove(); // Add login for the next test - pwmgr.addLogin(login1); + pwmgr.addLogin(login1B); break; case 25: // Check for notification popup when a form with 2 password fields (no username) is // submitted and there is a saved login with a username and different password. is(gotUser, "null", "Checking submitted username"); - is(gotPass, "notifyp2", "Checking submitted password"); + is(gotPass, "notifyp1", "Checking submitted password"); popup = getPopup(popupNotifications, "password-change"); ok(popup, "got notification popup"); popup.remove(); // remove that login - pwmgr.removeLogin(login1); + pwmgr.removeLogin(login1B); // Add login for the next test pwmgr.addLogin(login2B); break; case 26: // Check for notification popup when a form with 2 password fields (no username) is // submitted and there is a saved login with no username and a different password. is(gotUser, "null", "Checking submitted username"); - is(gotPass, "notifyp2", "Checking submitted password"); + is(gotPass, "notifyp1", "Checking submitted password"); popup = getPopup(popupNotifications, "password-change"); ok(popup, "got notification popup"); popup.remove(); // remove that login pwmgr.removeLogin(login2B); + + // Add login for the next test + pwmgr.addLogin(login1); + + break; + + case 27: + // Check for no notification popup when a form with 2 password fields (no username) is + // submitted and there is a saved login with a username and the same password. + is(gotUser, "null", "Checking submitted username"); + is(gotPass, "notifyp1", "Checking submitted password"); + popup = getPopup(popupNotifications, "password-change"); + ok(!popup, "checking for no notification popup"); + + // Check to make sure we updated the timestamps and use count on the + // existing login that was submitted for this form. + var logins = pwmgr.getAllLogins(); + is(logins.length, 1, "Should only have 1 login"); + ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI"); + is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission"); + ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped"); + ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated"); + + // remove that login + pwmgr.removeLogin(login1); + + // Add login for the next test + pwmgr.addLogin(login2); + break; + + case 28: + // Check for no notification popup when a form with 2 password fields (no username) is + // submitted and there is a saved login with no username and the same password. + is(gotUser, "null", "Checking submitted username"); + is(gotPass, "notifyp1", "Checking submitted password"); + popup = getPopup(popupNotifications, "password-change"); + ok(!popup, "checking for no notification popup"); + + // Check to make sure we updated the timestamps and use count on the + // existing login that was submitted for this form. + var logins = pwmgr.getAllLogins(); + is(logins.length, 1, "Should only have 1 login"); + ok(SpecialPowers.call_Instanceof(logins[0], Ci.nsILoginMetaInfo), "metainfo QI"); + is(logins[0].timesUsed, 2, "check .timesUsed for existing login submission"); + ok(logins[0].timeLastUsed > logins[0].timeCreated, "timeLastUsed bumped"); + ok(logins[0].timeCreated == logins[0].timePasswordChanged, "timeChanged not updated"); + + // remove that login + pwmgr.removeLogin(login2); break; default: ok(false, "Unexpected call to checkTest for test #" + testNum); } // TODO:
--- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -23,16 +23,18 @@ #include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryServiceUtils.h" #include "prsystem.h" #include "nsPrintfCString.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "prtime.h" +#include "nsXULAppAPI.h" + // Time between corrupt database backups. #define RECENT_BACKUP_TIME_MICROSEC (int64_t)86400 * PR_USEC_PER_SEC // 24H // Filename of the database. #define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite") // Filename used to backup corrupt databases. #define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt") @@ -341,16 +343,18 @@ Database::Database() : mMainThreadStatements(mMainConn) , mMainThreadAsyncStatements(mMainConn) , mAsyncThreadStatements(mMainConn) , mDBPageSize(0) , mDatabaseStatus(nsINavHistoryService::DATABASE_STATUS_OK) , mShuttingDown(false) , mClosed(false) { + MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Content, + "Cannot instantiate Places in the content process"); // Attempting to create two instances of the service? MOZ_ASSERT(!gDatabase); gDatabase = this; } Database::~Database() { // Check to make sure it's us, in case somebody wrongly creates an extra
--- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -2001,16 +2001,22 @@ XPCOMUtils.defineLazyGetter(this, "gAsyn () => new Promise((resolve) => { Sqlite.wrapStorageConnection({ connection: PlacesUtils.history.DBConnection, }).then(conn => { try { Sqlite.shutdown.addBlocker( "PlacesUtils wrapped connection closing", conn.close.bind(conn)); + + // Also ensure we close the wrapper in case Places shutdowns first. + Services.obs.addObserver(function observe() { + Services.obs.removeObserver(observe, "places-will-close-connection"); + conn.close(); + }, "places-will-close-connection", false); } catch(ex) { // It's too late to block shutdown, just close the connection. conn.close(); throw ex; } resolve(conn); }); })
--- a/toolkit/components/places/nsLivemarkService.js +++ b/toolkit/components/places/nsLivemarkService.js @@ -67,19 +67,19 @@ XPCOMUtils.defineLazyGetter(this, "gLive feedURI_anno: PlacesUtils.LMANNO_FEEDURI, siteURI_anno: PlacesUtils.LMANNO_SITEURI }); for (let row of rows) { let siteURI = row.getResultByName("siteURI"); let livemark = new Livemark({ id: row.getResultByName("id"), guid: row.getResultByName("guid"), title: row.getResultByName("title"), - parentId: row.getResultByName("parent"), + parentId: row.getResultByName("parentId"), parentGuid: row.getResultByName("parentGuid"), - index: row.getResultByName("position"), + index: row.getResultByName("index"), dateAdded: row.getResultByName("dateAdded"), lastModified: row.getResultByName("lastModified"), feedURI: NetUtil.newURI(row.getResultByName("feedURI")), siteURI: siteURI ? NetUtil.newURI(siteURI) : null }); livemarksMap.set(livemark.guid, livemark); } return livemarksMap;
--- a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js +++ b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js @@ -1,16 +1,48 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests functionality of the mozIAsyncLivemarks interface. const FEED_URI = NetUtil.newURI("http://feed.rss/"); const SITE_URI = NetUtil.newURI("http://site.org/"); +// This test must be the first one, since it's testing the cache. +add_task(function* test_livemark_cache() { + // Add a livemark through other APIs. + let folder = yield PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + title: "test", + parentGuid: PlacesUtils.bookmarks.unfiledGuid + }); + let id = yield PlacesUtils.promiseItemId(folder.guid); + PlacesUtils.annotations + .setItemAnnotation(id, PlacesUtils.LMANNO_FEEDURI, + "http://example.com/feed", + 0, PlacesUtils.annotations.EXPIRE_NEVER); + PlacesUtils.annotations + .setItemAnnotation(id, PlacesUtils.LMANNO_SITEURI, + "http://example.com/site", + 0, PlacesUtils.annotations.EXPIRE_NEVER); + + let livemark = yield PlacesUtils.livemarks.getLivemark({ guid: folder.guid }); + Assert.equal(folder.guid, livemark.guid); + Assert.equal(folder.dateAdded * 1000, livemark.dateAdded); + Assert.equal(folder.parentGuid, livemark.parentGuid); + Assert.equal(folder.index, livemark.index); + Assert.equal(folder.title, livemark.title); + Assert.equal(id, livemark.id); + Assert.equal(PlacesUtils.unfiledBookmarksFolderId, livemark.parentId); + Assert.equal("http://example.com/feed", livemark.feedURI.spec); + Assert.equal("http://example.com/site", livemark.siteURI.spec); + + yield PlacesUtils.livemarks.removeLivemark(livemark); +}); + add_task(function* test_addLivemark_noArguments_throws() { try { yield PlacesUtils.livemarks.addLivemark(); do_throw("Invoking addLivemark with no arguments should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS); } });
--- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -1986,96 +1986,84 @@ ThreadActor.prototype = { onNewScript: function (aScript, aGlobal) { // XXX: The scripts must be added to the ScriptStore before restoring // breakpoints in _addScript. If we try to add them to the ScriptStore // inside _addScript, we can accidentally set a breakpoint in a top level // script as a "closest match" because we wouldn't have added the child // scripts to the ScriptStore yet. this.scripts.addScripts(this.dbg.findScripts({ source: aScript.source })); - this._addScript(aScript); - - // `onNewScript` is only fired for top-level scripts (AKA staticLevel == 0), - // but top-level scripts have the wrong `lineCount` sometimes (bug 979094), - // so iterate over the immediate children to activate breakpoints for now - // (TODO bug 1124258: don't do this when `lineCount` bug is fixed) - for (let s of aScript.getChildScripts()) { - this._addScript(s); - } + this._addSource(aScript.source); }, onNewSource: function (aSource) { this.conn.send({ from: this.actorID, type: "newSource", source: aSource.form() }); }, /** - * Restore any pre-existing breakpoints to the scripts that we have access to. + * Restore any pre-existing breakpoints to the sources that we have access to. */ _restoreBreakpoints: function () { if (this.breakpointActorMap.size === 0) { return; } - for (let s of this.scripts.getAllScripts()) { - this._addScript(s); + for (let s of this.scripts.getSources()) { + this._addSource(s); } }, /** - * Add the provided script to the server cache. + * Add the provided source to the server cache. * - * @param aScript Debugger.Script - * The source script that will be stored. - * @returns true, if the script was added; false otherwise. + * @param aSource Debugger.Source + * The source that will be stored. + * @returns true, if the source was added; false otherwise. */ - _addScript: function (aScript) { - if (!this.sources.allowSource(aScript.source)) { + _addSource: function (aSource) { + if (!this.sources.allowSource(aSource)) { return false; } // Set any stored breakpoints. let promises = []; - let sourceActor = this.sources.createNonSourceMappedActor(aScript.source); - let endLine = aScript.startLine + aScript.lineCount - 1; + let sourceActor = this.sources.createNonSourceMappedActor(aSource); for (let _actor of this.breakpointActorMap.findActors()) { // XXX bug 1142115: We do async work in here, so we need to // create a fresh binding because for/of does not yet do that in // SpiderMonkey let actor = _actor; if (actor.isPending) { promises.push(actor.originalLocation.originalSourceActor._setBreakpoint(actor)); } else { promises.push(this.sources.getGeneratedLocation(actor.originalLocation) .then((generatedLocation) => { - // Limit the search to the line numbers contained in the new script. - if (generatedLocation.generatedSourceActor.actorID === sourceActor.actorID && - generatedLocation.generatedLine >= aScript.startLine && - generatedLocation.generatedLine <= endLine) { + if (generatedLocation.generatedSourceActor.actorID === sourceActor.actorID) { sourceActor._setBreakpointAtGeneratedLocation( actor, generatedLocation ); } })); } } if (promises.length > 0) { this.synchronize(Promise.all(promises)); } // Go ahead and establish the source actors for this script, which // fetches sourcemaps if available and sends onNewSource // notifications - this.sources.createSourceActors(aScript.source); + this.sources.createSourceActors(aSource); return true; }, /** * Get prototypes and properties of multiple objects. */