Merge m-c to inbound a=merge

This commit is contained in:
Wes Kocher 2015-05-01 17:23:32 -07:00
commit b492021bca
106 changed files with 1548 additions and 262 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

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="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "8e64346ce8197b50b815a294278797bc144aa3e6",
"git_revision": "07a1a20b86931ee9911b16df94df60a178825bb2",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "1bbaa54b674c42e0d8b2fe31d8b0080901811fa0",
"revision": "99b2099a5fa6ac2567993f2c859d651934556464",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -100,7 +100,7 @@ nsContextMenu.prototype = {
this.linkURI = makeURI(this.linkURL);
} catch (ex) {}
this.linkText = this.selectionInfo.linkText;
this.linkTextStr = this.selectionInfo.linkText;
this.onPlainTextLink = true;
}
@ -524,7 +524,7 @@ nsContextMenu.prototype = {
this.link = null;
this.linkURL = "";
this.linkURI = null;
this.linkText = "";
this.linkTextStr = "";
this.linkProtocol = "";
this.linkDownload = "";
this.linkHasNoReferrer = false;
@ -700,7 +700,7 @@ nsContextMenu.prototype = {
this.link = elem;
this.linkURL = this.getLinkURL();
this.linkURI = this.getLinkURI();
this.linkText = this.getLinkText();
this.linkTextStr = this.getLinkText();
this.linkProtocol = this.getLinkProtocol();
this.onMailtoLink = (this.linkProtocol == "mailto");
this.onSaveableLink = this.isLinkSaveable( this.link );
@ -1281,7 +1281,7 @@ nsContextMenu.prototype = {
// Save URL of clicked-on link.
saveLink: function() {
urlSecurityCheck(this.linkURL, this.principal);
this.saveHelper(this.linkURL, this.linkText, null, true, this.ownerDoc,
this.saveHelper(this.linkURL, this.linkTextStr, null, true, this.ownerDoc,
gContextMenuContentData.documentURIObject,
gContextMenuContentData.frameOuterWindowID,
this.linkDownload);
@ -1496,6 +1496,11 @@ nsContextMenu.prototype = {
return text;
},
// Kept for addon compat
linkText: function() {
return this.linkTextStr;
},
isMediaURLReusable: function(aURL) {
return !/^(?:blob|mediasource):/.test(aURL);
},
@ -1563,7 +1568,7 @@ nsContextMenu.prototype = {
bookmarkLink: function CM_bookmarkLink() {
window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId,
this.linkURL, this.linkText);
this.linkURL, this.linkTextStr);
},
addBookmarkForFrame: function CM_addBookmarkForFrame() {
@ -1657,7 +1662,7 @@ nsContextMenu.prototype = {
// Formats the 'Search <engine> for "<selection or link text>"' context menu.
formatSearchContextItem: function() {
var menuItem = document.getElementById("context-searchselect");
let selectedText = this.isTextSelected ? this.textSelected : this.linkText;
let selectedText = this.isTextSelected ? this.textSelected : this.linkTextStr;
// Store searchTerms in context menu item so we know what to search onclick
menuItem.searchTerms = selectedText;

View File

@ -3347,11 +3347,13 @@
},
/*
* Telemetry related helpers for recording tab switch timing.
* Telemetry and Profiler related helpers for recording tab switch
* timing.
*/
startTabSwitch: function () {
TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
this.addMarker("AsyncTabSwitch:Start");
},
finishTabSwitch: function () {
@ -3360,6 +3362,7 @@
if (time != -1) {
TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
this.log("DEBUG: tab switch time = " + time);
this.addMarker("AsyncTabSwitch:Finish");
}
}
},
@ -3367,6 +3370,7 @@
spinnerDisplayed: function () {
if (this.spinnerTab) {
TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
this.addMarker("AsyncTabSwitch:SpinnerShown");
}
},
@ -3375,11 +3379,18 @@
this.log("DEBUG: spinner time = " +
TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window));
TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
this.addMarker("AsyncTabSwitch:SpinnerHidden");
// we do not get a onPaint after displaying the spinner
this.finishTabSwitch();
}
},
addMarker: function(marker) {
if (Services.profiler) {
Services.profiler.AddMarker(marker);
}
},
/*
* Debug related logging for switcher.
*/

View File

@ -89,18 +89,15 @@ function waitForProviderLoad(cb) {
waitForCondition(function() {
let sbrowser = document.getElementById("social-sidebar-browser");
let provider = SocialSidebar.provider;
let postActivation = provider && gBrowser.contentDocument.location.href == provider.origin + "/browser/browser/base/content/test/social/social_postActivation.html";
let postActivation = provider && gBrowser.contentDocument &&
gBrowser.contentDocument.location.href == provider.origin + "/browser/browser/base/content/test/social/social_postActivation.html";
return provider &&
provider.profile &&
provider.profile.displayName &&
postActivation &&
sbrowser.docShellIsActive;
return postActivation && sbrowser.docShellIsActive;
}, function() {
// executeSoon to let the browser UI observers run first
executeSoon(cb);
},
"waitForProviderLoad: provider profile was not set");
"waitForProviderLoad: provider was not loaded");
}
@ -178,22 +175,19 @@ let gProviders = [
{
name: "provider 1",
origin: "https://example.com",
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?provider1",
workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider1",
iconURL: "chrome://branding/content/icon48.png"
},
{
name: "provider 2",
origin: "https://test1.example.com",
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider2",
iconURL: "chrome://branding/content/icon64.png"
},
{
name: "provider 3",
origin: "https://test2.example.com",
sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
workerURL: "https://test2.example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider2",
iconURL: "chrome://branding/content/about-logo.png"
}
];

View File

@ -218,11 +218,6 @@ let LoopRoomsInternal = {
};
}
// For now, disable encryption/context if context is disabled
if (!MozLoopService.getLoopPref("contextInConverations.enabled")) {
return getUnencryptedData();
}
var newRoomData = extend({}, roomData);
if (!newRoomData.context) {
@ -700,7 +695,8 @@ let LoopRoomsInternal = {
};
// If we're not encrypting currently, then only send the roomName.
if (!Services.prefs.getBoolPref("loop.contextInConverations.enabled")) {
// XXX This should go away once bug 1153788 is fixed.
if (!sendData.context) {
sendData = {
roomName: newRoomName
};

View File

@ -11,8 +11,6 @@ Cu.import("resource://gre/modules/Promise.jsm");
let openChatOrig = Chat.open;
const kContextEnabledPref = "loop.contextInConverations.enabled";
const kGuestKey = "uGIs-kGbYt1hBBwjyW7MLQ";
// Rooms details as responded by the server.
@ -299,14 +297,10 @@ add_task(function* setup_server() {
let body = CommonUtils.readBytesFromInputStream(req.bodyInputStream);
let data = JSON.parse(body);
if (Services.prefs.getBoolPref(kContextEnabledPref)) {
Assert.equal(data.roomOwner, kCreateRoomProps.roomOwner);
Assert.equal(data.maxSize, kCreateRoomProps.maxSize);
Assert.ok(!("decryptedContext" in data), "should not have any decrypted data");
Assert.ok("context" in data, "should have context");
} else {
Assert.deepEqual(data, kCreateRoomUnencryptedProps);
}
Assert.equal(data.roomOwner, kCreateRoomProps.roomOwner);
Assert.equal(data.maxSize, kCreateRoomProps.maxSize);
Assert.ok(!("decryptedContext" in data), "should not have any decrypted data");
Assert.ok("context" in data, "should have context");
res.write(JSON.stringify(kCreateRoomData));
} else {
@ -353,15 +347,11 @@ add_task(function* setup_server() {
res.finish();
} else if (req.method == "PATCH") {
let data = getJSONData(req.bodyInputStream);
if (Services.prefs.getBoolPref(kContextEnabledPref)) {
Assert.ok("context" in data, "should have encrypted context");
// We return a fake encrypted name here as the context is
// encrypted.
returnRoomDetails(res, "fakeEncrypted");
} else {
Assert.ok(!("context" in data), "should not have encrypted context");
returnRoomDetails(res, data.roomName);
}
Assert.ok("context" in data, "should have encrypted context");
// We return a fake encrypted name here as the context is
// encrypted.
returnRoomDetails(res, "fakeEncrypted");
} else {
roomDetail.context = room.context;
res.setStatusLine(null, 200, "OK");
@ -415,20 +405,6 @@ add_task(function* test_errorStates() {
// Test if creating a new room works as expected.
add_task(function* test_createRoom() {
Services.prefs.setBoolPref(kContextEnabledPref, true);
var expectedRoom = extend({}, kCreateRoomProps);
expectedRoom.roomToken = kCreateRoomData.roomToken;
gExpectedAdds.push(expectedRoom);
let room = yield LoopRooms.promise("create", kCreateRoomProps);
compareRooms(room, expectedRoom);
});
// XXX Test unencrypted rooms. This will go away once we switch encryption on.
add_task(function* test_createRoom_unencrypted() {
Services.prefs.setBoolPref(kContextEnabledPref, false);
var expectedRoom = extend({}, kCreateRoomProps);
expectedRoom.roomToken = kCreateRoomData.roomToken;
@ -601,19 +577,11 @@ add_task(function* test_sendConnectionStatus() {
// Test if renaming a room works as expected.
add_task(function* test_renameRoom() {
Services.prefs.setBoolPref(kContextEnabledPref, true);
let roomToken = "_nxD4V4FflQ";
let renameData = yield LoopRooms.promise("rename", roomToken, "fakeName");
Assert.equal(renameData.roomName, "fakeEncrypted", "should have set the new name");
});
add_task(function* test_renameRoom_unencrpyted() {
Services.prefs.setBoolPref(kContextEnabledPref, false);
let roomToken = "_nxD4V4FflQ";
let renameData = yield LoopRooms.promise("rename", roomToken, "fakeName");
Assert.equal(renameData.roomName, "fakeName", "should have set the new name");
});
add_task(function* test_roomDeleteNotifications() {
gExpectedDeletes.push("_nxD4V4FflQ");
roomsPushNotification("5", kChannelGuest);
@ -657,7 +625,6 @@ function run_test() {
do_register_cleanup(function () {
// Revert original Chat.open implementation
Chat.open = openChatOrig;
Services.prefs.clearUserPref(kContextEnabledPref);
Services.prefs.clearUserPref("loop.key");
MozLoopServiceInternal.fxAOAuthTokenData = null;

View File

@ -1829,7 +1829,15 @@ MarkupContainer.prototype = {
this.hovered = false;
this.markup.navigate(this);
event.stopPropagation();
event.preventDefault();
// Preventing the default behavior will avoid the body to gain focus on
// mouseup (through bubbling) when clicking on a non focusable node in the
// line. So, if the click happened outside of a focusable element, do
// prevent the default behavior, so that the tagname or textcontent gains
// focus.
if (!target.closest(".open [tabindex]")) {
event.preventDefault();
}
// Start dragging the container after a delay.
this.markup._dragStartEl = target;

View File

@ -8,7 +8,7 @@
// the first focusable element in the corresponding MarkupContainer so that the
// keyboard can be used immediately.
const TEST_URL = "data:text/html;charset=utf8,<div></div>Text node";
const TEST_URL = "data:text/html;charset=utf8,<div class='test-class'></div>Text node";
add_task(function*() {
let {inspector, toolbox} = yield addTab(TEST_URL).then(openInspector);
@ -31,4 +31,18 @@ add_task(function*() {
is(inspector.markup.doc.activeElement,
getContainerForNodeFront(divFront, inspector).editor.tag,
"The currently focused element is the div's tagname");
info("Click on the test-class attribute, to make sure it gets focused");
let editor = getContainerForNodeFront(divFront, inspector).editor;
let attributeEditor = editor.attrElements.get("class").querySelector(".editable");
let onFocus = once(attributeEditor, "focus");
EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mousedown"},
inspector.markup.doc.defaultView);
EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mouseup"},
inspector.markup.doc.defaultView);
yield onFocus;
is(inspector.markup.doc.activeElement, attributeEditor,
"The currently focused element is the div's class attribute");
});

View File

@ -266,8 +266,8 @@ GraphsController.prototype = {
yield this._rendering.promise;
}
for (let graphName in this._graphs) {
yield this._graphs[graphName].destroy();
for (let graph of this.getWidgets()) {
yield graph.destroy();
}
}),
@ -277,9 +277,9 @@ GraphsController.prototype = {
*/
setTheme: function (options={}) {
let theme = options.theme || this._getTheme();
for (let graph in this._graphs) {
this._graphs[graph].setTheme(theme);
this._graphs[graph].refresh({ force: options.redraw });
for (let graph of this.getWidgets()) {
graph.setTheme(theme);
graph.refresh({ force: options.redraw });
}
},
@ -348,6 +348,14 @@ GraphsController.prototype = {
return this._getPrimaryLink().getMappedSelection({ mapStart, mapEnd });
},
/**
* Returns an array of graphs that have been created, not necessarily
* enabled currently.
*/
getWidgets: function () {
return Object.keys(this._graphs).map(name => this._graphs[name]);
},
/**
* Drops the selection.
*/

View File

@ -43,6 +43,7 @@ support-files =
[browser_perf-details-03.js]
[browser_perf-details-04.js]
[browser_perf-details-05.js]
[browser_perf-details-06.js]
[browser_perf-events-calltree.js]
[browser_perf-front-basic-profiler-01.js]
[browser_perf-front-basic-timeline-01.js]

View File

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the views with `shouldUpdateWhileMouseIsActive` works as intended.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView, JsFlameGraphView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
// Set the debounce on WaterfallView and JsFlameGraphView to 0
WaterfallView.rangeChangeDebounceTime = 0;
JsFlameGraphView.rangeChangeDebounceTime = 0;
yield DetailsView.selectView("js-flamegraph");
let duration = PerformanceController.getCurrentRecording().getDuration();
// Fake an active mouse
Object.defineProperty(OverviewView, "isMouseActive", { value: true });
// Flame Graph should update on every selection, debounced, while mouse is down
let flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
yield flamegraphRendered;
ok(true, "FlameGraph rerenders when mouse is active (1)");
flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
yield flamegraphRendered;
ok(true, "FlameGraph rerenders when mouse is active (2)");
ok(OverviewView.isMouseActive, "Fake mouse is still active");
// Fake an inactive mouse for rerender
Object.defineProperty(OverviewView, "isMouseActive", { value: false });
yield DetailsView.selectView("waterfall");
// Fake an active mouse for rerender
Object.defineProperty(OverviewView, "isMouseActive", { value: true });
let oneSecondElapsed = false;
let waterfallRendered = false;
WaterfallView.on(EVENTS.WATERFALL_RENDERED, () => waterfallRendered = true);
// Keep firing range selection events for one second
idleWait(1000).then(() => oneSecondElapsed = true);
yield waitUntil(() => {
OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
return oneSecondElapsed;
});
ok(OverviewView.isMouseActive, "Fake mouse is still active");
ok(!waterfallRendered, "the waterfall view should not have been rendered while mouse is active.");
yield teardown(panel);
finish();
}

View File

@ -97,9 +97,10 @@ let OverviewView = {
* false otherwise.
*/
get isMouseActive() {
return (this.markersOverview && this.markersOverview.isMouseActive) ||
(this.memoryOverview && this.memoryOverview.isMouseActive) ||
(this.framerateGraph && this.framerateGraph.isMouseActive);
// Fetch all graphs currently stored in the GraphsController.
// These graphs are not necessarily active, but will not have
// an active mouse, in that case.
return !!this.graphs.getWidgets().some(e => e.isMouseActive);
},
/**

View File

@ -119,7 +119,9 @@ function test() {
info(customPresetIndex);
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
let resizePromise = instance._test_notifyOnResize();
instance.menulist.selectedIndex = customPresetIndex;
yield resizePromise;
is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");

View File

@ -53,6 +53,16 @@ exports.parseLocation = function parseLocation (frame) {
};
},
/**
* Determines if the given frame is the (root) frame.
*
* @param object frame
* @return boolean
*/
exports.isRoot = function isRoot({ location }) {
return location === "(root)";
};
/**
* Checks if the specified function represents a chrome or content frame.
*
@ -61,8 +71,13 @@ exports.parseLocation = function parseLocation (frame) {
* @return boolean
* True if a content frame, false if a chrome frame.
*/
exports.isContent = function isContent ({ category, location }) {
exports.isContent = function isContent (frame) {
if (exports.isRoot(frame)) {
return true;
}
// Only C++ stack frames have associated category information.
const { category, location } = frame;
return !!(!category &&
!CHROME_SCHEMES.find(e => location.includes(e)) &&
CONTENT_SCHEMES.find(e => location.includes(e)));

View File

@ -93,15 +93,20 @@ ThreadNode.prototype = {
let sampleFrames = sample.frames;
if (!options.invertTree) {
// Remove the (root) node if the tree is not inverted: we will synthesize
// our own root in the view. However, for inverted trees, we wish to be
// able to differentiate between (root)->A->B->C and (root)->B->C stacks,
// so we need the root node in that case.
sampleFrames = sampleFrames.slice(1);
}
// Filter out platform frames if only content-related function calls
// should be taken into consideration.
if (options.contentOnly) {
// The (root) node is not considered a content function, it'll be removed.
sampleFrames = FrameUtils.filterPlatformData(sampleFrames);
} else {
// Remove the (root) node manually.
sampleFrames = sampleFrames.slice(1);
}
// If no frames remain after filtering, then this is a leaf node, no need
// to continue.
if (!sampleFrames.length) {

View File

@ -20,79 +20,56 @@ function test()
let {tab} = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
let jsterm = hud.jsterm;
let result;
let vview;
let msg;
let msg = yield execute("fooObj");
ok(msg, "output message found");
let anchor = msg.querySelector("a");
let body = msg.querySelector(".message-body");
ok(anchor, "object anchor");
ok(body, "message body");
ok(body.textContent.includes('testProp: "testValue"'), "message text check");
msg.scrollIntoView();
executeSoon(() => {
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
});
let vviewVar = yield jsterm.once("variablesview-fetched");
let vview = vviewVar._variablesView;
ok(vview, "variables view object");
let [result] = yield findVariableViewProperties(vviewVar, [
{ name: "testProp", value: "testValue" },
], { webconsole: hud });
yield openSidebar("fooObj",
'testProp: "testValue"',
{ name: "testProp", value: "testValue" });
let prop = result.matchedProp;
ok(prop, "matched the |testProp| property in the variables view");
vview.window.focus();
executeSoon(() => {
EventUtils.synthesizeKey("VK_ESCAPE", {});
});
yield jsterm.once("sidebar-closed");
let sidebarClosed = jsterm.once("sidebar-closed");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield sidebarClosed;
jsterm.clearOutput();
msg = yield execute("window.location");
ok(msg, "output message found");
body = msg.querySelector(".message-body");
ok(body, "message body");
anchor = msg.querySelector("a");
ok(anchor, "object anchor");
ok(body.textContent.includes("Location \u2192 http://example.com/browser/"),
"message text check");
msg.scrollIntoView();
executeSoon(() => {
EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow)
});
vviewVar = yield jsterm.once("variablesview-fetched");
vview = vviewVar._variablesView;
ok(vview, "variables view object");
yield findVariableViewProperties(vviewVar, [
{ name: "host", value: "example.com" },
], { webconsole: hud });
yield openSidebar("window.location",
"Location \u2192 http://example.com/browser/",
{ name: "host", value: "example.com" });
vview.window.focus();
msg.scrollIntoView();
executeSoon(() => {
EventUtils.synthesizeKey("VK_ESCAPE", {});
});
sidebarClosed = jsterm.once("sidebar-closed");
EventUtils.synthesizeKey("VK_ESCAPE", {});
yield sidebarClosed;
yield jsterm.once("sidebar-closed");
}
function* openSidebar(objName, expectedText, expectedObj) {
msg = yield jsterm.execute(objName);
ok(msg, "output message found");
function execute(str) {
let deferred = promise.defer();
hud.jsterm.execute(str, (msg) => {
deferred.resolve(msg);
});
return deferred.promise;
let anchor = msg.querySelector("a");
let body = msg.querySelector(".message-body");
ok(anchor, "object anchor");
ok(body, "message body");
ok(body.textContent.includes(expectedText), "message text check");
msg.scrollIntoView();
yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
let vviewVar = yield jsterm.once("variablesview-fetched");
vview = vviewVar._variablesView;
ok(vview, "variables view object exists");
[result] = yield findVariableViewProperties(vviewVar, [
expectedObj,
], { webconsole: hud });
}
}
}

View File

@ -4,6 +4,7 @@
*/
// Check that clear output on page reload works - bug 705921.
// Check that clear output and page reload remove the sidebar - bug 971967.
"use strict";
@ -19,7 +20,12 @@ let test = asyncTest(function*() {
let hud = yield openConsole();
ok(hud, "Web Console opened");
yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
let sidebarClosed = hud.jsterm.once("sidebar-closed");
hud.jsterm.clearOutput();
yield sidebarClosed;
hud.jsterm.execute("console.log('foobarz1')");
yield waitForMessages({
@ -31,8 +37,13 @@ let test = asyncTest(function*() {
}],
});
yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
BrowserReload();
yield loadBrowser(gBrowser.selectedBrowser);
sidebarClosed = hud.jsterm.once("sidebar-closed");
loadBrowser(gBrowser.selectedBrowser);
yield sidebarClosed;
hud.jsterm.execute("console.log('foobarz2')");
@ -51,4 +62,24 @@ let test = asyncTest(function*() {
is(hud.outputNode.textContent.indexOf("foobarz1"), -1,
"foobarz1 has been removed from output");
function* openSidebar(objName, expectedObj) {
let msg = yield hud.jsterm.execute(objName);
ok(msg, "output message found");
let anchor = msg.querySelector("a");
let body = msg.querySelector(".message-body");
ok(anchor, "object anchor");
ok(body, "message body");
yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
let vviewVar = yield hud.jsterm.once("variablesview-fetched");
let vview = vviewVar._variablesView;
ok(vview, "variables view object exists");
yield findVariableViewProperties(vviewVar, [
expectedObj,
], { webconsole: hud });
}
});

View File

@ -3,6 +3,10 @@
<meta charset="utf-8">
<title>Console test</title>
<script type="text/javascript">
var fooObj = {
testProp: "testValue"
};
function test() {
var str = "Dolske Digs Bacon, Now and Forevermore."
for (var i=0; i < 5; i++) {

View File

@ -3979,6 +3979,8 @@ JSTerm.prototype = {
this.webConsoleClient.clearMessagesCache();
}
this._sidebarDestroy();
this.emit("messages-cleared");
},

View File

@ -888,6 +888,9 @@ public:
virtual void EnergyInfoNotification(const BluetoothActivityEnergyInfo& aInfo)
{ }
virtual void BackendErrorNotification(bool aCrashed)
{ }
protected:
BluetoothNotificationHandler()
{ }

View File

@ -538,6 +538,7 @@ void
BluetoothA2dpManager::OnDisconnectError()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(mController);
mController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
}
@ -582,7 +583,9 @@ BluetoothA2dpManager::Disconnect(BluetoothProfileController* aController)
if (!sBtA2dpInterface) {
BT_LOGR("sBluetoothA2dpInterface is null");
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
if (aController) {
aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
}
return;
}

View File

@ -24,6 +24,8 @@ using namespace mozilla::ipc;
BEGIN_BLUETOOTH_NAMESPACE
static const int sRetryInterval = 100; // ms
//
// Protocol initialization and setup
//
@ -1148,7 +1150,7 @@ private:
nsresult
operator () (nsString& aArg1, nsString& aArg2, uint32_t& aArg3,
BluetoothSspVariant aArg4, uint32_t& aArg5) const
BluetoothSspVariant& aArg4, uint32_t& aArg5) const
{
BluetoothDaemonPDU& pdu = GetPDU();
@ -1749,6 +1751,20 @@ BluetoothDaemonChannel::GetIO()
#define container(_t, _v, _m) \
( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) )
static bool
IsDaemonRunning()
{
char value[PROPERTY_VALUE_MAX];
NS_WARN_IF(property_get("init.svc.bluetoothd", value, "") < 0);
if (strcmp(value, "running")) {
BT_LOGR("[RESTART] Bluetooth daemon state <%s>", value);
return false;
}
return true;
}
BluetoothDaemonInterface*
BluetoothDaemonInterface::GetInstance()
{
@ -1769,6 +1785,42 @@ BluetoothDaemonInterface::BluetoothDaemonInterface()
BluetoothDaemonInterface::~BluetoothDaemonInterface()
{ }
class BluetoothDaemonInterface::StartDaemonTask final : public Task
{
public:
StartDaemonTask(BluetoothDaemonInterface* aInterface,
const nsACString& aCommand)
: mInterface(aInterface)
, mCommand(aCommand)
{
MOZ_ASSERT(mInterface);
}
void Run() override
{
MOZ_ASSERT(NS_IsMainThread());
BT_LOGR("Start Daemon Task");
// Start Bluetooth daemon again
if (NS_WARN_IF(property_set("ctl.start", mCommand.get()) < 0)) {
mInterface->OnConnectError(CMD_CHANNEL);
}
// We're done if Bluetooth daemon is already running
if (IsDaemonRunning()) {
return;
}
// Otherwise try again later
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new StartDaemonTask(mInterface, mCommand), sRetryInterval);
}
private:
BluetoothDaemonInterface* mInterface;
nsCString mCommand;
};
class BluetoothDaemonInterface::InitResultHandler final
: public BluetoothSetupResultHandler
{
@ -1831,6 +1883,19 @@ BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel)
if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
OnConnectError(CMD_CHANNEL);
}
/*
* If Bluetooth daemon is not running, retry to start it later.
*
* This condition happens when when we restart Bluetooth daemon
* immediately after it crashed, as the daemon state remains 'stopping'
* instead of 'stopped'. Due to the limitation of property service,
* hereby add delay. See Bug 1143925 Comment 41.
*/
if (!IsDaemonRunning()) {
MessageLoop::current()->PostDelayedTask(FROM_HERE,
new StartDaemonTask(this, value), sRetryInterval);
}
}
break;
case CMD_CHANNEL:
@ -1890,33 +1955,40 @@ BluetoothDaemonInterface::OnConnectError(enum Channel aChannel)
}
}
/*
* Three cases for restarting:
* a) during startup
* b) during regular service
* c) during shutdown
* For (a)/(c) cases, mResultHandlerQ contains an element, but case (b)
* mResultHandlerQ shall be empty. The following procedure to recover from crashed
* consists of several steps for case (b).
* 1) Close listen socket.
* 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to
* perform the regular stop bluetooth procedure.
* 3) When stop bluetooth procedures complete, fire
* AdapterStateChangedNotification to cleanup all necessary data members and
* deinit ProfileManagers.
* 4) After all resources cleanup, call |StartBluetooth|
*/
void
BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
{
MOZ_ASSERT(NS_IsMainThread());
if (mResultHandlerQ.IsEmpty()) {
if (sNotificationHandler) {
// Bluetooth daemon crashed; clear state
sNotificationHandler->AdapterStateChangedNotification(false);
sNotificationHandler = nullptr;
}
return;
}
switch (aChannel) {
case CMD_CHANNEL:
// We don't have to do anything here. Step 4 is triggered
// by the daemon.
break;
case NTF_CHANNEL:
// Cleanup, step 4: Close listen socket
// Cleanup, step 4 (Recovery, step 1): Close listen socket
mListenSocket->Close();
break;
case LISTEN_SOCKET: {
case LISTEN_SOCKET:
if (!mResultHandlerQ.IsEmpty()) {
nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
mResultHandlerQ.RemoveElementAt(0);
// Cleanup, step 5: Signal success to caller
if (res) {
res->Cleanup();
@ -1924,6 +1996,20 @@ BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
}
break;
}
/* For recovery make sure all sockets disconnected, in order to avoid
* the remaining disconnects interfere with the restart procedure.
*/
if (sNotificationHandler && mResultHandlerQ.IsEmpty()) {
if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED &&
mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) {
// Assume daemon crashed during regular service; notify
// BluetoothServiceBluedroid to prepare restart-daemon procedure
sNotificationHandler->BackendErrorNotification(true);
sNotificationHandler = nullptr;
}
}
}
class BluetoothDaemonSocketConnector final
@ -2198,16 +2284,18 @@ private:
void
BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
{
sNotificationHandler = nullptr;
mResultHandlerQ.AppendElement(aRes);
sNotificationHandler = nullptr;
// Cleanup, step 1: Unregister Socket module
nsresult rv = mProtocol->UnregisterModuleCmd(
0x02, new CleanupResultHandler(this));
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
return;
}
mResultHandlerQ.AppendElement(aRes);
}
void

View File

@ -24,11 +24,13 @@ class BluetoothDaemonInterface final : public BluetoothInterface
public:
class CleanupResultHandler;
class InitResultHandler;
class StartDaemonTask;
friend class BluetoothDaemonListenSocket;
friend class BluetoothDaemonChannel;
friend class CleanupResultHandler;
friend class InitResultHandler;
friend class StartDaemonTask;
static BluetoothDaemonInterface* GetInstance();

View File

@ -102,6 +102,8 @@ static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
static bool sIsRestart(false);
static bool sIsFirstTimeToggleOffBt(false);
/**
* Static callback functions
@ -598,6 +600,8 @@ static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
static bool sAdapterDiscoverable(false);
static bool sIsRestart(false);
static bool sIsFirstTimeToggleOffBt(false);
static uint32_t sAdapterDiscoverableTimeout(0);
/**
@ -2127,7 +2131,11 @@ public:
private:
void Proceed() const
{
sBtInterface->Cleanup(nullptr);
if (!sIsRestart) {
sBtInterface->Cleanup(nullptr);
} else {
BT_LOGR("ProfileDeinitResultHandler::Proceed cancel cleanup() ");
}
}
unsigned char mNumProfiles;
@ -2231,6 +2239,12 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
BT_LOGR("BT_STATE: %d", aState);
if (sIsRestart && aState) {
// daemon restarted, reset flag
BT_LOGR("daemon restarted, reset flag");
sIsRestart = false;
sIsFirstTimeToggleOffBt = false;
}
bool isBtEnabled = (aState == true);
if (!isBtEnabled) {
@ -2279,6 +2293,11 @@ BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState)
BT_LOGR("Fail to start BluetoothOppManager listening");
}
}
// After ProfileManagers deinit and cleanup, now restarts bluetooth daemon
if (sIsRestart && !aState) {
BT_LOGR("sIsRestart and off, now restart");
StartBluetooth(false);
}
#endif
}
@ -3074,3 +3093,39 @@ BluetoothServiceBluedroid::EnergyInfoNotification(
// FIXME: This will be implemented in the later patchset
}
#endif
void
BluetoothServiceBluedroid::BackendErrorNotification(bool aCrashed)
{
MOZ_ASSERT(NS_IsMainThread());
// Recovery step 2 stop bluetooth
if (aCrashed) {
BT_LOGR("Set aRestart = true");
sIsRestart = true;
BT_LOGR("Reocvery step2: stop bluetooth");
#ifdef MOZ_B2G_BT_API_V2
StopBluetooth(false, nullptr);
#else
StopBluetooth(false);
#endif
}
}
void
BluetoothServiceBluedroid::CompleteToggleBt(bool aEnabled)
{
MOZ_ASSERT(NS_IsMainThread());
if (sIsRestart && !aEnabled && sIsFirstTimeToggleOffBt) {
// Both StopBluetooth and AdapterStateChangedNotification
// trigger CompleteToggleBt. We don't need to call CompleteToggleBt again
} else if (sIsRestart && !aEnabled && !sIsFirstTimeToggleOffBt) {
// Recovery step 3: cleanup and deinit Profile managers
BT_LOGR("CompleteToggleBt set sIsFirstTimeToggleOffBt = true");
sIsFirstTimeToggleOffBt = true;
BluetoothService::CompleteToggleBt(aEnabled);
AdapterStateChangedNotification(false);
} else {
BluetoothService::CompleteToggleBt(aEnabled);
}
}

View File

@ -300,7 +300,9 @@ public:
uint8_t aLen) override;
virtual void LeTestModeNotification(BluetoothStatus aStatus,
uint16_t aNumPackets) override;
virtual void BackendErrorNotification(bool aCrashed) override;
virtual void CompleteToggleBt(bool aEnabled) override;
protected:
static nsresult StartGonkBluetooth();
static nsresult StopGonkBluetooth();
@ -527,6 +529,9 @@ public:
virtual void EnergyInfoNotification(
const BluetoothActivityEnergyInfo& aInfo) override;
virtual void BackendErrorNotification(bool aCrashed) override;
virtual void CompleteToggleBt(bool aEnabled) override;
protected:
static nsresult StartGonkBluetooth();
static nsresult StopGonkBluetooth();

View File

@ -1283,6 +1283,7 @@ void
BluetoothHfpManager::OnDisconnectError()
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(mController);
mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
}

View File

@ -365,6 +365,9 @@ protected:
virtual nsresult
HandleStartup();
virtual void
CompleteToggleBt(bool aEnabled);
/**
* Called when the startup settings check has completed.
*/
@ -391,7 +394,6 @@ protected:
static BluetoothService*
Create();
void CompleteToggleBt(bool aEnabled);
typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
BluetoothSignalObserverTable;

View File

@ -256,6 +256,8 @@ BluetoothGatt::DiscoverServices(ErrorResult& aRv)
BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
mDiscoveringServices = true;
mServices.Clear();
BluetoothGattBinding::ClearCachedServicesValue(this);
nsRefPtr<BluetoothReplyRunnable> result =
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
promise,
@ -292,6 +294,7 @@ BluetoothGatt::HandleServicesDiscovered(const BluetoothValue& aValue)
const InfallibleTArray<BluetoothGattServiceId>& serviceIds =
aValue.get_ArrayOfBluetoothGattServiceId();
mServices.Clear();
for (uint32_t i = 0; i < serviceIds.Length(); i++) {
mServices.AppendElement(new BluetoothGattService(
GetParentObject(), mAppUuid, serviceIds[i]));

View File

@ -149,6 +149,7 @@ BluetoothGattCharacteristic::HandleDescriptorsDiscovered(
const InfallibleTArray<BluetoothGattId>& descriptorIds =
aValue.get_ArrayOfBluetoothGattId();
mDescriptors.Clear();
for (uint32_t i = 0; i < descriptorIds.Length(); i++) {
mDescriptors.AppendElement(new BluetoothGattDescriptor(
GetParentObject(), this, descriptorIds[i]));
@ -194,8 +195,6 @@ void
BluetoothGattCharacteristic::GetValue(JSContext* cx,
JS::MutableHandle<JSObject*> aValue) const
{
MOZ_ASSERT(aValue);
aValue.set(mValue.IsEmpty()
? nullptr
: ArrayBuffer::Create(cx, mValue.Length(), mValue.Elements()));

View File

@ -112,8 +112,6 @@ void
BluetoothGattDescriptor::GetValue(JSContext* cx,
JS::MutableHandle<JSObject*> aValue) const
{
MOZ_ASSERT(aValue);
aValue.set(mValue.IsEmpty()
? nullptr
: ArrayBuffer::Create(cx, mValue.Length(), mValue.Elements()));

View File

@ -85,6 +85,7 @@ BluetoothGattService::HandleIncludedServicesDiscovered(
const InfallibleTArray<BluetoothGattServiceId>& includedServIds =
aValue.get_ArrayOfBluetoothGattServiceId();
mIncludedServices.Clear();
for (uint32_t i = 0; i < includedServIds.Length(); i++) {
mIncludedServices.AppendElement(new BluetoothGattService(
GetParentObject(), mAppUuid, includedServIds[i]));
@ -103,6 +104,7 @@ BluetoothGattService::HandleCharacteristicsDiscovered(
const InfallibleTArray<BluetoothGattCharAttribute>& characteristics =
aValue.get_ArrayOfBluetoothGattCharAttribute();
mCharacteristics.Clear();
for (uint32_t i = 0; i < characteristics.Length(); i++) {
mCharacteristics.AppendElement(new BluetoothGattCharacteristic(
GetParentObject(), this, characteristics[i]));

View File

@ -515,6 +515,9 @@ protected:
virtual nsresult
HandleStartup();
virtual void
CompleteToggleBt(bool aEnabled);
/**
* Called when the startup settings check has completed.
*/
@ -541,9 +544,6 @@ protected:
static BluetoothService*
Create();
void
CompleteToggleBt(bool aEnabled);
typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
BluetoothSignalObserverTable;

View File

@ -1850,6 +1850,8 @@ MediaManager::GetUserMedia(
false) ||
#if defined(XP_MACOSX) || defined(XP_WIN)
(
// Allow tab sharing for all platforms including XP and OSX 10.6
(src != dom::MediaSourceEnum::Browser) &&
!Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms",
false) &&
#if defined(XP_MACOSX)

View File

@ -377,7 +377,8 @@ bool
MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType)
{
return (aMimeType.EqualsLiteral("audio/mpeg") ||
aMimeType.EqualsLiteral("audio/mp4a-latm")) &&
aMimeType.EqualsLiteral("audio/mp4a-latm") ||
aMimeType.EqualsLiteral("audio/3gpp")) &&
mPlatform->SupportsMimeType(aMimeType);
}

View File

@ -50,8 +50,9 @@ GonkAudioDecoderManager::GonkAudioDecoderManager(
{
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
MOZ_ASSERT(mAudioChannels);
mUserData.AppendElements(aConfig.mCodecSpecificConfig->Elements(),
aConfig.mCodecSpecificConfig->Length());
mCodecSpecificData = aConfig.mCodecSpecificConfig;
mMimeType = aConfig.mMimeType;
// Pass through mp3 without applying an ADTS header.
if (!aConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
mUseAdts = false;
@ -66,6 +67,7 @@ GonkAudioDecoderManager::~GonkAudioDecoderManager()
android::sp<MediaCodecProxy>
GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
{
status_t rv = OK;
if (mLooper != nullptr) {
return nullptr;
}
@ -74,7 +76,7 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
mLooper->setName("GonkAudioDecoderManager");
mLooper->start();
mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, nullptr);
mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr);
if (!mDecoder.get()) {
return nullptr;
}
@ -85,8 +87,8 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
}
sp<AMessage> format = new AMessage;
// Fixed values
GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);
format->setString("mime", "audio/mp4a-latm");
GADM_LOG("Configure audio mime type:%s, chan no:%d, sample-rate:%d", mMimeType.get(), mAudioChannels, mAudioRate);
format->setString("mime", mMimeType.get());
format->setInt32("channel-count", mAudioChannels);
format->setInt32("sample-rate", mAudioRate);
format->setInt32("aac-profile", mAudioProfile);
@ -95,8 +97,11 @@ GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
if (err != OK || !mDecoder->Prepare()) {
return nullptr;
}
status_t rv = mDecoder->Input(mUserData.Elements(), mUserData.Length(), 0,
android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
if (mMimeType.EqualsLiteral("audio/mp4a-latm")) {
rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0,
android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
}
if (rv == OK) {
return mDecoder;

View File

@ -51,7 +51,6 @@ private:
const uint32_t mAudioChannels;
const uint32_t mAudioRate;
const uint32_t mAudioProfile;
nsTArray<uint8_t> mUserData;
bool mUseAdts;
MediaDataDecoderCallback* mReaderCallback;

View File

@ -65,6 +65,7 @@ bool
GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType)
{
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
aMimeType.EqualsLiteral("audio/3gpp") ||
aMimeType.EqualsLiteral("video/mp4") ||
aMimeType.EqualsLiteral("video/mp4v-es") ||
aMimeType.EqualsLiteral("video/avc");

View File

@ -69,6 +69,10 @@ protected:
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
RefPtr<MediaTaskQueue> mTaskQueue;
nsRefPtr<MediaByteBuffer> mCodecSpecificData;
nsAutoCString mMimeType;
};
// Samples are decoded using the GonkDecoder (MediaCodec)

View File

@ -494,7 +494,7 @@ GonkVideoDecoderManager::codecReserved()
sp<Surface> surface;
status_t rv = OK;
// Fixed values
GVDM_LOG("Configure mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
GVDM_LOG("Configure video mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
format->setString("mime", mMimeType.get());
format->setInt32("width", mVideoWidth);
format->setInt32("height", mVideoHeight);

View File

@ -147,7 +147,6 @@ private:
android::MediaBuffer* mVideoBuffer;
nsRefPtr<MediaByteBuffer> mCodecSpecificData;
MediaDataDecoderCallback* mReaderCallback;
MediaInfo mInfo;
android::sp<VideoResourceListener> mVideoListener;
@ -178,7 +177,6 @@ private:
// The lock protects mPendingVideoBuffers.
Mutex mPendingVideoBuffersLock;
nsAutoCString mMimeType;
};
} // namespace mozilla

View File

@ -0,0 +1,47 @@
/* 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/. */
#include "mozilla/dom/MozMobileMessageManagerBinding.h"
#include "nsISmsService.h"
namespace mozilla {
namespace dom {
namespace mobilemessage {
#define ASSERT_SMS_EQUALITY(webidlType, webidlState, xpidlState) \
static_assert(static_cast<uint32_t>(webidlType::webidlState) == nsISmsService::xpidlState, \
#webidlType "::" #webidlState " should equal to nsISmsService::" #xpidlState)
/**
* Enum TypeOfNumber
*/
#define ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(webidlState, xpidlState) \
ASSERT_SMS_EQUALITY(TypeOfNumber, webidlState, xpidlState)
ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Unknown, TYPE_OF_NUMBER_UNKNOWN);
ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(International, TYPE_OF_NUMBER_INTERNATIONAL);
ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(National, TYPE_OF_NUMBER_NATIONAL);
ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Network_specific, TYPE_OF_NUMBER_NETWORK_SPECIFIC);
ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Dedicated_access_short_code, TYPE_OF_NUMBER_DEDICATED_ACCESS_SHORT_CODE);
#undef ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY
/**
* Enum NumberPlanIdentification
*/
#define ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(webidlState, xpidlState) \
ASSERT_SMS_EQUALITY(NumberPlanIdentification, webidlState, xpidlState)
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Unknown, NUMBER_PLAN_IDENTIFICATION_UNKNOWN);
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Isdn, NUMBER_PLAN_IDENTIFICATION_ISDN);
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Data, NUMBER_PLAN_IDENTIFICATION_DATA);
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Telex, NUMBER_PLAN_IDENTIFICATION_TELEX);
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(National, NUMBER_PLAN_IDENTIFICATION_NATIONAL);
ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Private, NUMBER_PLAN_IDENTIFICATION_PRIVATE);
#undef ASSERT_SMS_EQUALITY
} // namespace mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -17,6 +17,7 @@
#include "nsServiceManagerUtils.h"
#include "nsTArrayHelpers.h"
#include "DOMMobileMessageError.h"
#include "mozilla/dom/Promise.h"
namespace mozilla {
namespace dom {
@ -80,6 +81,11 @@ MobileMessageCallback::MobileMessageCallback(DOMRequest* aDOMRequest)
{
}
MobileMessageCallback::MobileMessageCallback(Promise* aPromise)
: mPromise(aPromise)
{
}
MobileMessageCallback::~MobileMessageCallback()
{
}
@ -280,6 +286,21 @@ MobileMessageCallback::NotifyGetSmscAddressFailed(int32_t aError)
return NotifyError(aError);
}
NS_IMETHODIMP
MobileMessageCallback::NotifySetSmscAddress()
{
mPromise->MaybeResolve(JS::UndefinedHandleValue);
return NS_OK;
}
NS_IMETHODIMP
MobileMessageCallback::NotifySetSmscAddressFailed(int32_t aError)
{
const nsAString& errorStr = ConvertErrorCodeToErrorString(aError);
mPromise->MaybeRejectBrokenly(errorStr);
return NS_OK;
}
} // namesapce mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -10,6 +10,8 @@
#include "nsCOMPtr.h"
#include "DOMRequest.h"
class Promise;
namespace mozilla {
namespace dom {
namespace mobilemessage {
@ -21,11 +23,13 @@ public:
NS_DECL_NSIMOBILEMESSAGECALLBACK
explicit MobileMessageCallback(DOMRequest* aDOMRequest);
explicit MobileMessageCallback(Promise* aPromise);
private:
~MobileMessageCallback();
nsRefPtr<DOMRequest> mDOMRequest;
nsRefPtr<Promise> mPromise;
nsresult NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync = false);
nsresult NotifySuccess(nsISupports *aMessage, bool aAsync = false);

View File

@ -15,6 +15,7 @@
#include "mozilla/dom/MozMmsEvent.h"
#include "mozilla/dom/MozMobileMessageManagerBinding.h"
#include "mozilla/dom/MozSmsEvent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
@ -697,6 +698,72 @@ MobileMessageManager::GetSmscAddress(const Optional<uint32_t>& aServiceId,
return request.forget();
}
already_AddRefed<Promise>
MobileMessageManager::SetSmscAddress(const SmscAddress& aSmscAddress,
const Optional<uint32_t>& aServiceId,
ErrorResult& aRv)
{
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
if (!smsService) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
// Use the default one unless |serviceId| is available.
uint32_t serviceId;
nsresult rv;
if (aServiceId.WasPassed()) {
serviceId = aServiceId.Value();
} else {
rv = smsService->GetSmsDefaultServiceId(&serviceId);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
}
}
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (!global) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
if (aRv.Failed()) {
return nullptr;
}
if (!aSmscAddress.mAddress.WasPassed()) {
NS_WARNING("SmscAddress.address is a mandatory field and can not be omitted.");
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return promise.forget();
}
nsString address = aSmscAddress.mAddress.Value();
TypeOfNumber ton = aSmscAddress.mTypeOfAddress.mTypeOfNumber;
NumberPlanIdentification npi =
aSmscAddress.mTypeOfAddress.mNumberPlanIdentification;
// If the address begins with +, set TON to international no matter what has
// passed in.
if (!address.IsEmpty() && address[0] == '+') {
ton = TypeOfNumber::International;
}
nsCOMPtr<nsIMobileMessageCallback> msgCallback =
new MobileMessageCallback(promise);
rv = smsService->SetSmscAddress(serviceId, address,
static_cast<uint32_t>(ton), static_cast<uint32_t>(npi), msgCallback);
if (NS_FAILED(rv)) {
promise->MaybeReject(rv);
return promise.forget();
}
return promise.forget();
}
} // namespace dom
} // namespace mozilla

View File

@ -13,6 +13,7 @@
class nsISmsService;
class nsIDOMMozSmsMessage;
class nsIDOMMozMmsMessage;
class Promise;
namespace mozilla {
namespace dom {
@ -24,6 +25,7 @@ struct MmsSendParameters;
struct MobileMessageFilter;
class OwningLongOrMozSmsMessageOrMozMmsMessage;
struct SmsSendParameters;
struct SmscAddress;
class MobileMessageManager final : public DOMEventTargetHelper
, public nsIObserver
@ -115,6 +117,11 @@ public:
GetSmscAddress(const Optional<uint32_t>& aServiceId,
ErrorResult& aRv);
already_AddRefed<Promise>
SetSmscAddress(const SmscAddress& aSmscAddress,
const Optional<uint32_t>& aServiceId,
ErrorResult& aRv);
IMPL_EVENT_HANDLER(received)
IMPL_EVENT_HANDLER(retrieving)
IMPL_EVENT_HANDLER(sending)

View File

@ -69,7 +69,20 @@ SmsService::GetSmscAddress(uint32_t aServiceId,
nsIMobileMessageCallback *aRequest)
{
// TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress
return NS_OK;
NS_NOTYETIMPLEMENTED("Implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
SmsService::SetSmscAddress(uint32_t aServiceId,
const nsAString& aNumber,
uint32_t aTypeOfNumber,
uint32_t aNumberPlanIdentification,
nsIMobileMessageCallback* aRequest)
{
// TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress
NS_NOTYETIMPLEMENTED("Implement me!");
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace mobilemessage

View File

@ -802,7 +802,7 @@ SmsService.prototype = {
}
},
// An array of slient numbers.
// An array of silent numbers.
_silentNumbers: null,
_isSilentNumber: function(aNumber) {
return this._silentNumbers.indexOf(aNumber) >= 0;
@ -990,6 +990,30 @@ SmsService.prototype = {
});
},
setSmscAddress: function(aServiceId, aNumber, aTypeOfNumber,
aNumberPlanIdentification, aRequest) {
if (aServiceId > (gRadioInterfaces.length - 1)) {
throw Cr.NS_ERROR_INVALID_ARG;
}
let options = {
smscAddress: aNumber,
typeOfNumber: aTypeOfNumber,
numberPlanIdentification: aNumberPlanIdentification
};
gRadioInterfaces[aServiceId].sendWorkerMessage("setSmscAddress",
options,
(aResponse) => {
if (!aResponse.errorMsg) {
aRequest.notifySetSmscAddress();
} else {
aRequest.notifySetSmscAddressFailed(
Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR);
}
});
},
/**
* nsIGonkSmsService interface
*/

View File

@ -10,7 +10,7 @@
"@mozilla.org/sms/gonksmsservice;1"
%}
[scriptable, uuid(4dda515e-05ec-47b1-b750-e42c74576c43)]
[scriptable, uuid(76681431-8261-4540-bab8-24ef3866e8b6)]
interface nsIGonkSmsService : nsISmsService
{
const unsigned short SMS_MESSAGE_ENCODING_7BITS_ALPHABET = 0x00;

View File

@ -4,7 +4,7 @@
#include "nsISupports.idl"
[scriptable, uuid(35279dbc-9f1d-419f-b17a-230fcf49f0c7)]
[scriptable, uuid(b1367554-51c6-4153-b20a-effec50ca827)]
interface nsIMobileMessageCallback : nsISupports
{
/**
@ -54,4 +54,6 @@ interface nsIMobileMessageCallback : nsISupports
*/
void notifyGetSmscAddress(in DOMString aSmscAddress);
void notifyGetSmscAddressFailed(in long error);
void notifySetSmscAddress();
void notifySetSmscAddressFailed(in long error);
};

View File

@ -12,7 +12,7 @@ interface nsIMobileMessageCallback;
#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
%}
[scriptable, uuid(ae688bca-00c9-4d08-945d-e8a5272ad5b1)]
[scriptable, uuid(c8ca5f06-ad76-44b0-a324-9e2910fd37da)]
interface nsISmsService : nsISupports
{
/**
@ -41,22 +41,131 @@ interface nsISmsService : nsISupports
const unsigned short DELIVERY_STATUS_TYPE_PENDING = 2;
const unsigned short DELIVERY_STATUS_TYPE_ERROR = 3;
/**
* Constant definitions of SM-RP type of number as defined in
* |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
*/
const unsigned short TYPE_OF_NUMBER_UNKNOWN = 0;
const unsigned short TYPE_OF_NUMBER_INTERNATIONAL = 1;
const unsigned short TYPE_OF_NUMBER_NATIONAL = 2;
const unsigned short TYPE_OF_NUMBER_NETWORK_SPECIFIC = 3;
const unsigned short TYPE_OF_NUMBER_DEDICATED_ACCESS_SHORT_CODE = 4;
/**
* Constant definitions of SM-RP number plan identification as defined in
* |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
*/
const unsigned short NUMBER_PLAN_IDENTIFICATION_UNKNOWN = 0;
const unsigned short NUMBER_PLAN_IDENTIFICATION_ISDN = 1;
const unsigned short NUMBER_PLAN_IDENTIFICATION_DATA = 2;
const unsigned short NUMBER_PLAN_IDENTIFICATION_TELEX = 3;
const unsigned short NUMBER_PLAN_IDENTIFICATION_NATIONAL = 4;
const unsigned short NUMBER_PLAN_IDENTIFICATION_PRIVATE = 5;
/**
* The default RIL service ID used for SMS.
*/
readonly attribute unsigned long smsDefaultServiceId;
/**
* Get the information necessary to create a multi-part SMS for a given text.
*
* @param text
* The text message content.
* @param request
* The callback object to use. It invokes
* |notifySegmentInfoForTextGot| on success, or
* |notifyGetSegmentInfoForTextFailed| on failure.
*/
void getSegmentInfoForText(in DOMString text,
in nsIMobileMessageCallback request);
/**
* Send a SMS.
*
* @param serviceId
* The ID of RIL service to use.
* @param number
* Destination number in string.
* @param message
* The text message content.
* @param silent
* |true| to send a silent message. It's used to make a SMS based
* authentication for some services such as mobile billing.
* @param request
* The callback object to use. It invokes |notifyMessageSent| on
* success, or |notifySendMessageFailed| on failure.
* @throws NS_ERROR_INVALID_ARG
* If |serviceId| exceeds the max value of available IDs.
*/
void send(in unsigned long serviceId,
in DOMString number,
in DOMString message,
in boolean silent,
in nsIMobileMessageCallback request);
/**
* Add a number to the list of silent message originators. When receiving a
* SMS sent from one of the numbers in the list, |SmsService| will notify
* observers through the topic "silent-sms-received".
*
* It's used when a SMS based authentication has been initiated and the client
* is waiting for an incoming silent message containing the authentication
* result.
*
* @param number
* Originator number in string.
* @throw NS_ERROR_UNEXPECTED
* If the given number has already been added before.
*/
void addSilentNumber(in DOMString number);
/**
* Remove a number from the silent message originator list.
*
* @param number
* Originator number in string.
* @throws NS_ERROR_INVALID_ARG
* If the number doesn't exist in the list.
*/
void removeSilentNumber(in DOMString number);
/**
* Get the short message service center address of given |serviceId|.
*
* @param serviceId
* The ID of RIL service to use.
* @param request
* The callback object to use. It invokes |notifyGetSmscAddress| on
* success, or |notifyGetSmscAddressFailed| on failure.
* @throws NS_ERROR_INVALID_ARG
* If |serviceId| exceeds the max value of available IDs.
*/
void getSmscAddress(in unsigned long serviceId,
in nsIMobileMessageCallback request);
/**
* Set the short message service center address of given |serviceId|.
*
* @param serviceId
* The ID of RIL service to use.
* @param number
* Number part of the SMSC address.
* @param typeOfNumber
* Type of number of the SMSC address.
* @param numberPlanIdentification
* Number plan identification of the SMSC address.
* @param request
* The callback object to use. It invokes |notifySetSmscAddress| on
* success, or |notifySetSmscAddressFailed| on failure.
* @throws NS_ERROR_INVALID_ARG
* If |serviceId| exceeds the max value of available IDs.
*/
void setSmscAddress(in unsigned long serviceId,
in DOMString number,
in unsigned long typeOfNumber,
in unsigned long numberPlanIdentification,
in nsIMobileMessageCallback request);
};
%{C++

View File

@ -79,6 +79,14 @@ struct GetSmscAddressRequest
uint32_t serviceId;
};
struct SetSmscAddressRequest
{
uint32_t serviceId;
nsString number;
uint32_t typeOfNumber;
uint32_t numberPlanIdentification;
};
union IPCSmsRequest
{
SendMessageRequest;
@ -88,6 +96,7 @@ union IPCSmsRequest
MarkMessageReadRequest;
GetSegmentInfoForTextRequest;
GetSmscAddressRequest;
SetSmscAddressRequest;
};
union IPCMobileMessageCursor

View File

@ -94,6 +94,15 @@ struct ReplyGetSmscAddressFail
int32_t error;
};
struct ReplySetSmscAddress
{
};
struct ReplySetSmscAddressFail
{
int32_t error;
};
union MessageReply
{
ReplyMessageSend;
@ -108,6 +117,8 @@ union MessageReply
ReplyGetSegmentInfoForTextFail;
ReplyGetSmscAddress;
ReplyGetSmscAddressFail;
ReplySetSmscAddress;
ReplySetSmscAddressFail;
};
} // namespace mobilemessage

View File

@ -262,6 +262,12 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply)
case MessageReply::TReplyGetSmscAddressFail:
mReplyRequest->NotifyGetSmscAddressFailed(aReply.get_ReplyGetSmscAddressFail().error());
break;
case MessageReply::TReplySetSmscAddress:
mReplyRequest->NotifySetSmscAddress();
break;
case MessageReply::TReplySetSmscAddressFail:
mReplyRequest->NotifySetSmscAddressFailed(aReply.get_ReplySetSmscAddressFail().error());
break;
default:
MOZ_CRASH("Received invalid response parameters!");
}

View File

@ -181,6 +181,21 @@ SmsIPCService::GetSmscAddress(uint32_t aServiceId,
return SendRequest(GetSmscAddressRequest(aServiceId), aRequest);
}
NS_IMETHODIMP
SmsIPCService::SetSmscAddress(uint32_t aServiceId,
const nsAString& aNumber,
uint32_t aTypeOfNumber,
uint32_t aNumberPlanIdentification,
nsIMobileMessageCallback* aRequest)
{
return SendRequest(SetSmscAddressRequest(aServiceId,
nsString(aNumber),
aTypeOfNumber,
aNumberPlanIdentification),
aRequest);
}
NS_IMETHODIMP
SmsIPCService::Send(uint32_t aServiceId,
const nsAString& aNumber,

View File

@ -406,6 +406,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
case IPCSmsRequest::TGetSmscAddressRequest:
return actor->DoRequest(aRequest.get_GetSmscAddressRequest());
case IPCSmsRequest::TSetSmscAddressRequest:
return actor->DoRequest(aRequest.get_SetSmscAddressRequest());
default:
MOZ_CRASH("Unknown type!");
}
@ -574,6 +576,29 @@ SmsRequestParent::DoRequest(const GetSmscAddressRequest& aRequest)
return true;
}
bool
SmsRequestParent::DoRequest(const SetSmscAddressRequest& aRequest)
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
if (smsService) {
rv = smsService->SetSmscAddress(aRequest.serviceId(),
aRequest.number(),
aRequest.typeOfNumber(),
aRequest.numberPlanIdentification(),
this);
} else {
return NS_SUCCEEDED(NotifySetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
}
if (NS_FAILED(rv)) {
return NS_SUCCEEDED(NotifySetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
}
return true;
}
bool
SmsRequestParent::DoRequest(const DeleteMessageRequest& aRequest)
{
@ -746,6 +771,18 @@ SmsRequestParent::NotifyGetSmscAddressFailed(int32_t aError)
return SendReply(ReplyGetSmscAddressFail(aError));
}
NS_IMETHODIMP
SmsRequestParent::NotifySetSmscAddress()
{
return SendReply(ReplySetSmscAddress());
}
NS_IMETHODIMP
SmsRequestParent::NotifySetSmscAddressFailed(int32_t aError)
{
return SendReply(ReplySetSmscAddressFail(aError));
}
/*******************************************************************************
* MobileMessageCursorParent
******************************************************************************/

View File

@ -117,6 +117,9 @@ protected:
bool
DoRequest(const GetSmscAddressRequest& aRequest);
bool
DoRequest(const SetSmscAddressRequest& aRequest);
nsresult
SendReply(const MessageReply& aReply);
};

View File

@ -50,6 +50,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
'Assertions.cpp',
'Constants.cpp',
'DeletedMessageInfo.cpp',
'DOMMobileMessageError.cpp',

View File

@ -52,3 +52,4 @@ qemu = true
[test_ondeleted_event.js]
[test_decode_spanish_fallback.js]
[test_update_gsm_nl_on_mcc_chanages.js]
[test_set_smsc_address.js]

View File

@ -0,0 +1,72 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
const SMSC_ATT = '+13123149810';
const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0';
const SMSC_ATT_TEXT = '"+13123149810",145';
const SMSC_O2 = '+447802000332';
const SMSC_O2_TEXT = '"+447802000332",145';
const SMSC_DEF = '+123456789';
const SMSC_DEF_TEXT = '"+123456789",145';
const SMSC_TON_UNKNOWN = '0407485455'
const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129';
function getSmscAddress() {
return new Promise((resolve, reject) => {
let req = manager.getSmscAddress();
if (!req) {
reject("manager.getSmscAddress() returns null.");
}
req.onsuccess = function() {
resolve(this.result);
};
req.onerror = function() {
reject(this.error);
};
});
};
startTestBase(function testCaseMain() {
return ensureMobileMessage()
// Verify setting AT&T SMSC address.
.then(() => manager.setSmscAddress({ address:SMSC_ATT }))
.then(() => getSmscAddress())
.then((result) => is(result, SMSC_ATT_TEXT))
// Verify setting O2 SMSC address.
.then(() => manager.setSmscAddress({ address:SMSC_O2 }))
.then(() => getSmscAddress())
.then((result) => is(result, SMSC_O2_TEXT))
// Verify setting AT&T SMSC address with extra illegal characters.
.then(() => manager.setSmscAddress({ address:SMSC_ATT_TYPO }))
.then(() => getSmscAddress())
.then((result) => is(result, SMSC_ATT_TEXT))
// Verify setting a SMSC address with TON=unknown.
.then(() => manager.setSmscAddress({ address:SMSC_TON_UNKNOWN }))
.then(() => getSmscAddress())
.then((result) => is(result, SMSC_TON_UNKNOWN_TEXT))
// Verify setting invalid SMSC address.
.then(() => manager.setSmscAddress({}))
.then(() => Promise.reject("Expect for an error."),
(err) => log("Got expected error: " + err))
.then(() => manager.setSmscAddress({ address:"" }))
.then(() => Promise.reject("Expect for an error."),
(err) => log("Got expected error: " + err))
.then(() => manager.setSmscAddress({ address:"???" }))
.then(() => Promise.reject("Expect for an error."),
(err) => log("Got expected error: " + err))
// Restore to default emulator SMSC address.
.then(() => manager.setSmscAddress({ address:SMSC_DEF }))
.then(() => getSmscAddress())
.then((result) => is(result, SMSC_DEF_TEXT));
});

View File

@ -1494,6 +1494,8 @@ WorkerMessenger.prototype = {
libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true",
sendStkProfileDownload:
libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
smscAddressFormat:
libcutils.property_get("ro.moz.ril.smsc_address_format", "text"),
dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL,
signalExtraInt: RILQUIRKS_SIGNAL_EXTRA_INT32

View File

@ -1406,6 +1406,30 @@ this.CB_UMTS_MESSAGE_TYPE_CBS = 1;
this.CB_UMTS_MESSAGE_TYPE_SCHEDULE = 2;
this.CB_UMTS_MESSAGE_TYPE_CBS41 = 3;
/**
* Number plan identification defined in
* |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
*/
this.CALLED_PARTY_BCD_NPI_UNKNOWN = 0;
this.CALLED_PARTY_BCD_NPI_ISDN = 1;
this.CALLED_PARTY_BCD_NPI_DATA = 3;
this.CALLED_PARTY_BCD_NPI_TELEX = 4;
this.CALLED_PARTY_BCD_NPI_NATIONAL = 8;
this.CALLED_PARTY_BCD_NPI_PRIVATE = 9;
/**
* Array of number plan identification values which can be used to map an
* enumeration to the corresponding value.
*/
this.CALLED_PARTY_BCD_NPI = [
CALLED_PARTY_BCD_NPI_UNKNOWN,
CALLED_PARTY_BCD_NPI_ISDN,
CALLED_PARTY_BCD_NPI_DATA,
CALLED_PARTY_BCD_NPI_TELEX,
CALLED_PARTY_BCD_NPI_NATIONAL,
CALLED_PARTY_BCD_NPI_PRIVATE
];
/**
* GSM PDU constants
*/

View File

@ -86,6 +86,9 @@ let RILQUIRKS_SUBSCRIPTION_CONTROL;
let RILQUIRKS_SIGNAL_EXTRA_INT32;
// Ril quirk to describe the SMSC address format.
let RILQUIRKS_SMSC_ADDRESS_FORMAT;
/**
* The RIL state machine.
*
@ -1728,12 +1731,91 @@ RilObject.prototype = {
* Set the Short Message Service Center address.
*
* @param smscAddress
* Short Message Service Center address in PDU format.
* Number part of the SMSC address.
* @param typeOfNumber
* Type of number in integer, as defined in
* |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
* @param numberPlanIdentification
* Number plan identification in integer, as defined in
* |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
*/
setSmscAddress: function(options) {
let ton = options.typeOfNumber;
let npi = CALLED_PARTY_BCD_NPI[options.numberPlanIdentification];
// If any of the mandatory arguments is not available, return an error
// immediately.
if (ton === undefined || npi === undefined || !options.smscAddress) {
options.errorMsg = GECKO_ERROR_INVALID_PARAMETER;
this.sendChromeMessage(options);
return;
}
// Remove all illegal characters in the number string for user-input fault
// tolerance.
let numStart = options.smscAddress[0] === "+" ? 1 : 0;
let number = options.smscAddress.substring(0, numStart) +
options.smscAddress.substring(numStart)
.replace(/[^0-9*#abc]/ig, "");
// If the filtered number is an empty string, return an error immediately.
if (number.length === 0) {
options.errorMsg = GECKO_ERROR_INVALID_PARAMETER;
this.sendChromeMessage(options);
return;
}
// Init parcel.
this.SMSC = null;
let Buf = this.context.Buf;
Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options);
Buf.writeString(options.smscAddress);
// +---+-----------+---------------+
// | 1 | TON | NPI |
// +---+-----------+---------------+
let tosca = (0x1 << 7) + (ton << 4) + npi;
if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") {
let pduHelper = this.context.GsmPDUHelper;
// Remove the preceding '+', and covert the special BCD digits defined in
// |Called party BCD number| of 3GPP TS 24.008 to corresponding
// hexadecimal values (refer the following table).
//
// +=========+=======+=====+
// | value | digit | hex |
// +========================
// | 1 0 1 0 | * | 0xA |
// | 1 0 1 1 | # | 0xB |
// | 1 1 0 0 | a | 0xC |
// | 1 1 0 1 | b | 0xD |
// | 1 1 1 0 | c | 0xE |
// +=========+=======+=====+
//
// The replace order is reversed intentionally, because if the digits are
// replaced in ascending order, "#" will be converted to "b" and then be
// converted again to "d", which generates incorrect result.
let pureNumber = number.substring(numStart)
.replace(/c/ig, "e")
.replace(/b/ig, "d")
.replace(/a/ig, "c")
.replace(/\#/g, "b")
.replace(/\*/g, "a");
// address length and string length
let length = Math.ceil(pureNumber.length / 2) + 1; // +1 octet for TOA
let strlen = length * 2 + 2; // +2 semi-octets for length octet
Buf.writeInt32(strlen);
pduHelper.writeHexOctet(length);
pduHelper.writeHexOctet(tosca);
pduHelper.writeSwappedNibbleBCD(pureNumber);
Buf.writeStringDelimiter(strlen);
} else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ {
let sca;
sca = '"' + number + '"' + ',' + tosca;
Buf.writeString(sca);
}
Buf.sendParcel();
},
@ -5506,7 +5588,17 @@ RilObject.prototype[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRES
options.smscAddress = this.SMSC;
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = null;
RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS(length, options) {
if (!options.rilMessageType || options.rilMessageType !== "setSmscAddress") {
return;
}
if (options.rilRequestError) {
optioins.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
}
this.sendChromeMessage(options);
};
RilObject.prototype[REQUEST_REPORT_SMS_MEMORY_STATUS] = function REQUEST_REPORT_SMS_MEMORY_STATUS(length, options) {
this.pendingToReportSmsMemoryStatus = !!options.errorMsg;
};
@ -15398,6 +15490,7 @@ let ContextPool = {
RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand;
RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl;
RILQUIRKS_SIGNAL_EXTRA_INT32 = quirks.signalExtraInt;
RILQUIRKS_SMSC_ADDRESS_FORMAT = quirks.smscAddressFormat;
},
setDebugFlag: function(aOptions) {

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
const SMSC_ATT = '+13123149810';
const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0';
const SMSC_ATT_TEXT = '"+13123149810",145';
const SMSC_ATT_PDU = '07913121139418F0';
const SMSC_O2 = '+447802000332';
const SMSC_O2_TEXT = '"+447802000332",145';
const SMSC_O2_PDU = '0791448720003023';
const SMSC_TON_UNKNOWN = '0407485455'
const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129';
const SMSC_TON_UNKNOWN_PDU = '06814070844555';
function run_test() {
run_next_test();
}
function setSmsc(context, smsc, ton, npi, expected) {
context.Buf.sendParcel = function() {
equal(this.readString(), expected);
};
context.RIL.setSmscAddress({
smscAddress: smsc,
typeOfNumber: ton,
numberPlanIdentification: npi
});
}
add_test(function test_setSmscAddress() {
let worker = newUint8Worker();
let context = worker.ContextPool._contexts[0];
let parcelTypes = [];
context.Buf.newParcel = (type, options) => parcelTypes.push(type);
// Test text mode.
worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text";
setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_TEXT);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_TEXT);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_TEXT);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_TEXT);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
// Test pdu mode.
worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu";
setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_PDU);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_PDU);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_PDU);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_PDU);
equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
run_next_test();
});

View File

@ -22,6 +22,7 @@ skip-if = true
[test_ril_worker_sms_nl_tables.js]
[test_ril_worker_sms_gsmpduhelper.js]
[test_ril_worker_sms_segment_info.js]
[test_ril_worker_smsc_address.js]
[test_ril_worker_mmi.js]
[test_ril_worker_mmi_cf.js]
[test_ril_worker_cf.js]

View File

@ -75,6 +75,45 @@ dictionary MobileMessageFilter
[EnforceRange] unsigned long long? threadId = 0;
};
/**
* TON defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
* It's used in SM-RL originator / destination address element as defined in
* |8.2.5.2 Destination address element| of 3GPP TS 24.011.
*/
enum TypeOfNumber { "unknown", "international", "national", "network-specific",
"dedicated-access-short-code" };
/**
* NPI defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
* It's used in SM-RL originator / destination address element as defined in
* |8.2.5.2 Destination address element| of 3GPP TS 24.011.
*/
enum NumberPlanIdentification { "unknown", "isdn", "data", "telex", "national",
"private" };
/**
* Type of address used in SmscAddress.
*
* As described in |3.1 Parameters Definitions| of 3GPP TS 27.005, the default
* value of <tosca> should be 129 (typeOfNumber=unknown,
* numberPlanIdentification=isdn) if the number does not begin with '+'.
*
* |setSmscAddress| updates typeOfNumber to international automatically if the
* given number begins with '+'.
*/
dictionary TypeOfAddress {
TypeOfNumber typeOfNumber = "unknown";
NumberPlanIdentification numberPlanIdentification = "isdn";
};
/**
* SMSC address.
*/
dictionary SmscAddress {
DOMString address;
TypeOfAddress typeOfAddress;
};
[Pref="dom.sms.enabled",
CheckPermissions="sms",
AvailableIn="CertifiedApps"]
@ -157,6 +196,22 @@ interface MozMobileMessageManager : EventTarget
[Throws]
DOMRequest getSmscAddress(optional unsigned long serviceId);
/**
* Set the SMSC address.
*
* @param smscAddress
* SMSC address to use.
* Reject if smscAddress.address does not present.
* @param serviceId (optional)
* The ID of the RIL service which needs to be specified under
* the multi-sim scenario.
* @return a Promise
* Resolve if success. Otherwise, reject with error cause.
*/
[NewObject]
Promise<void> setSmscAddress(optional SmscAddress smscAddress,
optional unsigned long serviceId);
attribute EventHandler onreceived;
attribute EventHandler onretrieving;
attribute EventHandler onsending;

View File

@ -21,7 +21,7 @@ interface nsITabParent;
interface nsIURI;
interface nsIWebBrowserChrome;
[scriptable, uuid(e28f810b-9b49-4927-a4be-62a74fadfe21)]
[scriptable, uuid(b6c44689-f97e-4f32-a723-29eeddfbdc53)]
interface nsIWindowCreator2 : nsIWindowCreator {
@ -59,4 +59,14 @@ interface nsIWindowCreator2 : nsIWindowCreator {
in nsIURI uri,
in nsITabParent aOpeningTab,
out boolean cancel);
/**
* B2G multi-screen support. When open another top-level window on b2g,
* a screen ID is needed for identifying which screen this window is
* opened to.
* @param aScreenId Differentiate screens of windows. It is platform-
* specific due to the hardware limitation for now.
*/
[noscript]
void setScreenId(in uint32_t aScreenId);
};

View File

@ -18,6 +18,7 @@
#include "nsIDocument.h"
#include "nsIDOMWindow.h"
#include "nsRefreshDriver.h"
#include "nsView.h"
#define APZCCH_LOG(...)
// #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
@ -499,6 +500,21 @@ GetDisplayportElementFor(nsIScrollableFrame* aScrollableFrame)
return content->AsElement();
}
static dom::Element*
GetRootDocumentElementFor(nsIWidget* aWidget)
{
// This returns the root element that ChromeProcessController sets the
// displayport on during initialization.
if (nsView* view = nsView::GetViewFor(aWidget)) {
if (nsIPresShell* shell = view->GetPresShell()) {
MOZ_ASSERT(shell->GetDocument());
return shell->GetDocument()->GetDocumentElement();
}
}
return nullptr;
}
// Determine the scrollable target frame for the given point and add it to
// the target list. If the frame doesn't have a displayport, set one.
// Return whether or not a displayport was set.
@ -515,7 +531,11 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget,
nsIFrame* target =
nsLayoutUtils::GetFrameForPoint(aRootFrame, point, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
nsIScrollableFrame* scrollAncestor = GetScrollableAncestorFrame(target);
nsCOMPtr<dom::Element> dpElement = GetDisplayportElementFor(scrollAncestor);
// Assuming that if there's no scrollAncestor, there's already a displayPort.
nsCOMPtr<dom::Element> dpElement = scrollAncestor
? GetDisplayportElementFor(scrollAncestor)
: GetRootDocumentElementFor(aWidget);
nsAutoString dpElementDesc;
if (dpElement) {
@ -534,6 +554,7 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget,
}
APZCCH_LOG("%p didn't have a displayport, so setting one...\n", dpElement.get());
MOZ_ASSERT(scrollAncestor);
return nsLayoutUtils::CalculateAndSetDisplayPortMargins(
scrollAncestor, nsLayoutUtils::RepaintMode::Repaint);
}

View File

@ -606,6 +606,17 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
// When doing so, it might be useful to look at how it was called here before
// bug 1036967 removed the (dead) call.
#if defined(MOZ_ANDROID_APZ)
if (mIsFirstPaint) {
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
mContentRect = metrics.GetScrollableRect();
SetFirstPaintViewport(scrollOffsetLayerPixels,
geckoZoom,
mContentRect);
}
#endif
mIsFirstPaint = false;
mLayersUpdated = false;

View File

@ -1521,12 +1521,12 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
nsIContent* content = nullptr;
if (scrollFrame) {
content = scrollFrame->GetContent();
} else if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
// If there is no root scroll frame, and we're using containerless
// scrolling, pick the document element instead.
// On Android we want the root xul document to get a null scroll id
// so that the root content document gets the first non-null scroll id.
#ifndef MOZ_WIDGET_ANDROID
} else {
// If there is no root scroll frame, pick the document element instead.
// The only case we don't want to do this is in non-APZ fennec, where
// we want the root xul document to get a null scroll id so that the root
// content document gets the first non-null scroll id.
#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
content = document->GetDocumentElement();
#endif
}

View File

@ -3115,6 +3115,17 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
}
}
}
#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
else if (presShell->GetDocument() && presShell->GetDocument()->IsRootDisplayDocument()) {
// In cases where the root document is a XUL document, we want to take
// the ViewID from the root element, as that will be the ViewID of the
// root APZC in the tree.
if (dom::Element* element = presShell->GetDocument()->GetDocumentElement()) {
id = nsLayoutUtils::FindOrCreateIDFor(element);
}
}
#endif
nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList",

View File

@ -38,7 +38,7 @@ public class TabQueueDispatcher extends Locales.LocaleAwareActivity {
// For the moment lets exit early and start fennec as normal if we're not in nightly with
// the tab queue build flag.
if (!AppConstants.MOZ_ANDROID_TAB_QUEUE) {
if (!AppConstants.MOZ_ANDROID_TAB_QUEUE || !AppConstants.NIGHTLY_BUILD) {
loadNormally(intent.getUnsafe());
return;
}

View File

@ -90,6 +90,7 @@ public class StringHelper {
public final String ROBOCOP_ADOBE_FLASH_URL = "/robocop/robocop_adobe_flash.html";
public final String ROBOCOP_INPUT_URL = "/robocop/robocop_input.html";
public final String ROBOCOP_READER_MODE_BASIC_ARTICLE = "/robocop/reader_mode_pages/basic_article.html";
public final String ROBOCOP_LINK_TO_SLOW_LOADING = "/robocop/robocop_link_to_slow_loading.html";
private final String ROBOCOP_JS_HARNESS_URL = "/robocop/robocop_javascript.html";

View File

@ -14,6 +14,7 @@ import org.mozilla.gecko.tests.components.AboutHomeComponent;
import org.mozilla.gecko.tests.components.AppMenuComponent;
import org.mozilla.gecko.tests.components.BaseComponent;
import org.mozilla.gecko.tests.components.GeckoViewComponent;
import org.mozilla.gecko.tests.components.TabStripComponent;
import org.mozilla.gecko.tests.components.ToolbarComponent;
import org.mozilla.gecko.tests.helpers.HelperInitializer;
@ -41,6 +42,7 @@ abstract class UITest extends BaseRobocopTest
protected AboutHomeComponent mAboutHome;
protected AppMenuComponent mAppMenu;
protected GeckoViewComponent mGeckoView;
protected TabStripComponent mTabStrip;
protected ToolbarComponent mToolbar;
@Override
@ -93,6 +95,7 @@ abstract class UITest extends BaseRobocopTest
mAboutHome = new AboutHomeComponent(this);
mAppMenu = new AppMenuComponent(this);
mGeckoView = new GeckoViewComponent(this);
mTabStrip = new TabStripComponent(this);
mToolbar = new ToolbarComponent(this);
}

View File

@ -0,0 +1,56 @@
package org.mozilla.gecko.tests.components;
import android.view.View;
import com.jayway.android.robotium.solo.Condition;
import org.mozilla.gecko.tests.UITestContext;
import org.mozilla.gecko.tests.helpers.DeviceHelper;
import org.mozilla.gecko.tests.helpers.WaitHelper;
import org.mozilla.gecko.widget.TwoWayView;
import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
/**
* A class representing any interactions that take place on the tablet tab strip.
*/
public class TabStripComponent extends BaseComponent {
// Using a text id because the layout and therefore the id might be stripped from the (non-tablet) build
private static final String TAB_STRIP_ID = "tab_strip";
public TabStripComponent(final UITestContext testContext) {
super(testContext);
}
public void switchToTab(int index) {
// The tab strip is only available on tablets
DeviceHelper.assertIsTablet();
View tabView = waitForTabView(index);
fAssertNotNull(String.format("Tab at index %d is not null", index), tabView);
mSolo.clickOnView(tabView);
}
private View waitForTabView(final int index) {
final TwoWayView tabStrip = getTabStripView();
final View[] tabView = new View[1];
WaitHelper.waitFor(String.format("Tab at index %d to be visible", index), new Condition() {
@Override
public boolean isSatisfied() {
return (tabView[0] = tabStrip.getChildAt(index)) != null;
}
});
return tabView[0];
}
private TwoWayView getTabStripView() {
TwoWayView tabStrip = (TwoWayView) mSolo.getView("tab_strip");
fAssertNotNull("Tab strip is not null", tabStrip);
return tabStrip;
}
}

View File

@ -84,6 +84,11 @@ public class ToolbarComponent extends BaseComponent {
return this;
}
public ToolbarComponent assertBackButtonIsNotEnabled() {
fAssertFalse("The back button is not enabled", isBackButtonEnabled());
return this;
}
/**
* Returns the root View for the browser toolbar.
*/
@ -306,4 +311,8 @@ public class ToolbarComponent extends BaseComponent {
private boolean isUrlEditTextSelected() {
return getUrlEditText().isSelected();
}
private boolean isBackButtonEnabled() {
return getBackButton().isEnabled();
}
}

View File

@ -0,0 +1,50 @@
package org.mozilla.gecko.tests.helpers;
import android.app.Activity;
import android.util.DisplayMetrics;
import com.jayway.android.robotium.solo.Solo;
import org.mozilla.gecko.Driver;
import org.mozilla.gecko.tests.StringHelper;
import org.mozilla.gecko.tests.UITestContext;
/**
* Provides helper functions for clicking elements rendered by the Gecko engine.
*/
public class GeckoClickHelper {
private static Solo sSolo;
private static Activity sActivity;
private static Driver sDriver;
protected static void init(final UITestContext context) {
sSolo = context.getSolo();
sActivity = context.getActivity();
sDriver = context.getDriver();
}
private GeckoClickHelper() { /* To disallow instantiation. */ }
/**
* Long press the link and select "Open Link in New Tab" from the context menu.
*
* The link should be positioned at the top of the page, at least 60px high and
* aligned to the middle.
*/
public static void openCentralizedLinkInNewTab() {
openLinkContextMenu();
// Click on "Open Link in New Tab"
sSolo.clickOnText(StringHelper.get().CONTEXT_MENU_ITEMS_IN_NORMAL_TAB[0]);
}
private static void openLinkContextMenu() {
DisplayMetrics dm = new DisplayMetrics();
sActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
sSolo.clickLongOnScreen(
sDriver.getGeckoLeft() + sDriver.getGeckoWidth() / 2,
sDriver.getGeckoTop() + 30 * dm.density
);
}
}

View File

@ -20,6 +20,7 @@ public final class HelperInitializer {
AssertionHelper.init(context);
DeviceHelper.init(context);
GeckoClickHelper.init(context);
GeckoHelper.init(context);
JavascriptBridge.init(context);
NavigationHelper.init(context);

View File

@ -166,6 +166,7 @@ skip-if = android_version == "10" || android_version == "18"
[testSessionHistory]
# disabled on Android 4.3, bug 1144879
skip-if = android_version == "18"
[testStateWhileLoading]
# testSelectionHandler disabled on Android 2.3 by trailing skip-if, due to bug 980074
# also disabled on Android 4.3, bug 1144882

View File

@ -0,0 +1,12 @@
<html>
<head>
<title>Link</title>
<meta name="viewport" content="initial-scale=1.0"/>
<meta charset="utf-8">
</head>
<body style="margin: 0; padding: 0">
<div style="text-align: center; margin: 0; padding: 0">
<a style="font-size: 60px" href="robocop_slow_loading.html">Slow Loading Page</a>
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<html>
<head>
<title>Slow Loading</title>
<meta name="viewport" content="initial-scale=1.0"/>
<meta charset="utf-8">
<script type="text/javascript">
// Busy wait (There's no sleep function in JavaScript)
var waitForMilliseconds = 10000;
var start = new Date();
var now = null;
do {
now = new Date();
} while (now - start < waitForMilliseconds);
</script>
</head>
<body style="margin: 0; padding: 0">
<div style="text-align: center; margin: 0; padding: 0">
<h1>This page is loading very slow.</h1>
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
package org.mozilla.gecko.tests;
import org.mozilla.gecko.tests.helpers.DeviceHelper;
import org.mozilla.gecko.tests.helpers.GeckoClickHelper;
import org.mozilla.gecko.tests.helpers.GeckoHelper;
import org.mozilla.gecko.tests.helpers.NavigationHelper;
import org.mozilla.gecko.tests.helpers.WaitHelper;
/**
* This test ensures the back/forward state is correct when switching to loading pages
* to prevent regressions like Bug 1124190.
*/
public class testStateWhileLoading extends UITest {
public void testStateWhileLoading() {
if (!DeviceHelper.isTablet()) {
// This test case only covers tablets currently.
return;
}
GeckoHelper.blockForReady();
NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_LINK_TO_SLOW_LOADING);
GeckoClickHelper.openCentralizedLinkInNewTab();
WaitHelper.waitForPageLoad(new Runnable() {
@Override
public void run() {
mTabStrip.switchToTab(1);
// Assert that the state of the back button is correct
// after switching to the new (still loading) tab.
mToolbar.assertBackButtonIsNotEnabled();
}
});
// Assert that the state of the back button is still correct after the page has loaded.
mToolbar.assertBackButtonIsNotEnabled();
}
}

View File

@ -614,6 +614,17 @@ nsAppStartup::CreateChromeWindow(nsIWebBrowserChrome *aParent,
// nsAppStartup->nsIWindowCreator2
//
NS_IMETHODIMP
nsAppStartup::SetScreenId(uint32_t aScreenId)
{
nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
if (!appShell) {
return NS_ERROR_FAILURE;
}
return appShell->SetScreenId(aScreenId);
}
NS_IMETHODIMP
nsAppStartup::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
uint32_t aChromeFlags,

View File

@ -1060,10 +1060,7 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
"binary-component");
if (SIGNED_TYPES.has(addon.type))
addon.signedState = yield verifyDirSignedState(aDir, addon.id);
else
addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
addon.signedState = yield verifyDirSignedState(aDir, addon);
addon.appDisabled = !isUsableAddon(addon);
return addon;
@ -1108,10 +1105,7 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
addon.hasBinaryComponents = false;
}
if (SIGNED_TYPES.has(addon.type))
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon.id, addon.version);
else
addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
addon.appDisabled = !isUsableAddon(addon);
return addon;
@ -1325,11 +1319,14 @@ function getSignedStatus(aRv, aCert, aExpectedID) {
*
* @param aFile
* the xpi file to check
* @param aExpectedID
* the expected ID of the signature
* @param aAddon
* the add-on object to verify
* @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
*/
function verifyZipSignedState(aFile, aExpectedID, aVersion) {
function verifyZipSignedState(aFile, aAddon) {
if (!SIGNED_TYPES.has(aAddon.type))
return Promise.resolve(undefined);
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
@ -1341,7 +1338,7 @@ function verifyZipSignedState(aFile, aExpectedID, aVersion) {
certDB.openSignedAppFileAsync(root, aFile, (aRv, aZipReader, aCert) => {
if (aZipReader)
aZipReader.close();
resolve(getSignedStatus(aRv, aCert, aExpectedID));
resolve(getSignedStatus(aRv, aCert, aAddon.id));
});
});
}
@ -1352,11 +1349,14 @@ function verifyZipSignedState(aFile, aExpectedID, aVersion) {
*
* @param aDir
* the directory to check
* @param aExpectedID
* the expected ID of the signature
* @param aAddon
* the add-on object to verify
* @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
*/
function verifyDirSignedState(aDir, aExpectedID) {
function verifyDirSignedState(aDir, aAddon) {
if (!SIGNED_TYPES.has(aAddon.type))
return Promise.resolve(undefined);
// TODO: Get the certificate for an unpacked add-on (bug 1038072)
return Promise.resolve(AddonManager.SIGNEDSTATE_MISSING);
}
@ -1367,14 +1367,14 @@ function verifyDirSignedState(aDir, aExpectedID) {
*
* @param aBundle
* the nsIFile for the bundle to check, either a directory or zip file
* @param aExpectedID
* the expected ID of the signature
* @param aAddon
* the add-on object to verify
* @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
*/
function verifyBundleSignedState(aBundle, aExpectedID) {
function verifyBundleSignedState(aBundle, aAddon) {
if (aBundle.isFile())
return verifyZipSignedState(aBundle, aExpectedID);
return verifyDirSignedState(aBundle, aExpectedID);
return verifyZipSignedState(aBundle, aAddon);
return verifyDirSignedState(aBundle, aAddon);
}
/**
@ -2522,7 +2522,7 @@ this.XPIProvider = {
* Verifies that all installed add-ons are still correctly signed.
*/
verifySignatures: function XPI_verifySignatures() {
XPIDatabase.getAddonList(addon => SIGNED_TYPES.has(addon.type), (addons) => {
XPIDatabase.getAddonList(a => true, (addons) => {
Task.spawn(function*() {
let changes = {
enabled: [],
@ -2534,7 +2534,7 @@ this.XPIProvider = {
if (!addon._sourceBundle.exists())
continue;
let signedState = yield verifyBundleSignedState(addon._sourceBundle, addon.id);
let signedState = yield verifyBundleSignedState(addon._sourceBundle, addon);
if (signedState == addon.signedState)
continue;
@ -3168,7 +3168,7 @@ this.XPIProvider = {
// If updating from a version of the app that didn't support signedState
// then fetch that property now
if (aOldAddon.signedState === undefined) {
if (aOldAddon.signedState === undefined && SIGNED_TYPES.has(aOldAddon.type)) {
let file = aInstallLocation.getLocationForID(aOldAddon.id);
let manifest = syncLoadManifestFromFile(file);
aOldAddon.signedState = manifest.signedState;
@ -5418,7 +5418,8 @@ AddonInstall.prototype = {
"signature verification failed"])
}
}
else if (this.addon.signedState == AddonManager.SIGNEDSTATE_UNKNOWN) {
else if (this.addon.signedState == AddonManager.SIGNEDSTATE_UNKNOWN ||
this.addon.signedState == undefined) {
// Check object signing certificate, if any
let x509 = zipreader.getSigningCert(null);
if (x509) {

View File

@ -95,10 +95,12 @@ function run_test() {
do_check_neq(d, null);
do_check_false(d.skinnable);
do_check_false(d.foreignInstall);
do_check_eq(d.signedState, undefined);
do_check_neq(t1, null);
do_check_false(t1.userDisabled);
do_check_false(t1.appDisabled);
do_check_eq(t1.signedState, undefined);
do_check_true(t1.isActive);
do_check_true(t1.skinnable);
do_check_true(t1.foreignInstall);
@ -112,6 +114,7 @@ function run_test() {
do_check_neq(t2, null);
do_check_true(t2.userDisabled);
do_check_false(t2.appDisabled);
do_check_eq(t2.signedState, undefined);
do_check_false(t2.isActive);
do_check_false(t2.skinnable);
do_check_true(t2.foreignInstall);

View File

@ -40,8 +40,8 @@ body.dark a::-moz-selection {
}
body.sepia {
color: #333333;
background-color: #f0ece7;
color: #5b4636;
background-color: #f4ecd8;
}
body.sans-serif,
@ -92,11 +92,14 @@ body.serif .remove-button {
/* Override some controls and content styles based on color scheme */
body.light > .container > .header > .domain,
body.sepia > .container > .header > .domain {
body.light > .container > .header > .domain {
border-bottom-color: #333333 !important;
}
body.sepia > .container > .header > .domain {
border-bottom-color: #5b4636 !important;
}
body.dark > .container > .header > .domain {
border-bottom-color: #eeeeee !important;
}
@ -105,11 +108,14 @@ body.sepia > .container > .footer {
background-color: #dedad4 !important;
}
body.light blockquote,
body.sepia blockquote {
body.light blockquote {
-moz-border-start: 2px solid #333333 !important;
}
body.sepia blockquote {
-moz-border-start: 2px solid #5b4636 !important;
}
body.dark blockquote {
-moz-border-start: 2px solid #eeeeee !important;
}

View File

@ -13,8 +13,8 @@
}
.sepia-button {
color: #333333;
background-color: #f0ece7;
color: #5b4636;
background-color: #f4ecd8;
}
.sans-serif-button {

View File

@ -639,7 +639,6 @@ StartBootAnimation()
pthread_create(&sAnimationThread, nullptr, AnimationThread, nullptr);
}
void
StopBootAnimation()
{

View File

@ -128,16 +128,15 @@ GonkDisplayJB::GonkDisplayJB()
#else
sp<Surface> stc = new Surface(producer);
#endif
mSTClient = stc;
mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2);
mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE,
GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
if (mHwc) {
uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
if (mFBDevice) {
// If device uses fb, they can not use single buffer for boot animation
mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2);
mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE, usage);
} else if (mHwc) {
#if ANDROID_VERSION >= 21
if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) {
mHwc->setPowerMode(mHwc, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_NORMAL);
@ -147,9 +146,11 @@ GonkDisplayJB::GonkDisplayJB()
#else
mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, 0);
#endif
// For devices w/ hwc v1.0 or no hwc, this buffer can not be created,
// only create this buffer for devices w/ hwc version > 1.0.
mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &err);
}
ALOGI("Starting bootanimation with (%d) format framebuffer", surfaceformat);
StartBootAnimation();
}
@ -166,7 +167,9 @@ GonkDisplayJB::~GonkDisplayJB()
ANativeWindow*
GonkDisplayJB::GetNativeWindow()
{
StopBootAnimation();
if (!mBootAnimBuffer.get()) {
StopBootAnimation();
}
return mSTClient.get();
}
@ -232,6 +235,11 @@ GonkDisplayJB::GetDispSurface()
bool
GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
{
if (mBootAnimBuffer.get()) {
StopBootAnimation();
mBootAnimBuffer = nullptr;
}
// Should be called when composition rendering is complete for a frame.
// Only HWC v1.0 needs this call.
// HWC > v1.0 case, do not call compositionComplete().
@ -307,6 +315,9 @@ GonkDisplayJB::Post(buffer_handle_t buf, int fence)
ANativeWindowBuffer*
GonkDisplayJB::DequeueBuffer()
{
if (mBootAnimBuffer.get()) {
return static_cast<ANativeWindowBuffer*>(mBootAnimBuffer.get());
}
ANativeWindowBuffer *buf;
mSTClient->dequeueBuffer(mSTClient.get(), &buf, &mFence);
return buf;
@ -316,14 +327,20 @@ bool
GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf)
{
bool success = Post(buf->handle, -1);
int error = mSTClient->queueBuffer(mSTClient.get(), buf, mFence);
int error = 0;
if (!mBootAnimBuffer.get()) {
error = mSTClient->queueBuffer(mSTClient.get(), buf, mFence);
}
return error == 0 && success;
}
void
GonkDisplayJB::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur)
{
if (mBootAnimBuffer.get()) {
StopBootAnimation();
mBootAnimBuffer = nullptr;
}
eglSwapBuffers(dpy, sur);
}

View File

@ -63,6 +63,7 @@ private:
android::sp<android::DisplaySurface> mDispSurface;
android::sp<ANativeWindow> mSTClient;
android::sp<android::IGraphicBufferAlloc> mAlloc;
android::sp<android::GraphicBuffer> mBootAnimBuffer;
int mFence;
hwc_display_contents_1_t* mList;
uint32_t mWidth;

View File

@ -316,7 +316,7 @@ KeyEventDispatcher::DispatchKeyEventInternal(uint32_t aEventMessage)
event.modifiers = getDOMModifiers(mData.metaState);
event.location = mDOMKeyLocation;
event.time = mData.timeMs;
return nsWindow::DispatchInputEvent(event);
return nsWindow::DispatchKeyInput(event);
}
void

Some files were not shown because too many files have changed in this diff Show More