--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -69,17 +69,20 @@ const WorkerSandbox = Class({
/**
* Synchronous version of `emit`.
* /!\ Should only be used when it is strictly mandatory /!\
* Doesn't ensure passing only JSON values.
* Mainly used by context-menu in order to avoid breaking it.
*/
emitSync: function emitSync(...args) {
- return emitToContent(this, args);
+ // because the arguments could be also non JSONable values,
+ // we need to ensure the array instance is created from
+ // the content's sandbox
+ return emitToContent(this, new modelFor(this).sandbox.Array(...args));
},
/**
* Configures sandbox and loads content scripts into it.
* @param {Worker} worker
* content worker
*/
initialize: function WorkerSandbox(worker, window) {
--- a/addon-sdk/source/lib/sdk/panel/window.js
+++ b/addon-sdk/source/lib/sdk/panel/window.js
@@ -30,20 +30,24 @@ function getWindow(anchor) {
for (let enumWindow of windows) {
// Check if the anchor is in this browser window.
if (enumWindow == anchorWindow) {
window = anchorWindow;
break;
}
// Check if the anchor is in a browser tab in this browser window.
- let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument);
- if (browser) {
- window = enumWindow;
- break;
+ try {
+ let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument);
+ if (browser) {
+ window = enumWindow;
+ break;
+ }
+ }
+ catch (e) {
}
// Look in other subdocuments (sidebar, etc.)?
}
}
// If we didn't find the anchor's window (or we have no anchor),
// return the most recent browser window.
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -130,16 +130,17 @@ skip-if = os == "linux"
[browser_985815_propagate_setToolbarVisibility.js]
[browser_981305_separator_insertion.js]
[browser_988072_sidebar_events.js]
[browser_989338_saved_placements_not_resaved.js]
[browser_989751_subviewbutton_class.js]
[browser_987177_destroyWidget_xul.js]
[browser_987177_xul_wrapper_updating.js]
+[browser_987185_syncButton.js]
[browser_987492_window_api.js]
[browser_987640_charEncoding.js]
[browser_992747_toggle_noncustomizable_toolbar.js]
[browser_993322_widget_notoolbar.js]
[browser_995164_registerArea_during_customize_mode.js]
[browser_996364_registerArea_different_properties.js]
[browser_996635_remove_non_widgets.js]
[browser_1003588_no_specials_in_panel.js]
new file mode 100755
--- /dev/null
+++ b/browser/components/customizableui/test/browser_987185_syncButton.js
@@ -0,0 +1,69 @@
+/* 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";
+
+let syncService = {};
+Components.utils.import("resource://services-sync/service.js", syncService);
+
+let needsSetup;
+let originalSync;
+let service = syncService.Service;
+let syncWasCalled = false;
+
+add_task(function* testSyncButtonFunctionality() {
+ info("Check Sync button functionality");
+ storeInitialValues();
+ mockFunctions();
+
+ // add the Sync button to the panel
+ CustomizableUI.addWidgetToArea("sync-button", CustomizableUI.AREA_PANEL);
+
+ // check the button's functionality
+ yield PanelUI.show();
+ info("The panel menu was opened");
+
+ let syncButton = document.getElementById("sync-button");
+ ok(syncButton, "The Sync button was added to the Panel Menu");
+ syncButton.click();
+ info("The sync button was clicked");
+
+ yield waitForCondition(() => syncWasCalled);
+});
+
+add_task(function* asyncCleanup() {
+ // reset the panel UI to the default state
+ yield resetCustomization();
+ ok(CustomizableUI.inDefaultState, "The panel UI is in default state again.");
+
+ if (isPanelUIOpen()) {
+ let panelHidePromise = promisePanelHidden(window);
+ PanelUI.hide();
+ yield panelHidePromise;
+ }
+
+ restoreValues();
+});
+
+function mockFunctions() {
+ // mock needsSetup
+ gSyncUI._needsSetup = function() false;
+
+ // mock service.errorHandler.syncAndReportErrors()
+ service.errorHandler.syncAndReportErrors = mocked_syncAndReportErrors;
+}
+
+function mocked_syncAndReportErrors() {
+ syncWasCalled = true;
+}
+
+function restoreValues() {
+ gSyncUI._needsSetup = needsSetup;
+ service.sync = originalSync;
+}
+
+function storeInitialValues() {
+ needsSetup = gSyncUI._needsSetup;
+ originalSync = service.sync;
+}
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -50,17 +50,19 @@ loop.panel = (function(_, mozL10n) {
tabs.push(
React.DOM.div({key: i, className: cx({tab: true, selected: isSelected})},
tab.props.children
)
);
}, this);
return (
React.DOM.div({className: "tab-view-container"},
- React.DOM.ul({className: "tab-view"}, tabButtons),
+ !this.props.buttonsHidden
+ ? React.DOM.ul({className: "tab-view"}, tabButtons)
+ : null,
tabs
)
);
}
});
var Tab = React.createClass({displayName: 'Tab',
render: function() {
@@ -434,16 +436,17 @@ loop.panel = (function(_, mozL10n) {
*/
var PanelView = React.createClass({displayName: 'PanelView',
propTypes: {
notifications: React.PropTypes.object.isRequired,
client: React.PropTypes.object.isRequired,
// Mostly used for UI components showcase and unit tests
callUrl: React.PropTypes.string,
userProfile: React.PropTypes.object,
+ showTabButtons: React.PropTypes.bool,
},
getInitialState: function() {
return {
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
};
},
@@ -470,17 +473,22 @@ loop.panel = (function(_, mozL10n) {
detailsButtonLabel: serviceError.error.friendlyDetailsButtonLabel,
});
} else {
this.props.notifications.remove(this.props.notifications.get("service-error"));
}
},
_onStatusChanged: function() {
- this.setState({userProfile: navigator.mozLoop.userProfile});
+ var profile = navigator.mozLoop.userProfile;
+ if (profile != this.state.userProfile) {
+ // On profile change (login, logout), switch back to the default tab.
+ this.selectTab("call");
+ }
+ this.setState({userProfile: profile});
this.updateServiceErrors();
},
startForm: function(name, contact) {
this.refs[name].initForm(contact);
this.selectTab(name);
},
@@ -503,17 +511,17 @@ loop.panel = (function(_, mozL10n) {
render: function() {
var NotificationListView = sharedViews.NotificationListView;
var displayName = this.state.userProfile && this.state.userProfile.email ||
__("display_name_guest");
return (
React.DOM.div(null,
NotificationListView({notifications: this.props.notifications,
clearOnDocumentHidden: true}),
- TabView({ref: "tabView"},
+ TabView({ref: "tabView", buttonsHidden: !this.state.userProfile && !this.props.showTabButtons},
Tab({name: "call"},
React.DOM.div({className: "content-area"},
CallUrlResult({client: this.props.client,
notifications: this.props.notifications,
callUrl: this.props.callUrl}),
ToSView(null)
)
),
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -50,17 +50,19 @@ loop.panel = (function(_, mozL10n) {
tabs.push(
<div key={i} className={cx({tab: true, selected: isSelected})}>
{tab.props.children}
</div>
);
}, this);
return (
<div className="tab-view-container">
- <ul className="tab-view">{tabButtons}</ul>
+ {!this.props.buttonsHidden
+ ? <ul className="tab-view">{tabButtons}</ul>
+ : null}
{tabs}
</div>
);
}
});
var Tab = React.createClass({
render: function() {
@@ -434,16 +436,17 @@ loop.panel = (function(_, mozL10n) {
*/
var PanelView = React.createClass({
propTypes: {
notifications: React.PropTypes.object.isRequired,
client: React.PropTypes.object.isRequired,
// Mostly used for UI components showcase and unit tests
callUrl: React.PropTypes.string,
userProfile: React.PropTypes.object,
+ showTabButtons: React.PropTypes.bool,
},
getInitialState: function() {
return {
userProfile: this.props.userProfile || navigator.mozLoop.userProfile,
};
},
@@ -470,17 +473,22 @@ loop.panel = (function(_, mozL10n) {
detailsButtonLabel: serviceError.error.friendlyDetailsButtonLabel,
});
} else {
this.props.notifications.remove(this.props.notifications.get("service-error"));
}
},
_onStatusChanged: function() {
- this.setState({userProfile: navigator.mozLoop.userProfile});
+ var profile = navigator.mozLoop.userProfile;
+ if (profile != this.state.userProfile) {
+ // On profile change (login, logout), switch back to the default tab.
+ this.selectTab("call");
+ }
+ this.setState({userProfile: profile});
this.updateServiceErrors();
},
startForm: function(name, contact) {
this.refs[name].initForm(contact);
this.selectTab(name);
},
@@ -503,17 +511,17 @@ loop.panel = (function(_, mozL10n) {
render: function() {
var NotificationListView = sharedViews.NotificationListView;
var displayName = this.state.userProfile && this.state.userProfile.email ||
__("display_name_guest");
return (
<div>
<NotificationListView notifications={this.props.notifications}
clearOnDocumentHidden={true} />
- <TabView ref="tabView">
+ <TabView ref="tabView" buttonsHidden={!this.state.userProfile && !this.props.showTabButtons}>
<Tab name="call">
<div className="content-area">
<CallUrlResult client={this.props.client}
notifications={this.props.notifications}
callUrl={this.props.callUrl} />
<ToSView />
</div>
</Tab>
--- a/browser/components/loop/test/desktop-local/panel_test.js
+++ b/browser/components/loop/test/desktop-local/panel_test.js
@@ -135,17 +135,18 @@ describe("loop.panel", function() {
fakeClient = {
requestCallUrl: function(_, cb) {
cb(null, callUrlData);
}
};
view = TestUtils.renderIntoDocument(loop.panel.PanelView({
notifications: notifications,
- client: fakeClient
+ client: fakeClient,
+ showTabButtons: true,
}));
[callTab, contactsTab] =
TestUtils.scryRenderedDOMComponentsWithClass(view, "tab");
});
describe('TabView', function() {
it("should select contacts tab when clicking tab button", function() {
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -27,18 +27,18 @@ this.Translation = {
STATE_OFFER: 0,
STATE_TRANSLATING: 1,
STATE_TRANSLATED: 2,
STATE_ERROR: 3,
STATE_UNAVAILABLE: 4,
serviceUnavailable: false,
- supportedSourceLanguages: ["de", "en", "es", "fr", "ja", "ko", "pt", "ru", "zh"],
- supportedTargetLanguages: ["de", "en", "es", "fr", "ja", "ko", "pl", "pt", "ru", "tr", "vi", "zh"],
+ supportedSourceLanguages: ["bg", "cs", "de", "en", "es", "fr", "ja", "ko", "nl", "no", "pl", "pt", "ru", "tr", "vi", "zh"],
+ supportedTargetLanguages: ["bg", "cs", "de", "en", "es", "fr", "ja", "ko", "nl", "no", "pl", "pt", "ru", "tr", "vi", "zh"],
_defaultTargetLanguage: "",
get defaultTargetLanguage() {
if (!this._defaultTargetLanguage) {
this._defaultTargetLanguage = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global")
.split("-")[0];
--- a/browser/components/translation/translation-infobar.xml
+++ b/browser/components/translation/translation-infobar.xml
@@ -18,16 +18,31 @@
<resources>
<stylesheet src="chrome://global/skin/notification.css"/>
</resources>
<content>
<xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type">
<xul:hbox anonid="details" align="center" flex="1">
<xul:image class="translate-infobar-element messageImage"
anonid="messageImage"/>
+ <xul:panel anonid="welcomePanel" class="translation-welcome-panel"
+ type="arrow" align="start">
+ <xul:image class="translation-welcome-logo"/>
+ <xul:vbox flex="1" class="translation-welcome-content">
+ <xul:description class="translation-welcome-headline"
+ anonid="welcomeHeadline"/>
+ <xul:description class="translation-welcome-body" anonid="welcomeBody"/>
+ <xul:hbox align="center">
+ <xul:label anonid="learnMore" class="plain text-link"/>
+ <xul:spacer flex="1"/>
+ <xul:button class="translate-infobar-element" anonid="thanksButton"
+ onclick="this.parentNode.parentNode.parentNode.hidePopup();"/>
+ </xul:hbox>
+ </xul:vbox>
+ </xul:panel>
<xul:deck anonid="translationStates" selectedIndex="0">
<!-- offer to translate -->
<xul:hbox class="translate-offer-box" align="center">
<xul:label class="translate-infobar-element" value="&translation.thisPageIsIn.label;"/>
<xul:menulist class="translate-infobar-element" anonid="detectedLanguage">
<xul:menupopup/>
</xul:menulist>
@@ -193,16 +208,51 @@
for (let [code, name] of targetLanguages)
toLanguage.appendItem(name, code);
if (aTranslation.translatedTo)
toLanguage.value = aTranslation.translatedTo;
if (aTranslation.state)
this.state = aTranslation.state;
+
+ const kWelcomePref = "browser.translation.ui.welcomeMessageShown";
+ if (Services.prefs.prefHasUserValue(kWelcomePref))
+ return;
+
+ this.addEventListener("transitionend", function onShown() {
+ this.removeEventListener("transitionend", onShown);
+
+ // These strings are hardcoded because they need to reach beta
+ // without riding the trains.
+ let localizedStrings = {
+ en: ["Hey look! It's something new!",
+ "Now the Web is even more accessible with our new in-page translation feature. Click the translate button to try it!",
+ "Learn more.",
+ "Thanks"]
+ };
+
+ let locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry)
+ .getSelectedLocale("browser");
+ if (!(locale in localizedStrings))
+ locale = "en";
+ let strings = localizedStrings[locale];
+
+ this._getAnonElt("welcomeHeadline").setAttribute("value", strings[0]);
+ this._getAnonElt("welcomeBody").textContent = strings[1];
+ this._getAnonElt("learnMore").setAttribute("value", strings[2]);
+ this._getAnonElt("thanksButton").setAttribute("label", strings[3]);
+
+ let panel = this._getAnonElt("welcomePanel");
+ panel.openPopup(this._getAnonElt("messageImage"),
+ "bottomcenter topleft");
+
+ Services.prefs.setBoolPref(kWelcomePref, true);
+ });
]]>
</body>
</method>
<method name="_getAnonElt">
<parameter name="aAnonId"/>
<body>
return document.getAnonymousElementByAttribute(this, "anonid", aAnonId);
--- a/browser/locales/en-US/chrome/browser/devtools/webide.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/webide.properties
@@ -14,17 +14,17 @@ local_runtime=Local Runtime
remote_runtime=Remote Runtime
remote_runtime_promptTitle=Remote Runtime
remote_runtime_promptMessage=hostname:port
importPackagedApp_title=Select Directory
importHostedApp_title=Open Hosted App
importHostedApp_header=Enter Manifest URL
-notification_showTroubleShooting_label=troubleshooting
+notification_showTroubleShooting_label=Troubleshooting
notification_showTroubleShooting_accesskey=t
# LOCALIZATION NOTE (project_tab_loading): This is shown as a temporary tab
# title for browser tab projects when the tab is still loading.
project_tab_loading=Loading…
# These messages appear in a notification box when an error occur.
--- a/browser/themes/shared/translation/infobar.inc.css
+++ b/browser/themes/shared/translation/infobar.inc.css
@@ -59,8 +59,33 @@ notification[value="translation"] menuli
.translation-attribution > label {
margin-bottom: 0;
}
.translation-attribution > image {
width: 70px;
}
+
+.translation-welcome-panel {
+ width: 305px;
+}
+
+.translation-welcome-logo {
+ height: 32px;
+ width: 32px;
+ list-style-image: url(chrome://browser/skin/translation-16@2x.png);
+ -moz-image-region: rect(0, 64px, 32px, 32px);
+}
+
+.translation-welcome-content {
+ -moz-margin-start: 16px;
+}
+
+.translation-welcome-headline {
+ font-size: larger;
+ font-weight: bold;
+}
+
+.translation-welcome-body {
+ padding: 1em 0;
+ margin: 0 0;
+}
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -17,17 +17,17 @@
# throws an error (and does not cause a crash or hang), just add it to
# gErrorTests in manifest.js.
# To test for a specific bug in handling a specific resource type, make the
# test first check canPlayType for the type, and if it's not supported, just
# do ok(true, "Type not supported") and stop the test.
[DEFAULT]
-skip-if = buildapp == 'mulet' || contentSandbox != 'off' # contentSandbox(Bug 1042735)
+skip-if = buildapp == 'mulet'
support-files =
320x240.ogv
320x240.ogv^headers^
448636.ogv
448636.ogv^headers^
VID_0001.ogg
VID_0001.ogg^headers^
allowed.sjs
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -1,10 +1,10 @@
[DEFAULT]
-skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || contentSandbox != 'off' #b2g-debug,b2g-desktop(bug 916135); contentSandbox(Bug 1042735)
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
support-files =
audio-expected.wav
audio-mono-expected-2.wav
audio-mono-expected.wav
audio-quad.wav
audio.ogv
audioBufferSourceNodeNeutered_worker.js
invalid.txt
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,10 +1,9 @@
[DEFAULT]
-skip-if = contentSandbox != 'off' # contentSandbox(Bug 1042735)
support-files =
head.js
constraints.js
mediaStreamPlayback.js
pc.js
templates.js
NetworkPreparationChromeScript.js
blacksilence.js
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -18,20 +18,18 @@
#include ../services/manifests/FxAccountAndroidManifest_permissions.xml.in
#include ../services/manifests/HealthReportAndroidManifest_permissions.xml.in
#include ../services/manifests/SyncAndroidManifest_permissions.xml.in
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
#include ../search/manifests/SearchAndroidManifest_permissions.xml.in
#endif
-#ifndef RELEASE_BUILD
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
-#endif
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
--- a/mobile/android/base/home/TwoLinePageRow.java
+++ b/mobile/android/base/home/TwoLinePageRow.java
@@ -2,17 +2,19 @@
* 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.home;
import java.lang.ref.WeakReference;
+import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.R;
+import org.mozilla.gecko.ReaderModeUtils;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserContract.URLColumns;
import org.mozilla.gecko.favicons.Favicons;
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
import org.mozilla.gecko.widget.FaviconView;
@@ -243,17 +245,22 @@ public class TwoLinePageRow extends Line
// No point updating the below things if URL has not changed. Prevents evil Favicon flicker.
if (url.equals(mPageUrl)) {
return;
}
// Blank the Favicon, so we don't show the wrong Favicon if we scroll and miss DB.
mFavicon.clearImage();
Favicons.cancelFaviconLoad(mLoadFaviconJobId);
- mLoadFaviconJobId = Favicons.getSizedFaviconForPageFromLocal(getContext(), url, mFaviconListener);
+
+ // Displayed RecentTabsPanel urls may refer to pages openned in readermode, so we
+ // remove the about:reader prefix to ensure the Favicon loads properly.
+ final String pageURL = AboutPages.isAboutReader(url) ?
+ ReaderModeUtils.getUrlFromAboutReader(url) : url;
+ mLoadFaviconJobId = Favicons.getSizedFaviconForPageFromLocal(getContext(), pageURL, mFaviconListener);
updateDisplayedUrl(url);
}
/**
* Update the data displayed by this row.
* <p>
* This method must be invoked on the UI thread.
--- a/mobile/android/base/locales/Makefile.in
+++ b/mobile/android/base/locales/Makefile.in
@@ -110,21 +110,23 @@ endef
# L10NBASEDIR is not defined for en-US.
l10n-srcdir := $(if $(filter en-US,$(AB_CD)),,$(or $(realpath $(L10NBASEDIR)),$(abspath $(L10NBASEDIR)))/$(AB_CD)/mobile/chrome)
$(eval $(call generated_file_template,suggestedsites,suggestedsites.json))
$(suggestedsites-dstdir-raw)/suggestedsites.json: FORCE
$(call py_action,generate_suggestedsites, \
+ --verbose \
--android-package-name=$(ANDROID_PACKAGE_NAME) \
--resources=$(srcdir)/../resources \
$(if $(filter en-US,$(AB_CD)),,--srcdir=$(l10n-srcdir)) \
--srcdir=$(topsrcdir)/mobile/locales/en-US/chrome \
$@)
$(eval $(call generated_file_template,browsersearch,browsersearch.json))
$(browsersearch-dstdir-raw)/browsersearch.json: FORCE
$(call py_action,generate_browsersearch, \
+ --verbose \
$(if $(filter en-US,$(AB_CD)),,--srcdir=$(l10n-srcdir)) \
--srcdir=$(topsrcdir)/mobile/locales/en-US/chrome \
$@)
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -522,16 +522,31 @@ var Addons = {
element = this._createItemForAddon(aAddon);
list.insertBefore(element, list.firstElementChild);
}
if (needsRestart)
element.setAttribute("opType", "needs-restart");
},
+ onInstalled: function(aAddon) {
+ let list = document.getElementById("addons-list");
+ let element = this._getElementForAddon(aAddon.id);
+ if (!element) {
+ element = this._createItemForAddon(aAddon);
+ list.insertBefore(element, list.firstElementChild);
+ }
+ },
+
+ onUninstalled: function(aAddon) {
+ let list = document.getElementById("addons-list");
+ let element = this._getElementForAddon(aAddon.id);
+ list.removeChild(element);
+ },
+
onInstallFailed: function(aInstall) {
},
onDownloadProgress: function xpidm_onDownloadProgress(aInstall) {
},
onDownloadFailed: function(aInstall) {
},
--- a/mobile/android/chrome/content/aboutApps.xhtml
+++ b/mobile/android/chrome/content/aboutApps.xhtml
@@ -30,17 +30,16 @@
<body dir="&locale.dir;">
<menu type="context" id="appmenu">
<menuitem id="uninstallLabel" label="&aboutApps.uninstall;"></menuitem>
</menu>
<div class="header">
<div>&aboutApps.header;</div>
- <div id="header-button" role="button" aria-label="&aboutApps.browseMarketplace;" pref="app.marketplaceURL"/>
</div>
<div id="main-container" class="hidden">
<div>
<div class="spacer" id="spacer1"> </div>
<div id="appgrid"/>
<div class="spacer" id="spacer1"> </div>
</div>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -824,16 +824,23 @@ var BrowserApp = {
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");
}
+
+ // 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();
+ }
},
shutdown: function shutdown() {
NativeWindow.uninit();
LightWeightThemeWebInstaller.uninit();
FormAssistant.uninit();
IndexedDB.uninit();
ViewportHandler.uninit();
@@ -6904,16 +6911,20 @@ var SearchEngines = {
}
break;
default:
dump("Unexpected message type observed: " + aTopic);
break;
}
},
+ migrateSearchActivityDefaultPref: function migrateSearchActivityDefaultPref() {
+ Services.search.init(() => this._setSearchActivityDefaultPref(Services.search.defaultEngine));
+ },
+
// Updates the search activity pref when the default engine changes.
_setSearchActivityDefaultPref: function _setSearchActivityDefaultPref(engine) {
// Helper function copied from nsSearchService.js. This is the logic that is used
// to create file names for search plugin XML serialized to disk.
function sanitizeName(aName) {
const maxLength = 60;
const minLength = 1;
let name = aName.toLowerCase();
--- a/mobile/android/themes/core/aboutApps.css
+++ b/mobile/android/themes/core/aboutApps.css
@@ -1,23 +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/. */
.app:active {
background-color: #febc2b;
}
-#header-button {
- background-image: url("chrome://browser/skin/images/marketplace-logo.png"), url("chrome://browser/skin/images/chevron.png");
- background-size: 32px 32px, 8px 20px;
- background-position: left, right 0.5em center;
- -moz-padding-start: 2.5em;
-}
-
#main-container {
padding: 2em;
background-color: #EEF2F5;
border-bottom: 1px solid #BAC2AC;
}
.hidden {
display: none;
--- a/python/moz.build
+++ b/python/moz.build
@@ -18,16 +18,17 @@ PYTHON_UNIT_TESTS += [
'mach/mach/test/test_config.py',
'mach/mach/test/test_entry_point.py',
'mach/mach/test/test_error_output.py',
'mach/mach/test/test_logger.py',
'mozbuild/dumbmake/test/__init__.py',
'mozbuild/dumbmake/test/test_dumbmake.py',
'mozbuild/mozbuild/test/__init__.py',
'mozbuild/mozbuild/test/action/test_buildlist.py',
+ 'mozbuild/mozbuild/test/action/test_generate_browsersearch.py',
'mozbuild/mozbuild/test/backend/__init__.py',
'mozbuild/mozbuild/test/backend/common.py',
'mozbuild/mozbuild/test/backend/test_android_eclipse.py',
'mozbuild/mozbuild/test/backend/test_configenvironment.py',
'mozbuild/mozbuild/test/backend/test_recursivemake.py',
'mozbuild/mozbuild/test/backend/test_visualstudio.py',
'mozbuild/mozbuild/test/common.py',
'mozbuild/mozbuild/test/compilation/__init__.py',
--- a/python/mozbuild/mozbuild/action/generate_browsersearch.py
+++ b/python/mozbuild/mozbuild/action/generate_browsersearch.py
@@ -17,19 +17,23 @@ 2. Read the default search plugin from t
3. Read the list of search plugins from the 'browser.search.order.INDEX'
properties with values identifying particular search plugins by name.
4. Generate a JSON representation of 2. and 3., and write the result to
browsersearch.json in the locale-specific raw resource directory
e.g. raw/browsersearch.json, raw-pt-rBR/browsersearch.json.
'''
-from __future__ import print_function
+from __future__ import (
+ print_function,
+ unicode_literals,
+)
import argparse
+import codecs
import json
import re
import sys
import os
from mozbuild.dotproperties import (
DotProperties,
)
@@ -67,18 +71,19 @@ def main(args):
# Use reversed order so that the first srcdir has higher priority to override keys.
properties = merge_properties('region.properties', reversed(opts.srcdir))
default = properties.get('browser.search.defaultenginename')
engines = properties.get_list('browser.search.order')
if opts.verbose:
- print('Read {len} engines: {engines}'.format(len=len(engines), engines=engines))
- print("Default engine is '{default}'.".format(default=default))
+ writer = codecs.getwriter('utf-8')(sys.stdout)
+ print('Read {len} engines: {engines}'.format(len=len(engines), engines=engines), file=writer)
+ print("Default engine is '{default}'.".format(default=default), file=writer)
browsersearch = {}
browsersearch['default'] = default
browsersearch['engines'] = engines
# FileAvoidWrite creates its parent directories.
output = os.path.abspath(opts.output)
fh = FileAvoidWrite(output)
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/invalid/region.properties
@@ -0,0 +1,12 @@
+# A region.properties file with invalid unicode byte sequences. The
+# sequences were cribbed from Markus Kuhn's "UTF-8 decoder capability
+# and stress test", available at
+# http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+
+# 3.5 Impossible bytes |
+# |
+# The following two bytes cannot appear in a correct UTF-8 string |
+# |
+# 3.5.1 fe = "þ" |
+# 3.5.2 ff = "ÿ" |
+# 3.5.3 fe fe ff ff = "þþÿÿ" |
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/data/valid-zh-CN/region.properties
@@ -0,0 +1,37 @@
+# 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/.
+
+# Default search engine
+browser.search.defaultenginename=百度
+
+# Search engine order (order displayed in the search bar dropdown)s
+browser.search.order.1=百度
+browser.search.order.2=Google
+
+# This is the default set of web based feed handlers shown in the reader
+# selection UI
+browser.contentHandlers.types.0.title=Bloglines
+browser.contentHandlers.types.0.uri=http://www.bloglines.com/login?r=/sub/%s
+
+# increment this number when anything gets changed in the list below. This will
+# cause Firefox to re-read these prefs and inject any new handlers into the
+# profile database. Note that "new" is defined as "has a different URL"; this
+# means that it's not possible to update the name of existing handler, so
+# don't make any spelling errors here.
+gecko.handlerService.defaultHandlersVersion=3
+
+# The default set of protocol handlers for webcal:
+gecko.handlerService.schemes.webcal.0.name=30 Boxes
+gecko.handlerService.schemes.webcal.0.uriTemplate=https://30boxes.com/external/widget?refer=ff&url=%s
+
+# The default set of protocol handlers for mailto:
+gecko.handlerService.schemes.mailto.0.name=Yahoo! 邮件
+gecko.handlerService.schemes.mailto.0.uriTemplate=https://compose.mail.yahoo.com/?To=%s
+gecko.handlerService.schemes.mailto.1.name=Gmail
+gecko.handlerService.schemes.mailto.1.uriTemplate=https://mail.google.com/mail/?extsrc=mailto&url=%s
+
+# This is the default set of web based feed handlers shown in the reader
+# selection UI
+browser.contentHandlers.types.0.title=My Yahoo!
+browser.contentHandlers.types.0.uri=http://www.bloglines.com/login?r=/sub/%s
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from __future__ import unicode_literals
+
+import json
+import os
+import unittest
+
+import mozunit
+
+import mozbuild.action.generate_browsersearch as generate_browsersearch
+
+from mozfile.mozfile import (
+ NamedTemporaryFile,
+ TemporaryDirectory,
+)
+
+import mozpack.path as mozpath
+
+
+test_data_path = mozpath.abspath(mozpath.dirname(__file__))
+test_data_path = mozpath.join(test_data_path, 'data')
+
+
+class TestGenerateBrowserSearch(unittest.TestCase):
+ """
+ Unit tests for generate_browsersearch.py.
+ """
+
+ def _test_one(self, name):
+ with TemporaryDirectory() as tmpdir:
+ with NamedTemporaryFile(mode='r+') as temp:
+ srcdir = os.path.join(test_data_path, name)
+
+ generate_browsersearch.main([
+ '--verbose',
+ '--srcdir', srcdir,
+ temp.name])
+ return json.load(temp)
+
+ def test_valid_unicode(self):
+ o = self._test_one('valid-zh-CN')
+ self.assertEquals(o['default'], '百度')
+ self.assertEquals(o['engines'], ['百度', 'Google'])
+
+ def test_invalid_unicode(self):
+ with self.assertRaises(UnicodeDecodeError):
+ self._test_one('invalid')
+
+
+if __name__ == '__main__':
+ mozunit.main()
--- a/toolkit/components/places/PlacesSearchAutocompleteProvider.jsm
+++ b/toolkit/components/places/PlacesSearchAutocompleteProvider.jsm
@@ -59,16 +59,17 @@ const SearchAutocompleteProviderInternal
initialized: false,
observe: function (subject, topic, data) {
switch (data) {
case "engine-added":
case "engine-changed":
case "engine-removed":
+ case "engine-current":
this._refresh();
}
},
_refresh: function () {
this.priorityMatches = [];
this.aliasMatches = [];
this.defaultMatch = null;
--- a/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_current.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_current.js
@@ -26,10 +26,22 @@ add_task(function*() {
do_log_info("search engine, multiple words");
yield check_autocomplete({
search: "mozzarella cheese",
searchParam: "enable-actions",
matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch", input: "mozzarella cheese", searchQuery: "mozzarella cheese"}), title: "MozSearch" }, ]
});
+ do_log_info("search engine, after current engine has changed");
+ Services.search.addEngineWithDetails("MozSearch2", "", "", "", "GET",
+ "http://s.example.com/search2");
+ engine = Services.search.getEngineByName("MozSearch2");
+ notEqual(Services.search.currentEngine, engine, "New engine shouldn't be the current engine yet");
+ Services.search.currentEngine = engine;
+ yield check_autocomplete({
+ search: "mozilla",
+ searchParam: "enable-actions",
+ matches: [ { uri: makeActionURI("searchengine", {engineName: "MozSearch2", input: "mozilla", searchQuery: "mozilla"}), title: "MozSearch2" }, ]
+ });
+
yield cleanup();
});
\ No newline at end of file