Merge m-c to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-05-02 14:55:29 +02:00
commit 6361ce02c7
51 changed files with 2323 additions and 139 deletions

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
@ -102,7 +102,7 @@
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="d7755abaf703f86228e3938a3e204121b254638d"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="10977f28df27f79534f079c0a9852b21a5a0f6da"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a054c7385854b0e71b8d3071a465b9bc21581ee0"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="65fba428f8d76336b33ddd9e15900357953600ba">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="ca283b9db2b151d465cfd2e19346cf58fe89e413"/>
@ -102,7 +102,7 @@
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="d7755abaf703f86228e3938a3e204121b254638d"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="10977f28df27f79534f079c0a9852b21a5a0f6da"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -18,7 +18,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a054c7385854b0e71b8d3071a465b9bc21581ee0"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "689e41080c6c21f0d2b51363304776c70967c9c5",
"revision": "2796d30073cc12313afc0deef9d7700d25acdc77",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a054c7385854b0e71b8d3071a465b9bc21581ee0"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="386b5478eb9c3970972966123517e993e8a1092a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e3fc29c5d4a9196b0e32e246f3d0150ae0c39221"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f313e6d3aaaefe8c82eaed15912a09b120fb7260"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

View File

@ -52,11 +52,12 @@ function init(aEvent)
#ifdef MOZ_UPDATER
gAppUpdater = new appUpdater();
#if MOZ_UPDATE_CHANNEL != release
let defaults = Services.prefs.getDefaultBranch("");
let channelLabel = document.getElementById("currentChannel");
let currentChannelText = document.getElementById("currentChannelText");
channelLabel.value = defaults.getCharPref("app.update.channel");
#endif
if (channelLabel.value == "release")
currentChannelText.hidden = true;
#endif
#ifdef XP_MACOSX

View File

@ -108,12 +108,10 @@
#endif
</vbox>
#if MOZ_UPDATE_CHANNEL != release
#ifdef MOZ_UPDATER
<description class="text-blurb" id="currentChannelText">
&channel.description.start;<label id="currentChannel"/>&channel.description.end;
</description>
#endif
#endif
<vbox id="experimental" hidden="true">
<description class="text-blurb" id="warningDesc">

View File

@ -5,6 +5,7 @@ MARIONETTE_TIMEOUT = 30000;
MARIONETTE_HEAD_JS = 'head.js';
let MANIFEST_URL = "app://system.gaiamobile.org/manifest.webapp";
let INCORRECT_MANIFEST_URL = "app://xyz.gaiamobile.org/manifest.webapp";
function peerReadyCb(evt) {
log("peerReadyCb called");
@ -25,6 +26,7 @@ function handleTechnologyDiscoveredRE0(msg) {
let request = nfc.checkP2PRegistration(MANIFEST_URL);
request.onsuccess = function (evt) {
is(request.result, true, "check for P2P registration result");
nfc.notifyUserAcceptedP2P(MANIFEST_URL);
}
@ -34,6 +36,29 @@ function handleTechnologyDiscoveredRE0(msg) {
}
}
function handleTechnologyDiscoveredRE0ForP2PRegFailure(msg) {
log("Received \'nfc-manager-tech-discovered\'");
is(msg.type, "techDiscovered", "check for correct message type");
is(msg.techList[0], "P2P", "check for correct tech type");
nfc.onpeerready = peerReadyCb;
let request = nfc.checkP2PRegistration(INCORRECT_MANIFEST_URL);
request.onsuccess = function (evt) {
is(request.result, false, "check for P2P registration result");
nfc.onpeerready = null;
toggleNFC(false, runNextTest);
}
request.onerror = function () {
ok(false, "checkP2PRegistration failed.");
nfc.onpeerready = null;
toggleNFC(false, runNextTest);
}
}
function activateRE(re) {
let deferred = Promise.defer();
let cmd = "nfc ntf rf_intf_activated " + re;
@ -55,8 +80,18 @@ function testPeerReady() {
});
}
function testCheckP2PRegFailure() {
window.navigator.mozSetMessageHandler(
"nfc-manager-tech-discovered", handleTechnologyDiscoveredRE0ForP2PRegFailure);
toggleNFC(true, function() {
activateRE(0);
});
}
let tests = [
testPeerReady
testPeerReady,
testCheckP2PRegFailure
];
SpecialPowers.pushPermissions(

View File

@ -307,6 +307,24 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
(event === (NFC.NFC_PEER_EVENT_READY | NFC.NFC_PEER_EVENT_LOST)));
},
checkP2PRegistration: function checkP2PRegistration(msg) {
// Check if the session and application id yeild a valid registered
// target. It should have registered for NFC_PEER_EVENT_READY
let isValid = !!this.nfc.sessionTokenMap[this.nfc._currentSessionId] &&
this.isRegisteredP2PTarget(msg.json.appId,
NFC.NFC_PEER_EVENT_READY);
// Remember the current AppId if registered.
this.currentPeerAppId = (isValid) ? msg.json.appId : null;
let status = (isValid) ? NFC.GECKO_NFC_ERROR_SUCCESS :
NFC.GECKO_NFC_ERROR_GENERIC_FAILURE;
// Notify the content process immediately of the status
msg.target.sendAsyncMessage(msg.name + "Response", {
status: status,
requestId: msg.json.requestId
});
},
/**
* nsIMessageListener interface methods.
*/
@ -360,19 +378,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
this.unregisterPeerTarget(msg);
return null;
case "NFC:CheckP2PRegistration":
// Check if the application id is a valid registered target.
// (It should have registered for NFC_PEER_EVENT_READY).
let isRegistered = this.isRegisteredP2PTarget(msg.json.appId,
NFC.NFC_PEER_EVENT_READY);
// Remember the current AppId if registered.
this.currentPeerAppId = (isRegistered) ? msg.json.appId : null;
let status = (isRegistered) ? NFC.GECKO_NFC_ERROR_SUCCESS :
NFC.GECKO_NFC_ERROR_GENERIC_FAILURE;
// Notify the content process immediately of the status
msg.target.sendAsyncMessage(msg.name + "Response", {
status: status,
requestId: msg.json.requestId
});
this.checkP2PRegistration(msg);
return null;
case "NFC:NotifyUserAcceptedP2P":
// Notify the 'NFC_PEER_EVENT_READY' since user has acknowledged

View File

@ -407,11 +407,13 @@ NfcContentHelper.prototype = {
case "NFC:GetDetailsNDEFResponse":
this.handleGetDetailsNDEFResponse(result);
break;
case "NFC:CheckP2PRegistrationResponse":
this.handleCheckP2PRegistrationResponse(result);
break;
case "NFC:ConnectResponse": // Fall through.
case "NFC:CloseResponse":
case "NFC:WriteNDEFResponse":
case "NFC:MakeReadOnlyNDEFResponse":
case "NFC:CheckP2PRegistrationResponse":
case "NFC:NotifySendFileStatusResponse":
case "NFC:ConfigResponse":
if (result.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
@ -468,6 +470,13 @@ NfcContentHelper.prototype = {
let result = new GetDetailsNDEFResponse(result);
this.fireRequestSuccess(requestId, result);
},
handleCheckP2PRegistrationResponse: function handleCheckP2PRegistrationResponse(result) {
// Privilaged status API. Always fire success to avoid using exposed props.
// The receiver must check the boolean mapped status code to handle.
let requestId = atob(result.requestId);
this.fireRequestSuccess(requestId, result.status == NFC.GECKO_NFC_ERROR_SUCCESS);
},
};
if (NFC_ENABLED) {

View File

@ -18,6 +18,8 @@ import org.mozilla.gecko.AndroidGamepadManager;
import org.mozilla.gecko.DynamicToolbar.PinReason;
import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.db.BrowserContract.Combined;
@ -485,6 +487,8 @@ abstract public class BrowserApp extends GeckoApp
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
// Show the target URL immediately in the toolbar.
mBrowserToolbar.setTitle(intent.getDataString());
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
}
((GeckoApp.MainLayout) mMainLayout).setTouchEventInterceptor(new HideTabsTouchListener());
@ -643,6 +647,12 @@ abstract public class BrowserApp extends GeckoApp
if (isHomePagerVisible()) {
mHomePager.onToolbarFocusChange(hasFocus);
}
if (hasFocus) {
Telemetry.startUISession(TelemetryContract.Session.URLBAR_FOCUSED);
} else {
Telemetry.stopUISession(TelemetryContract.Session.URLBAR_FOCUSED);
}
}
});
@ -751,6 +761,7 @@ abstract public class BrowserApp extends GeckoApp
String text = Clipboard.getText();
if (!TextUtils.isEmpty(text)) {
Tabs.getInstance().loadUrl(text);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU);
}
return true;
}
@ -942,6 +953,9 @@ abstract public class BrowserApp extends GeckoApp
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, tab.getDisplayTitle());
// Context: Sharing via chrome list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
}
@Override
@ -1613,6 +1627,8 @@ abstract public class BrowserApp extends GeckoApp
// If the URL doesn't look like a search query, just load it.
if (!StringUtils.isSearchQuery(url, true)) {
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
return;
}
@ -1638,6 +1654,7 @@ abstract public class BrowserApp extends GeckoApp
// using the default search engine.
if (TextUtils.isEmpty(keywordUrl)) {
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
return;
}
@ -1646,6 +1663,7 @@ abstract public class BrowserApp extends GeckoApp
// Otherwise, construct a search query from the bookmark keyword.
final String searchUrl = keywordUrl.replace("%s", URLEncoder.encode(keywordSearch));
Tabs.getInstance().loadUrl(searchUrl, Tabs.LOADURL_USER_ENTERED);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, "", "keyword");
}
});
}
@ -2538,9 +2556,11 @@ abstract public class BrowserApp extends GeckoApp
return;
}
// Dismiss editing mode if the user is loading a URL from an external app.
if (Intent.ACTION_VIEW.equals(action)) {
// Dismiss editing mode if the user is loading a URL from an external app.
mBrowserToolbar.cancelEdit();
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT);
return;
}

View File

@ -607,6 +607,9 @@ public abstract class GeckoApp
} else if (event.equals("Share:Text")) {
String text = message.getString("text");
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, "");
// Context: Sharing via chrome list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
} else if (event.equals("Image:SetAs")) {
String src = message.getString("url");
setImageAs(src);

View File

@ -30,8 +30,22 @@ public interface TelemetryContract {
// Set default panel.
public static final String PANEL_SET_DEFAULT = "setdefault.1";
// Sharing content.
public static final String SHARE = "share.1";
// Sanitizing private data.
public static final String SANITIZE = "sanitize.1";
// Saving a resource (reader, bookmark, etc) for viewing later.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String SAVE = "save.1";
// Stop holding a resource (reader, bookmark, etc) for viewing later.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String UNSAVE = "unsave.1";
// Loading a URL.
public static final String LOAD_URL = "loadurl.1";
}
/**
@ -39,8 +53,29 @@ public interface TelemetryContract {
* Telemetry.sendUIEvent() as the "method" parameter.
*/
public interface Method {
// Action triggered from a list.
public static final String LIST = "list";
// Action triggered from a button.
public static final String BUTTON = "button";
// Action triggered from a dialog.
public static final String DIALOG = "dialog";
// Action occurred via an intent.
public static final String INTENT = "intent";
// Action occurred via a context menu.
public static final String CONTEXT_MENU = "contextmenu";
// Action triggered from a view grid item, like a thumbnail.
public static final String GRID_ITEM = "griditem";
// Action triggered from a view list item, like a row of a list.
public static final String LIST_ITEM = "listitem";
// Action triggered from a suggestion provided to the user.
public static final String SUGGESTION = "suggestion";
}
/**
@ -54,6 +89,16 @@ public interface TelemetryContract {
// Started when a user enters a given home panel.
// Session name is dynamic, encoded as "homepanel.1:<panel_id>"
public static final String HOME_PANEL = "homepanel.1:";
// Started when a Reader viewer becomes active in the foreground.
// Note: Only used in JavaScript for now, but here for completeness.
public static final String READER = "reader.1";
// URL bar focused.
public static final String URLBAR_FOCUSED = "urlbar.1:";
// Awesomescreen frecency search is active.
public static final String FRECENCY = "frecency.1:";
}
/**

View File

@ -8,6 +8,8 @@ package org.mozilla.gecko.home;
import java.util.EnumSet;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@ -91,6 +93,8 @@ public class BookmarksListView extends HomeListView
// Otherwise, just open the URL
final String url = cursor.getString(cursor.getColumnIndexOrThrow(URLColumns.URL));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
// This item is a TwoLinePageRow, so we allow switch-to-tab.
getOnUrlOpenListener().onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
}

View File

@ -11,6 +11,8 @@ import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.SearchEngine;
@ -220,6 +222,20 @@ public class BrowserSearch extends HomeFragment
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
@Override
public void onResume() {
super.onResume();
Telemetry.startUISession(TelemetryContract.Session.FRECENCY);
}
@Override
public void onPause() {
super.onPause();
Telemetry.stopUISession(TelemetryContract.Session.FRECENCY);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// All list views are styled to look the same with a global activity theme.
@ -264,6 +280,11 @@ public class BrowserSearch extends HomeFragment
final Cursor c = mAdapter.getCursor(position);
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
// The "urlbar" and "frecency" sessions can be open at the same time. Use the LIST_ITEM
// method to set this LOAD_URL event apart from the case where the user commits what's in
// the url bar.
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM);
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
}

View File

@ -12,6 +12,8 @@ import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ReaderModeUtils;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.Favicons;
@ -132,6 +134,9 @@ abstract class HomeFragment extends Fragment {
} else {
GeckoAppShell.openUriExternal(info.url, SHARE_MIME_TYPE, "", "",
Intent.ACTION_SEND, info.getDisplayTitle());
// Context: Sharing via chrome homepage contextmenu list (home session should be active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
return true;
}
}
@ -157,6 +162,8 @@ abstract class HomeFragment extends Fragment {
if (item.getItemId() == R.id.home_open_private_tab)
flags |= Tabs.LOADURL_PRIVATE;
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.CONTEXT_MENU);
final String url = (info.isInReadingList() ? ReaderModeUtils.getAboutReaderForUrl(info.url) : info.url);
// Some pinned site items have "user-entered" urls. URLs entered in the PinSiteDialog are wrapped in

View File

@ -9,6 +9,8 @@ import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.R;
import org.mozilla.gecko.SessionParser;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.home.HomePager.OnNewTabsListener;
@ -110,6 +112,8 @@ public class LastTabsPanel extends HomeFragment {
return;
}
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
final String url = c.getString(c.getColumnIndexOrThrow(Combined.URL));
mNewTabsListener.onNewTabs(new String[] { url });
}
@ -206,6 +210,8 @@ public class LastTabsPanel extends HomeFragment {
urls[c.getPosition()] = c.getString(c.getColumnIndexOrThrow(Combined.URL));
} while (c.moveToNext());
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.BUTTON);
mNewTabsListener.onNewTabs(urls);
}

View File

@ -9,6 +9,8 @@ import java.util.Date;
import java.util.EnumSet;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
@ -98,6 +100,8 @@ public class MostRecentPanel extends HomeFragment {
final Cursor c = mAdapter.getCursor(position);
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
}

View File

@ -9,6 +9,8 @@ import java.util.EnumSet;
import org.mozilla.gecko.R;
import org.mozilla.gecko.ReaderModeUtils;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
@ -105,6 +107,8 @@ public class ReadingListPanel extends HomeFragment {
String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
url = ReaderModeUtils.getAboutReaderForUrl(url);
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL);
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
}

View File

@ -6,6 +6,8 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.home.BrowserSearch.OnEditSuggestionListener;
import org.mozilla.gecko.home.BrowserSearch.OnSearchListener;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@ -79,9 +81,16 @@ class SearchEngineRow extends AnimatedHeightLayout {
// search for the term.
if (v != mUserEnteredView && !StringUtils.isSearchQuery(suggestion, false)) {
if (mUrlOpenListener != null) {
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "url");
mUrlOpenListener.onUrlOpen(suggestion, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
}
} else if (mSearchListener != null) {
if (v == mUserEnteredView) {
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
} else {
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "engine");
}
mSearchListener.onSearch(mSearchEngine, suggestion);
}
}
@ -135,6 +144,7 @@ class SearchEngineRow extends AnimatedHeightLayout {
public void performUserEnteredSearch() {
String searchTerm = getSuggestionTextFromView(mUserEnteredView);
if (mSearchListener != null) {
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.SUGGESTION, "user");
mSearchListener.onSearch(mSearchEngine, searchTerm);
}
}

View File

@ -8,6 +8,8 @@ package org.mozilla.gecko.home;
import java.util.EnumSet;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.ThumbnailHelper;
import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.db.TopSitesCursorWrapper;
@ -110,6 +112,8 @@ public class TopSitesGridView extends GridView {
// If not, navigate to the page given by the url.
if (!TextUtils.isEmpty(url)) {
if (mUrlOpenListener != null) {
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.GRID_ITEM);
mUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
}
} else {

View File

@ -181,6 +181,8 @@ public class TopSitesPanel extends HomeFragment {
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.LIST_ITEM);
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
}

View File

@ -1,9 +1,11 @@
package org.mozilla.gecko.prompts;
import org.mozilla.gecko.menu.MenuItemActionView;
import org.mozilla.gecko.R;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.menu.MenuItemActionView;
import org.mozilla.gecko.widget.GeckoActionProvider;
import org.json.JSONArray;
@ -197,6 +199,9 @@ public class PromptListAdapter extends ArrayAdapter<PromptListItem> {
@Override
public void onIntentSelected(final Intent intent, final int p) {
provider.chooseActivity(p);
// Context: Sharing via content contextmenu list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
}
@Override

View File

@ -19,6 +19,8 @@ import java.util.List;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.TabsAccessor;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
/**
* The actual list of synced tabs. This serves as the only child view of {@link RemoteTabsContainer}
@ -68,6 +70,8 @@ class RemoteTabsList extends ExpandableListView
return true;
}
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, "", "remote");
Tabs.getInstance().loadUrl(tab.get("url"), Tabs.LOADURL_NEW_TAB);
autoHidePanel();
return true;

View File

@ -5,6 +5,8 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.menu.MenuItemActionView;
import android.content.Context;
@ -194,6 +196,9 @@ public class GeckoActionProvider {
@Override
public boolean onMenuItemClick(MenuItem item) {
chooseActivity(item.getItemId());
// Context: Sharing via chrome mainmenu list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
return true;
}
@ -201,6 +206,9 @@ public class GeckoActionProvider {
public void onClick(View view) {
Integer index = (Integer) view.getTag();
chooseActivity(index);
// Context: Sharing via chrome mainmenu and content contextmenu quickshare (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.BUTTON);
}
}
}

View File

@ -7,6 +7,9 @@ let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm")
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
"resource://gre/modules/UITelemetry.jsm");
XPCOMUtils.defineLazyGetter(window, "gChromeWin", function ()
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
@ -286,12 +289,18 @@ AboutReader.prototype = {
this._isReadingListItem = (this._isReadingListItem == 1) ? 0 : 1;
this._updateToggleButton();
// Create a relative timestamp for telemetry
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
if (this._isReadingListItem == 1) {
gChromeWin.Reader.storeArticleInCache(this._article, function(success) {
dump("Reader:Add (in reader) success=" + success);
let result = (success ? gChromeWin.Reader.READER_ADD_SUCCESS :
gChromeWin.Reader.READER_ADD_FAILED);
let result = gChromeWin.Reader.READER_ADD_FAILED;
if (success) {
result = gChromeWin.Reader.READER_ADD_SUCCESS;
UITelemetry.addEvent("save.1", "button", uptime, "reader");
}
let json = JSON.stringify({ fromAboutReader: true, url: this._article.url });
Services.obs.notifyObservers(null, "Reader:Add", json);
@ -310,6 +319,8 @@ AboutReader.prototype = {
// browser.js), sending this message will cause the toggle button to be
// updated (handled in this file).
Services.obs.notifyObservers(null, "Reader:Remove", this._article.url);
UITelemetry.addEvent("unsave.1", "button", uptime, "reader");
}
},
@ -322,6 +333,10 @@ AboutReader.prototype = {
url: this._article.url,
title: this._article.title
});
// Create a relative timestamp for telemetry
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
UITelemetry.addEvent("share.1", "list", uptime);
},
_setFontSize: function Reader_setFontSize(newFontSize) {

View File

@ -7483,15 +7483,22 @@ let Reader = {
sendMessageToJava({
type: "Reader:LongClick",
});
// Create a relative timestamp for telemetry
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
UITelemetry.addEvent("save.1", "pageaction", uptime, "reader");
},
},
updatePageAction: function(tab) {
if(this.pageAction.id) {
if (this.pageAction.id) {
NativeWindow.pageactions.remove(this.pageAction.id);
delete this.pageAction.id;
}
// Create a relative timestamp for telemetry
let uptime = Date.now() - Services.startup.getStartupInfo().linkerInitialized;
if (tab.readerActive) {
this.pageAction.id = NativeWindow.pageactions.add({
title: Strings.browser.GetStringFromName("readerMode.exit"),
@ -7499,7 +7506,17 @@ let Reader = {
clickCallback: this.pageAction.readerModeCallback,
important: true
});
} else if (tab.readerEnabled) {
// Only start a reader session if the viewer is in the foreground. We do
// not track background reader viewers.
UITelemetry.startSession("reader.1", uptime);
return;
}
// Only stop a reader session if the foreground viewer is not visible.
UITelemetry.stopSession("reader.1", "", uptime);
if (tab.readerEnabled) {
this.pageAction.id = NativeWindow.pageactions.add({
title: Strings.browser.GetStringFromName("readerMode.enter"),
icon: "drawable://reader",

View File

@ -39,3 +39,4 @@
[include:js/xpconnect/tests/unit/xpcshell.ini]
[include:js/jsd/test/xpcshell.ini]
[include:security/manager/ssl/tests/unit/xpcshell.ini]
[include:toolkit/devtools/qrcode/tests/unit/xpcshell.ini]

View File

@ -9,6 +9,7 @@
[include:dom/wappush/tests/xpcshell.ini]
[include:toolkit/devtools/apps/tests/unit/xpcshell.ini]
[include:toolkit/devtools/debugger/tests/unit/xpcshell.ini]
[include:toolkit/devtools/qrcode/tests/unit/xpcshell.ini]
[include:toolkit/devtools/sourcemap/tests/unit/xpcshell.ini]
[include:toolkit/mozapps/downloads/tests/unit/xpcshell.ini]
[include:toolkit/mozapps/update/tests/unit_aus_update/xpcshell.ini]

View File

@ -141,7 +141,6 @@ this.UITelemetry = {
delete this._activeSessions[aName];
if (!sessionStart) {
Services.console.logStringMessage("UITelemetry error: no session [" + aName + "] to stop!");
return;
}

View File

@ -113,6 +113,7 @@
<li><a href="about:license#pbkdf2-sha256">pbkdf2_sha256 License</a></li>
<li><a href="about:license#praton">praton License</a></li>
<li><a href="about:license#qcms">qcms License</a></li>
<li><a href="about:license#qrcode-generator">QR Code Generator License</a></li>
<li><a href="about:license#xdg">Red Hat xdg_user_dir_lookup License</a></li>
<li><a href="about:license#hunspell-ru">Russian Spellchecking Dictionary License</a></li>
<li><a href="about:license#sctp">SCTP Licenses</a></li>
@ -3574,6 +3575,35 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</pre>
<hr>
<h1><a id="qrcode-generator"></a>QR Code Generator License</h1>
<p>This license applies to certain files in the directory
<span class="path">toolkit/devtools/qrcode/encoder/</span>.</p>
<pre>
Copyright (c) 2009 Kazuhiko Arase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
</pre>
<hr>
<h1><a id="xdg"></a>Red Hat xdg_user_dir_lookup License</h1>

View File

@ -130,6 +130,8 @@ skip-if = os == "win" # Intermittent failures, bug 919016
[test_preferences.xul]
[test_preferences_beforeaccept.xul]
support-files = window_preferences_beforeaccept.xul
[test_preferences_onsyncfrompreference.xul]
support-files = window_preferences_onsyncfrompreference.xul
[test_progressmeter.xul]
[test_props.xul]
[test_radio.xul]

View File

@ -0,0 +1,62 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<!-- 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/. -->
<window title="Preferences Window beforeaccept Tests"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript">
<![CDATA[
const PREFS = ['tests.onsyncfrompreference.pref1',
'tests.onsyncfrompreference.pref2',
'tests.onsyncfrompreference.pref3'];
SimpleTest.waitForExplicitFinish();
for (let pref of PREFS) {
SpecialPowers.setIntPref(pref, 1);
}
let counter = 0;
let prefWindow = openDialog("window_preferences_onsyncfrompreference.xul", "", "", onSync);
SimpleTest.registerCleanupFunction(() => {
for (let pref of PREFS) {
SpecialPowers.clearUserPref(pref);
}
prefWindow.close();
});
// Onsyncfrompreference handler for the prefs
function onSync() {
for (let pref of PREFS) {
// The `value` field of each <preference> element should be initialized by now.
is(SpecialPowers.getIntPref(pref), prefWindow.document.getElementById(pref).value,
"Pref constructor was called correctly")
}
counter++;
if (counter == PREFS.length) {
SimpleTest.finish();
}
return true;
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</window>

View File

@ -0,0 +1,42 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<!-- 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/. -->
<!--
XUL Widget Test for preferences window with onsyncfrompreference
This test ensures that onsyncfrompreference handlers are called after all the
values of the corresponding preference element have been set correctly
-->
<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="preferences window"
width="300" height="300"
windowtype="test:preferences">
<prefpane id="sample_pane" label="Sample Prefpane">
<preferences id="sample_preferences">
<preference id="tests.onsyncfrompreference.pref1"
name="tests.onsyncfrompreference.pref1"
type="int"/>
<preference id="tests.onsyncfrompreference.pref2"
name="tests.onsyncfrompreference.pref2"
type="int"/>
<preference id="tests.onsyncfrompreference.pref3"
name="tests.onsyncfrompreference.pref3"
type="int"/>
</preferences>
</prefpane>
<label>Test Prefpane</label>
<checkbox id="check1" label="Label1"
preference="tests.onsyncfrompreference.pref1"
onsyncfrompreference="return window.arguments[0]();"
onsynctopreference="return 1;"/>
<checkbox id="check2" label="Label2"
preference="tests.onsyncfrompreference.pref2"
onsyncfrompreference="return window.arguments[0]();"
onsynctopreference="return 1;"/>
<checkbox id="check3" label="Label3"
preference="tests.onsyncfrompreference.pref3"
onsyncfrompreference="return window.arguments[0]();"
onsynctopreference="return 1;"/>
</prefwindow>

View File

@ -30,6 +30,25 @@
<binding id="preferences">
<implementation implements="nsIObserver">
<method name="_constructAfterChildren">
<body>
<![CDATA[
// This method will be called after each one of the child
// <preference> elements is constructed. Its purpose is to propagate
// the values to the associated form elements
var elements = this.getElementsByTagName("preference");
for (let element of elements) {
if (!element._constructed) {
return;
}
}
for (let element of elements) {
element.updateElements();
}
]]>
</body>
</method>
<method name="observe">
<parameter name="aSubject"/>
<parameter name="aTopic"/>
@ -101,6 +120,8 @@
<implementation>
<constructor>
<![CDATA[
this._constructed = true;
// if the element has been inserted without the name attribute set,
// we have nothing to do here
if (!this.name)
@ -126,18 +147,20 @@
preference = parentPrefs[l];
}
}
this._setValue(preference ? preference.value
: this.valueFromPreferences, false);
// Don't use the value setter here, we don't want updateElements to be prematurely fired.
this._value = preference ? preference.value : this.valueFromPreferences;
}
else
this._setValue(this.valueFromPreferences, false);
this._value = this.valueFromPreferences;
this.preferences._constructAfterChildren();
]]>
</constructor>
<destructor>
this.preferences.rootBranchInternal
.removeObserver(this.name, this.preferences);
</destructor>
<field name="_constructed">false</field>
<property name="instantApply">
<getter>
return this.getAttribute("instantApply") == "true" || this.preferences.instantApply;
@ -169,24 +192,19 @@
<field name="_value">null</field>
<method name="_setValue">
<parameter name="aValue"/>
<parameter name="aUpdate"/>
<body>
<![CDATA[
if (aUpdate && this.value !== aValue) {
if (this.value !== aValue) {
this._value = aValue;
if (this.instantApply)
this.valueFromPreferences = aValue;
this.preferences.fireChangedEvent(this);
}
else if (!aUpdate) {
this._value = aValue;
this.updateElements();
}
return aValue;
]]>
</body>
</method>
<property name="value" onget="return this._value" onset="return this._setValue(val, true);"/>
<property name="value" onget="return this._value" onset="return this._setValue(val);"/>
<property name="locked">
<getter>

View File

@ -13,7 +13,8 @@ PARALLEL_DIRS += [
'apps',
'styleinspector',
'acorn',
'pretty-fast'
'pretty-fast',
'qrcode'
]
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']

View File

@ -0,0 +1,19 @@
Copyright (c) 2009 Kazuhiko Arase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
JS_MODULES_PATH = 'modules/devtools/qrcode/encoder'
EXTRA_JS_MODULES += [
'index.js',
]

View File

@ -0,0 +1,17 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
PARALLEL_DIRS += [
'encoder'
]
JS_MODULES_PATH = 'modules/devtools/qrcode'
EXTRA_JS_MODULES += [
'qrcode.js',
]
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']

View File

@ -0,0 +1,62 @@
/* 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 { Encoder, QRRSBlock, QRErrorCorrectLevel } = require("./encoder/index");
/**
* There are many "versions" of QR codes, which describes how many dots appear
* in the resulting image, thus limiting the amount of data that can be
* represented.
*
* The encoder used here allows for versions 1 - 10 (more dots for larger
* versions).
*
* It expects you to pick a version large enough to contain your message. Here
* we search for the mimimum version based on the message length.
* @param string message
* Text to encode
* @param string quality
* Quality level: L, M, Q, H
* @return integer
*/
exports.findMinimumVersion = function(message, quality) {
let msgLength = message.length;
let qualityLevel = QRErrorCorrectLevel[quality];
for (let version = 1; version <= 10; version++) {
let rsBlocks = QRRSBlock.getRSBlocks(version, qualityLevel);
let maxLength = rsBlocks.reduce((prev, block) => {
return prev + block.dataCount;
}, 0);
// Remove two bytes to fit header info
maxLength -= 2;
if (msgLength <= maxLength) {
return version;
}
}
throw new Error("Message too large");
};
/**
* Simple wrapper around the underlying encoder's API.
* @param string message
* Text to encode
* @param string quality (optional)
Quality level: L, M, Q, H
* @param integer version (optional)
* QR code "version" large enough to contain the message
* @return object with the following fields:
* * src: an image encoded a data URI
* * height: image height
* * width: image width
*/
exports.encodeToDataURI = function(message, quality, version) {
quality = quality || "H";
version = version || exports.findMinimumVersion(message, quality);
let encoder = new Encoder(version, quality);
encoder.addData(message);
encoder.make();
return encoder.createImgData();
};

View File

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test encoding a simple message.
*/
const { utils: Cu } = Components;
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
const QR = require("devtools/toolkit/qrcode/qrcode");
function run_test() {
let imgData = QR.encodeToDataURI("HELLO", "L");
do_check_eq(imgData.src,
"data:image/gif;base64,R0lGODdhOgA6AIAAAAAAAP///ywAAAAAOgA6AAAC" +
"/4yPqcvtD6OctNqLs968+w+G4gKU5nkaKKquLuW+QVy2tAkDTj3rfQts8CRDko" +
"+HPPoYRUgy9YsyldDm44mLWhHYZM6W7WaDqyCRGkZDySxpRGw2sqvLt1q5w/fo" +
"XyE6vnUQOJUHBlinMGh046V1F5PDqNcoqcgBOWKBKbK2N+aY+Ih49VkmqMcl2l" +
"dkhZUK1umE6jZXJ2ZJaujZaRqH4bpb2uZrJxvIt4Ebe9qoYYrJOsw8apz2bCut" +
"m9kqDcw52uuImyr5Oh1KXH1jrn2anuunywtODU/o2c6teceW39ZcLFg/fNMo1b" +
"t3jVw2dwTPwJq1KYG3gAklCgu37yGxeScYKyiCc+7DR34hPVQiuQ7UhJMagyEb" +
"lymmzJk0a9q8iTOnzp0NCgAAOw==");
do_check_eq(imgData.width, 58);
do_check_eq(imgData.height, 58);
}

View File

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_encode.js]

View File

@ -147,6 +147,12 @@ function log_exceptions(aCallback, ...aArgs) {
}
}
function log_callback(aPromise, aCallback) {
aPromise.then(aCallback)
.then(null, e => info("Exception thrown: " + e));
return aPromise;
}
function add_test(test) {
gPendingTests.push(test);
}
@ -283,87 +289,82 @@ function wait_for_manager_load(aManagerWindow, aCallback) {
}
function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) {
let deferred = Promise.defer();
let p = new Promise((resolve, reject) => {
function setup_manager(aManagerWindow) {
if (aLoadCallback)
log_exceptions(aLoadCallback, aManagerWindow);
function setup_manager(aManagerWindow) {
if (aLoadCallback)
log_exceptions(aLoadCallback, aManagerWindow);
if (aView)
aManagerWindow.loadView(aView);
if (aView)
aManagerWindow.loadView(aView);
ok(aManagerWindow != null, "Should have an add-ons manager window");
is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
ok(aManagerWindow != null, "Should have an add-ons manager window");
is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
waitForFocus(function() {
wait_for_manager_load(aManagerWindow, function() {
wait_for_view_load(aManagerWindow, function() {
// Some functions like synthesizeMouse don't like to be called during
// the load event so ensure that has completed
executeSoon(function() {
if (aCallback) {
log_exceptions(aCallback, aManagerWindow);
}
deferred.resolve(aManagerWindow);
});
}, null, aLongerTimeout);
});
}, aManagerWindow);
}
waitForFocus(function() {
info("window has focus, waiting for manager load");
wait_for_manager_load(aManagerWindow, function() {
info("Manager waiting for view load");
wait_for_view_load(aManagerWindow, function() {
resolve(aManagerWindow);
}, null, aLongerTimeout);
});
}, aManagerWindow);
}
if (gUseInContentUI) {
gBrowser.selectedTab = gBrowser.addTab();
switchToTabHavingURI(MANAGER_URI, true);
if (gUseInContentUI) {
info("Loading manager window in tab");
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, aTopic);
if (aSubject.location.href != MANAGER_URI) {
info("Ignoring load event for " + aSubject.location.href);
return;
}
setup_manager(aSubject);
}, "EM-loaded", false);
// This must be a new load, else the ping/pong would have
// found the window above.
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, aTopic);
if (aSubject.location.href != MANAGER_URI)
return;
setup_manager(aSubject);
}, "EM-loaded", false);
return deferred.promise;
}
gBrowser.selectedTab = gBrowser.addTab();
switchToTabHavingURI(MANAGER_URI, true);
} else {
info("Loading manager window in dialog");
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, aTopic);
setup_manager(aSubject);
}, "EM-loaded", false);
openDialog(MANAGER_URI);
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, aTopic);
setup_manager(aSubject);
}, "EM-loaded", false);
openDialog(MANAGER_URI);
}
});
return deferred.promise;
return log_callback(p, aCallback);
}
function close_manager(aManagerWindow, aCallback, aLongerTimeout) {
let deferred = Promise.defer();
requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
let p = new Promise((resolve, reject) => {
requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
ok(aManagerWindow != null, "Should have an add-ons manager window to close");
is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
ok(aManagerWindow != null, "Should have an add-ons manager window to close");
is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
aManagerWindow.addEventListener("unload", function() {
this.removeEventListener("unload", arguments.callee, false);
if (aCallback) {
log_exceptions(aCallback);
}
deferred.resolve();
}, false);
aManagerWindow.addEventListener("unload", function() {
info("Manager window unloaded");
this.removeEventListener("unload", arguments.callee, false);
resolve();
}, false);
});
aManagerWindow.close();
return deferred.promise;
return log_callback(p, aCallback);
}
function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) {
if (!aManagerWindow) {
open_manager(aView, aCallback, aLoadCallback);
return;
return open_manager(aView, aCallback, aLoadCallback);
}
close_manager(aManagerWindow, function() {
open_manager(aView, aCallback, aLoadCallback);
});
return close_manager(aManagerWindow)
.then(() => open_manager(aView, aCallback, aLoadCallback));
}
function wait_for_window_open(aCallback) {
@ -437,25 +438,17 @@ function is_element_hidden(aElement, aMsg) {
* The callback will receive the Addon for the installed add-on.
*/
function install_addon(path, cb, pathPrefix=TESTROOT) {
let deferred = Promise.defer();
let p = new Promise((resolve, reject) => {
AddonManager.getInstallForURL(pathPrefix + path, (install) => {
install.addListener({
onInstallEnded: () => resolve(install.addon),
});
AddonManager.getInstallForURL(pathPrefix + path, (install) => {
install.addListener({
onInstallEnded: () => {
executeSoon(() => {
if (cb) {
cb(install.addon);
}
install.install();
}, "application/x-xpinstall");
});
deferred.resolve(install.addon);
});
},
});
install.install();
}, "application/x-xpinstall");
return deferred.promise;
return log_callback(p, cb);
}
function CategoryUtilities(aManagerWindow) {
@ -517,22 +510,14 @@ CategoryUtilities.prototype = {
},
open: function(aCategory, aCallback) {
let deferred = Promise.defer();
isnot(this.window, null, "Should not open category when manager window is not loaded");
ok(this.isVisible(aCategory), "Category should be visible if attempting to open it");
EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window);
let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve));
wait_for_view_load(this.window, (win) => {
if (aCallback) {
log_exceptions(aCallback, win);
}
deferred.resolve(win);
});
return deferred.promise;
return log_callback(p, aCallback);
},
openType: function(aCategoryType, aCallback) {