mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
7df0008d0e
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
|
@ -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="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
|
@ -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="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -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="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "a26eadc5e1133d5112b6cbc10badbb7670a1090f",
|
||||
"git_revision": "2e89362de40a6c9c36525d36317fa1ae8e67e143",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "a99ff14b3258f49f5902775a5e3b849f3455714a",
|
||||
"revision": "4a596a387a18b019fc2763b3509940d52154d72c",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
|
||||
|
@ -576,6 +576,12 @@ ContentSearchUIController.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_onMsgSuggestionsCancelled: function () {
|
||||
if (!this._table.hidden) {
|
||||
this._hideSuggestions();
|
||||
}
|
||||
},
|
||||
|
||||
_onMsgState: function (state) {
|
||||
this.engines = state.engines;
|
||||
// No point updating the default engine (and the header) if there's no change.
|
||||
|
@ -421,13 +421,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
"room-active": this._isActive()
|
||||
});
|
||||
|
||||
var roomTitle = this.props.room.decryptedContext.roomName ||
|
||||
this.props.room.decryptedContext.urls[0].description ||
|
||||
this.props.room.decryptedContext.urls[0].location;
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: roomClasses,
|
||||
onClick: this.handleClickEntry,
|
||||
onMouseLeave: this._handleMouseOut,
|
||||
ref: "roomEntry"},
|
||||
React.createElement("h2", null,
|
||||
this.props.room.decryptedContext.roomName
|
||||
roomTitle
|
||||
),
|
||||
React.createElement(RoomEntryContextItem, {
|
||||
mozLoop: this.props.mozLoop,
|
||||
|
@ -421,13 +421,17 @@ loop.panel = (function(_, mozL10n) {
|
||||
"room-active": this._isActive()
|
||||
});
|
||||
|
||||
var roomTitle = this.props.room.decryptedContext.roomName ||
|
||||
this.props.room.decryptedContext.urls[0].description ||
|
||||
this.props.room.decryptedContext.urls[0].location;
|
||||
|
||||
return (
|
||||
<div className={roomClasses}
|
||||
onClick={this.handleClickEntry}
|
||||
onMouseLeave={this._handleMouseOut}
|
||||
ref="roomEntry">
|
||||
<h2>
|
||||
{this.props.room.decryptedContext.roomName}
|
||||
{roomTitle}
|
||||
</h2>
|
||||
<RoomEntryContextItem
|
||||
mozLoop={this.props.mozLoop}
|
||||
|
@ -755,8 +755,11 @@ loop.roomViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
if (this.state.roomName || this.state.roomContextUrls) {
|
||||
var roomTitle = this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
this.setTitle(roomTitle);
|
||||
}
|
||||
|
||||
var screenShareData = {
|
||||
|
@ -755,8 +755,11 @@ loop.roomViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if (this.state.roomName) {
|
||||
this.setTitle(this.state.roomName);
|
||||
if (this.state.roomName || this.state.roomContextUrls) {
|
||||
var roomTitle = this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
this.setTitle(roomTitle);
|
||||
}
|
||||
|
||||
var screenShareData = {
|
||||
|
@ -162,9 +162,14 @@ loop.store.TextChatStore = (function() {
|
||||
// XXX When we add special messages to desktop, we'll need to not post
|
||||
// multiple changes of room name, only the first. Bug 1171940 should fix this.
|
||||
if (actionData.roomName) {
|
||||
var roomName = actionData.roomName;
|
||||
if (!roomName && actionData.roomContextUrls && actionData.roomContextUrls.length) {
|
||||
roomName = actionData.roomContextUrls[0].description ||
|
||||
actionData.roomContextUrls[0].url;
|
||||
}
|
||||
this._appendTextChatMessage(CHAT_MESSAGE_TYPES.SPECIAL, {
|
||||
contentType: CHAT_CONTENT_TYPES.ROOM_NAME,
|
||||
message: actionData.roomName
|
||||
message: roomName
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomName = this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
// The extra scroller div here is for providing a scroll view for shorter
|
||||
// screens, as the common.css specifies overflow:hidden for the body which
|
||||
// we need in some places.
|
||||
@ -110,7 +113,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
React.createElement("div", {className: "handle-user-agent-view"},
|
||||
React.createElement("div", {className: "info-panel"},
|
||||
React.createElement("p", {className: "loop-logo-text", title: mozL10n.get("clientShortname2")}),
|
||||
React.createElement("p", {className: "roomName"}, this.state.roomName),
|
||||
React.createElement("p", {className: "roomName"}, roomName),
|
||||
React.createElement("p", {className: "loop-logo"}),
|
||||
|
||||
this.state.failureReason ?
|
||||
@ -444,16 +447,15 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
if (this.state.roomState !== ROOM_STATES.READY &&
|
||||
nextState.roomState === ROOM_STATES.READY) {
|
||||
var roomName = nextState.roomName || this.state.roomName;
|
||||
var roomName = nextState.roomName ||
|
||||
this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
|
||||
if (roomName) {
|
||||
this.setTitle(mozL10n.get("standalone_title_with_room_name", {
|
||||
roomName: roomName,
|
||||
clientShortname: mozL10n.get("clientShortname2")
|
||||
}));
|
||||
} else {
|
||||
this.setTitle(mozL10n.get("clientShortname2"));
|
||||
}
|
||||
this.setTitle(mozL10n.get("standalone_title_with_room_name", {
|
||||
roomName: roomName,
|
||||
clientShortname: mozL10n.get("clientShortname2")
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
|
||||
|
@ -102,6 +102,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var roomName = this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
// The extra scroller div here is for providing a scroll view for shorter
|
||||
// screens, as the common.css specifies overflow:hidden for the body which
|
||||
// we need in some places.
|
||||
@ -110,7 +113,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
<div className="handle-user-agent-view">
|
||||
<div className="info-panel">
|
||||
<p className="loop-logo-text" title={mozL10n.get("clientShortname2")}></p>
|
||||
<p className="roomName">{this.state.roomName}</p>
|
||||
<p className="roomName">{roomName}</p>
|
||||
<p className="loop-logo" />
|
||||
{
|
||||
this.state.failureReason ?
|
||||
@ -444,16 +447,15 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
||||
componentWillUpdate: function(nextProps, nextState) {
|
||||
if (this.state.roomState !== ROOM_STATES.READY &&
|
||||
nextState.roomState === ROOM_STATES.READY) {
|
||||
var roomName = nextState.roomName || this.state.roomName;
|
||||
var roomName = nextState.roomName ||
|
||||
this.state.roomName ||
|
||||
this.state.roomContextUrls[0].description ||
|
||||
this.state.roomContextUrls[0].location;
|
||||
|
||||
if (roomName) {
|
||||
this.setTitle(mozL10n.get("standalone_title_with_room_name", {
|
||||
roomName: roomName,
|
||||
clientShortname: mozL10n.get("clientShortname2")
|
||||
}));
|
||||
} else {
|
||||
this.setTitle(mozL10n.get("clientShortname2"));
|
||||
}
|
||||
this.setTitle(mozL10n.get("standalone_title_with_room_name", {
|
||||
roomName: roomName,
|
||||
clientShortname: mozL10n.get("clientShortname2")
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.state.roomState !== ROOM_STATES.MEDIA_WAIT &&
|
||||
|
@ -743,6 +743,68 @@ describe("loop.panel", function() {
|
||||
.eql("New room name");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Room name priority", function() {
|
||||
var roomEntry;
|
||||
beforeEach(function() {
|
||||
roomEntry = mountRoomEntry({
|
||||
dispatcher: dispatcher,
|
||||
room: new loop.store.Room(roomData)
|
||||
});
|
||||
});
|
||||
|
||||
function setDecryptedContext(newDecryptedContext) {
|
||||
return new loop.store.Room(_.extend({}, roomData, {
|
||||
decryptedContext: newDecryptedContext,
|
||||
ctime: new Date().getTime()
|
||||
}));
|
||||
}
|
||||
|
||||
it("should use room name by default", function() {
|
||||
var updatedRoom = setDecryptedContext({
|
||||
roomName: "Room name",
|
||||
urls: [
|
||||
{
|
||||
description: "Website title",
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
roomEntry.setProps({ room: updatedRoom });
|
||||
|
||||
expect(roomEntry.getDOMNode().textContent).eql("Room name");
|
||||
});
|
||||
|
||||
it("should use context title when there's no room title", function() {
|
||||
var updatedRoom = setDecryptedContext({
|
||||
urls: [
|
||||
{
|
||||
description: "Website title",
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
roomEntry.setProps({ room: updatedRoom });
|
||||
|
||||
expect(roomEntry.getDOMNode().textContent).eql("Website title");
|
||||
});
|
||||
|
||||
it("should use website url when there's no room title nor website", function() {
|
||||
var updatedRoom = setDecryptedContext({
|
||||
urls: [
|
||||
{
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
roomEntry.setProps({ room: updatedRoom });
|
||||
|
||||
expect(roomEntry.getDOMNode().textContent).eql("https://fakeurl.com");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("loop.panel.RoomList", function() {
|
||||
|
@ -649,6 +649,48 @@ describe("loop.roomViews", function() {
|
||||
expect(view.getDOMNode().querySelector(".local video")).not.eql(null);
|
||||
});
|
||||
|
||||
describe("Room name priority", function() {
|
||||
var roomEntry;
|
||||
beforeEach(function() {
|
||||
activeRoomStore.setStoreState({
|
||||
participants: [{}],
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomName: "fakeName",
|
||||
roomContextUrls: [
|
||||
{
|
||||
description: "Website title",
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it("should use room name by default", function() {
|
||||
view = mountTestComponent();
|
||||
expect(fakeWindow.document.title).to.equal("fakeName");
|
||||
});
|
||||
|
||||
it("should use context title when there's no room title", function() {
|
||||
activeRoomStore.setStoreState({ roomName: null });
|
||||
|
||||
view = mountTestComponent();
|
||||
expect(fakeWindow.document.title).to.equal("Website title");
|
||||
});
|
||||
|
||||
it("should use website url when there's no room title nor website", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomName: null,
|
||||
roomContextUrls: [
|
||||
{
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
view = mountTestComponent();
|
||||
expect(fakeWindow.document.title).to.equal("https://fakeurl.com");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Edit Context", function() {
|
||||
|
@ -140,7 +140,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should display a join room button if the state is not ROOM_JOINED", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
roomState: ROOM_STATES.READY,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -151,7 +152,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should dispatch a JoinRoom action when the join room button is clicked", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.READY
|
||||
roomState: ROOM_STATES.READY,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -165,7 +167,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should display a enjoy your conversation button if the state is ROOM_JOINED", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -176,7 +179,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should disable the enjoy your conversation button if the state is ROOM_JOINED", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -187,7 +191,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should not display a join button if there is a failure reason", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -198,7 +203,8 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
it("should display a room already joined message if opening failed", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN
|
||||
failureReason: FAILURE_DETAILS.ROOM_ALREADY_OPEN,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
@ -206,6 +212,59 @@ describe("loop.standaloneRoomViews", function() {
|
||||
|
||||
expect(text.textContent).eql("rooms_already_joined");
|
||||
});
|
||||
|
||||
describe("Room name priority", function() {
|
||||
it("should use room name", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
var text = view.getDOMNode().querySelector(".roomName");
|
||||
|
||||
expect(
|
||||
text.textContent)
|
||||
.eql("fakeName");
|
||||
});
|
||||
|
||||
it("should use context title when there's no room title", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomContextUrls: [
|
||||
{
|
||||
description: "Website title",
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
var text = view.getDOMNode().querySelector(".roomName");
|
||||
|
||||
expect(
|
||||
text.textContent)
|
||||
.eql("Website title");
|
||||
});
|
||||
|
||||
it("should use website url when there's no room title nor website", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.JOINED,
|
||||
roomContextUrls: [
|
||||
{
|
||||
location: "https://fakeurl.com"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
view = mountTestComponent();
|
||||
var text = view.getDOMNode().querySelector(".roomName");
|
||||
|
||||
expect(
|
||||
text.textContent)
|
||||
.eql("https://fakeurl.com");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("StandaloneRoomHeader", function() {
|
||||
@ -241,7 +300,10 @@ describe("loop.standaloneRoomViews", function() {
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.FAILED });
|
||||
activeRoomStore.setStoreState({
|
||||
roomState: ROOM_STATES.FAILED,
|
||||
roomName: "fakeName"
|
||||
});
|
||||
});
|
||||
|
||||
it("should display a status error message if not reason is supplied", function() {
|
||||
@ -365,20 +427,15 @@ describe("loop.standaloneRoomViews", function() {
|
||||
}
|
||||
|
||||
describe("#componentWillUpdate", function() {
|
||||
it("should set document.title to roomName and brand name when the READY state is dispatched", function() {
|
||||
activeRoomStore.setStoreState({ roomName: "fakeName", roomState: ROOM_STATES.INIT });
|
||||
view = mountTestComponent();
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.READY });
|
||||
|
||||
expect(fakeWindow.document.title).to.equal("fakeName — clientShortname2");
|
||||
beforeEach(function() {
|
||||
activeRoomStore.setStoreState({ roomName: "fakeName" });
|
||||
});
|
||||
|
||||
it("should set document.title brand name when there is no context available", function() {
|
||||
it("should set document.title to roomName and brand name when the READY state is dispatched", function() {
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.INIT });
|
||||
view = mountTestComponent();
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.READY });
|
||||
|
||||
expect(fakeWindow.document.title).to.equal("clientShortname2");
|
||||
expect(fakeWindow.document.title).to.equal("fakeName — clientShortname2");
|
||||
});
|
||||
|
||||
it("should dispatch a `SetupStreamElements` action when the MEDIA_WAIT state " +
|
||||
@ -456,7 +513,7 @@ describe("loop.standaloneRoomViews", function() {
|
||||
view = mountTestComponent();
|
||||
|
||||
// Pretend the user waited a little bit
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.JOINING });
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.JOINING, roomName: "fakeName" });
|
||||
clock.tick(loop.standaloneRoomViews.StandaloneRoomInfoArea.RENDER_WAITING_DELAY - 1);
|
||||
});
|
||||
|
||||
@ -541,7 +598,7 @@ describe("loop.standaloneRoomViews", function() {
|
||||
describe("#render", function() {
|
||||
beforeEach(function() {
|
||||
view = mountTestComponent();
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.JOINING });
|
||||
activeRoomStore.setStoreState({ roomState: ROOM_STATES.JOINING, roomName: "fakeName" });
|
||||
});
|
||||
|
||||
describe("Empty room message", function() {
|
||||
@ -976,6 +1033,10 @@ describe("loop.standaloneRoomViews", function() {
|
||||
}));
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
activeRoomStore.setStoreState({ roomName: "fakeName" });
|
||||
});
|
||||
|
||||
it("should not display anything if it is not known if Firefox can handle the room", function() {
|
||||
activeRoomStore.setStoreState({
|
||||
userAgentHandlesRoom: undefined
|
||||
|
@ -1332,8 +1332,63 @@
|
||||
}
|
||||
});
|
||||
|
||||
var Failure = React.createClass({displayName: "Failure",
|
||||
propTypes: {
|
||||
errorDetected: React.PropTypes.bool.isRequired,
|
||||
errorLine1: React.PropTypes.string,
|
||||
errorLine2: React.PropTypes.string,
|
||||
summary: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// if no errors, return blank
|
||||
return !this.props.errorDetected ? null :
|
||||
(React.createElement("li", {className: "test fail"},
|
||||
React.createElement("h2", null,
|
||||
this.props.summary
|
||||
),
|
||||
React.createElement("pre", {className: "error"},
|
||||
this.props.errorLine1 +
|
||||
this.props.errorLine2 ? "\n" + this.props.errorLine2 : ""
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Result = React.createClass({displayName: "Result",
|
||||
propTypes: {
|
||||
error: React.PropTypes.object,
|
||||
warnings: React.PropTypes.array
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var warningsDetected = this.props.warnings.length !== 0;
|
||||
var totalFailures = warningsDetected + !!this.props.error;
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "error-summary"},
|
||||
React.createElement("div", {className: "failures"},
|
||||
React.createElement("a", null, "failures: "),
|
||||
React.createElement("em", null, totalFailures)
|
||||
),
|
||||
React.createElement("ul", null,
|
||||
React.createElement(Failure, {errorDetected: warningsDetected,
|
||||
errorLine1: "Got: " + this.props.warnings.length,
|
||||
summary: "Unexpected warnings detected rendering UI-Showcase"}),
|
||||
React.createElement(Failure, {errorDetected: !!this.props.error,
|
||||
errorLine1: this.props.error,
|
||||
errorLine2: this.props.error ? this.props.error.stack : null,
|
||||
summary: "Errors rendering UI-Showcase"})
|
||||
),
|
||||
React.createElement("p", {id: "complete"}, "Completed")
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
var uncaughtError;
|
||||
var uncaughtError = null;
|
||||
var consoleWarn = console.warn;
|
||||
var caughtWarnings = [];
|
||||
console.warn = function() {
|
||||
@ -1362,54 +1417,9 @@
|
||||
// Put the title back, in case views changed it.
|
||||
document.title = "Loop UI Components Showcase";
|
||||
|
||||
// This simulates the mocha layout for errors which means we can run
|
||||
// this alongside our other unit tests but use the same harness.
|
||||
var expectedWarningsCount = 0;
|
||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||
var resultsElement = document.querySelector("#results");
|
||||
var divFailuresNode = document.createElement("div");
|
||||
var pCompleteNode = document.createElement("p");
|
||||
var emNode = document.createElement("em");
|
||||
|
||||
if (uncaughtError || warningsMismatch) {
|
||||
var liTestFail = document.createElement("li");
|
||||
var h2Node = document.createElement("h2");
|
||||
var preErrorNode = document.createElement("pre");
|
||||
|
||||
divFailuresNode.className = "failures";
|
||||
emNode.innerHTML = ((uncaughtError && warningsMismatch) ? 2 : 1).toString();
|
||||
divFailuresNode.appendChild(emNode);
|
||||
resultsElement.appendChild(divFailuresNode);
|
||||
|
||||
if (warningsMismatch) {
|
||||
liTestFail.className = "test";
|
||||
liTestFail.className += " fail";
|
||||
h2Node.innerHTML = "Unexpected number of warnings detected in UI-Showcase";
|
||||
preErrorNode.className = "error";
|
||||
preErrorNode.innerHTML = "Got: " + caughtWarnings.length + "\n" + "Expected: " + expectedWarningsCount;
|
||||
liTestFail.appendChild(h2Node);
|
||||
liTestFail.appendChild(preErrorNode);
|
||||
resultsElement.appendChild(liTestFail);
|
||||
}
|
||||
if (uncaughtError) {
|
||||
liTestFail.className = "test";
|
||||
liTestFail.className += " fail";
|
||||
h2Node.innerHTML = "Errors rendering UI-Showcase";
|
||||
preErrorNode.className = "error";
|
||||
preErrorNode.innerHTML = uncaughtError + "\n" + uncaughtError.stack;
|
||||
liTestFail.appendChild(h2Node);
|
||||
liTestFail.appendChild(preErrorNode);
|
||||
resultsElement.appendChild(liTestFail);
|
||||
}
|
||||
} else {
|
||||
divFailuresNode.className = "failures";
|
||||
emNode.innerHTML = "0";
|
||||
divFailuresNode.appendChild(emNode);
|
||||
resultsElement.appendChild(divFailuresNode);
|
||||
}
|
||||
pCompleteNode.id = "complete";
|
||||
pCompleteNode.innerHTML = "Completed";
|
||||
resultsElement.appendChild(pCompleteNode);
|
||||
React.render(React.createElement(Result, {error: uncaughtError,
|
||||
warnings: caughtWarnings}),
|
||||
document.querySelector("#results"));
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
@ -1332,8 +1332,63 @@
|
||||
}
|
||||
});
|
||||
|
||||
var Failure = React.createClass({
|
||||
propTypes: {
|
||||
errorDetected: React.PropTypes.bool.isRequired,
|
||||
errorLine1: React.PropTypes.string,
|
||||
errorLine2: React.PropTypes.string,
|
||||
summary: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
// if no errors, return blank
|
||||
return !this.props.errorDetected ? null :
|
||||
(<li className = "test fail">
|
||||
<h2>
|
||||
{this.props.summary}
|
||||
</h2>
|
||||
<pre className="error">
|
||||
{this.props.errorLine1 +
|
||||
this.props.errorLine2 ? "\n" + this.props.errorLine2 : ""}
|
||||
</pre>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var Result = React.createClass({
|
||||
propTypes: {
|
||||
error: React.PropTypes.object,
|
||||
warnings: React.PropTypes.array
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var warningsDetected = this.props.warnings.length !== 0;
|
||||
var totalFailures = warningsDetected + !!this.props.error;
|
||||
|
||||
return (
|
||||
<div className = "error-summary">
|
||||
<div className = "failures">
|
||||
<a>failures: </a>
|
||||
<em>{totalFailures}</em>
|
||||
</div>
|
||||
<ul>
|
||||
<Failure errorDetected={warningsDetected}
|
||||
errorLine1={"Got: " + this.props.warnings.length}
|
||||
summary="Unexpected warnings detected rendering UI-Showcase" />
|
||||
<Failure errorDetected={!!this.props.error}
|
||||
errorLine1={this.props.error}
|
||||
errorLine2={this.props.error ? this.props.error.stack : null}
|
||||
summary="Errors rendering UI-Showcase" />
|
||||
</ul>
|
||||
<p id="complete">Completed</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function() {
|
||||
var uncaughtError;
|
||||
var uncaughtError = null;
|
||||
var consoleWarn = console.warn;
|
||||
var caughtWarnings = [];
|
||||
console.warn = function() {
|
||||
@ -1362,54 +1417,9 @@
|
||||
// Put the title back, in case views changed it.
|
||||
document.title = "Loop UI Components Showcase";
|
||||
|
||||
// This simulates the mocha layout for errors which means we can run
|
||||
// this alongside our other unit tests but use the same harness.
|
||||
var expectedWarningsCount = 0;
|
||||
var warningsMismatch = caughtWarnings.length !== expectedWarningsCount;
|
||||
var resultsElement = document.querySelector("#results");
|
||||
var divFailuresNode = document.createElement("div");
|
||||
var pCompleteNode = document.createElement("p");
|
||||
var emNode = document.createElement("em");
|
||||
|
||||
if (uncaughtError || warningsMismatch) {
|
||||
var liTestFail = document.createElement("li");
|
||||
var h2Node = document.createElement("h2");
|
||||
var preErrorNode = document.createElement("pre");
|
||||
|
||||
divFailuresNode.className = "failures";
|
||||
emNode.innerHTML = ((uncaughtError && warningsMismatch) ? 2 : 1).toString();
|
||||
divFailuresNode.appendChild(emNode);
|
||||
resultsElement.appendChild(divFailuresNode);
|
||||
|
||||
if (warningsMismatch) {
|
||||
liTestFail.className = "test";
|
||||
liTestFail.className += " fail";
|
||||
h2Node.innerHTML = "Unexpected number of warnings detected in UI-Showcase";
|
||||
preErrorNode.className = "error";
|
||||
preErrorNode.innerHTML = "Got: " + caughtWarnings.length + "\n" + "Expected: " + expectedWarningsCount;
|
||||
liTestFail.appendChild(h2Node);
|
||||
liTestFail.appendChild(preErrorNode);
|
||||
resultsElement.appendChild(liTestFail);
|
||||
}
|
||||
if (uncaughtError) {
|
||||
liTestFail.className = "test";
|
||||
liTestFail.className += " fail";
|
||||
h2Node.innerHTML = "Errors rendering UI-Showcase";
|
||||
preErrorNode.className = "error";
|
||||
preErrorNode.innerHTML = uncaughtError + "\n" + uncaughtError.stack;
|
||||
liTestFail.appendChild(h2Node);
|
||||
liTestFail.appendChild(preErrorNode);
|
||||
resultsElement.appendChild(liTestFail);
|
||||
}
|
||||
} else {
|
||||
divFailuresNode.className = "failures";
|
||||
emNode.innerHTML = "0";
|
||||
divFailuresNode.appendChild(emNode);
|
||||
resultsElement.appendChild(divFailuresNode);
|
||||
}
|
||||
pCompleteNode.id = "complete";
|
||||
pCompleteNode.innerHTML = "Completed";
|
||||
resultsElement.appendChild(pCompleteNode);
|
||||
React.render(<Result error={uncaughtError}
|
||||
warnings={caughtWarnings} />,
|
||||
document.querySelector("#results"));
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
@ -56,6 +56,8 @@ const MAX_SUGGESTIONS = 6;
|
||||
* data: the entry, a string
|
||||
* Search
|
||||
* Performs a search.
|
||||
* Any GetSuggestions messages in the queue from the same target will be
|
||||
* cancelled.
|
||||
* data: { engineName, searchString, healthReportKey, searchPurpose }
|
||||
* SetCurrentEngine
|
||||
* Sets the current engine.
|
||||
@ -81,6 +83,10 @@ const MAX_SUGGESTIONS = 6;
|
||||
* Suggestions
|
||||
* Sent in reply to GetSuggestions.
|
||||
* data: see _onMessageGetSuggestions
|
||||
* SuggestionsCancelled
|
||||
* Sent in reply to GetSuggestions when pending GetSuggestions events are
|
||||
* cancelled.
|
||||
* data: null
|
||||
*/
|
||||
|
||||
this.ContentSearch = {
|
||||
@ -98,6 +104,10 @@ this.ContentSearch = {
|
||||
// Resolved when we finish shutting down.
|
||||
_destroyedPromise: null,
|
||||
|
||||
// The current controller and browser in _onMessageGetSuggestions. Allows
|
||||
// fetch cancellation from _cancelSuggestions.
|
||||
_currentSuggestion: null,
|
||||
|
||||
init: function () {
|
||||
Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager).
|
||||
@ -165,6 +175,12 @@ this.ContentSearch = {
|
||||
};
|
||||
msg.target.addEventListener("SwapDocShells", msg, true);
|
||||
|
||||
// Search requests cause cancellation of all Suggestion requests from the
|
||||
// same browser.
|
||||
if (msg.data.type == "Search") {
|
||||
this._cancelSuggestions(msg);
|
||||
}
|
||||
|
||||
this._eventQueue.push({
|
||||
type: "Message",
|
||||
data: msg,
|
||||
@ -208,6 +224,27 @@ this.ContentSearch = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_cancelSuggestions: function (msg) {
|
||||
let cancelled = false;
|
||||
// cancel active suggestion request
|
||||
if (this._currentSuggestion && this._currentSuggestion.target == msg.target) {
|
||||
this._currentSuggestion.controller.stop();
|
||||
cancelled = true;
|
||||
}
|
||||
// cancel queued suggestion requests
|
||||
for (let i = 0; i < this._eventQueue.length; i++) {
|
||||
let m = this._eventQueue[i].data;
|
||||
if (msg.target == m.target && m.data.type == "GetSuggestions") {
|
||||
this._eventQueue.splice(i, 1);
|
||||
cancelled = true;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (cancelled) {
|
||||
this._reply(msg, "SuggestionsCancelled");
|
||||
}
|
||||
},
|
||||
|
||||
_onMessage: Task.async(function* (msg) {
|
||||
let methodName = "_onMessage" + msg.data.type;
|
||||
if (methodName in this) {
|
||||
@ -302,7 +339,14 @@ this.ContentSearch = {
|
||||
let priv = PrivateBrowsingUtils.isBrowserPrivate(msg.target);
|
||||
// fetch() rejects its promise if there's a pending request, but since we
|
||||
// process our event queue serially, there's never a pending request.
|
||||
this._currentSuggestion = { controller: controller, target: msg.target };
|
||||
let suggestions = yield controller.fetch(data.searchString, priv, engine);
|
||||
this._currentSuggestion = null;
|
||||
|
||||
// suggestions will be null if the request was cancelled
|
||||
if (!suggestions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep the form history result so RemoveFormHistoryEntry can remove entries
|
||||
// from it. Keeping only one result isn't foolproof because the client may
|
||||
|
@ -1947,6 +1947,7 @@ toolbarbutton.chevron > .toolbarbutton-icon {
|
||||
|
||||
.browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
%include ../shared/usercontext/usercontext.inc.css
|
||||
|
@ -3621,6 +3621,7 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
|
||||
.browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
%include ../shared/usercontext/usercontext.inc.css
|
||||
|
@ -2807,6 +2807,7 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
|
||||
.browser-extension-panel > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
%include ../shared/usercontext/usercontext.inc.css
|
||||
|
@ -337,6 +337,19 @@ fi
|
||||
|
||||
])
|
||||
|
||||
AC_DEFUN([MOZ_ANDROID_GOOGLE_CLOUD_MESSAGING],
|
||||
[
|
||||
|
||||
if test -n "$MOZ_ANDROID_GCM" ; then
|
||||
AC_SUBST(MOZ_ANDROID_GCM)
|
||||
|
||||
MOZ_ANDROID_AAR(play-services-base, 8.1.0, google, com/google/android/gms)
|
||||
MOZ_ANDROID_AAR(play-services-basement, 8.1.0, google, com/google/android/gms)
|
||||
MOZ_ANDROID_AAR(play-services-gcm, 8.1.0, google, com/google/android/gms)
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
dnl Configure an Android SDK.
|
||||
dnl Arg 1: target SDK version, like 22.
|
||||
dnl Arg 2: build tools version, like 22.0.1.
|
||||
|
@ -48,6 +48,8 @@ toolkit/library
|
||||
profile
|
||||
services
|
||||
startupcache
|
||||
devtools/server
|
||||
devtools/shared
|
||||
browser/app
|
||||
browser/base
|
||||
browser/components
|
||||
@ -60,7 +62,6 @@ browser/app
|
||||
toolkit/components/jsdownloads
|
||||
toolkit/content
|
||||
toolkit/crashreporter
|
||||
devtools/shared
|
||||
toolkit/forgetaboutsite
|
||||
toolkit/identity
|
||||
toolkit/modules
|
||||
|
18
configure.in
18
configure.in
@ -3755,6 +3755,7 @@ MOZ_LOCALE_SWITCHER=
|
||||
MOZ_ANDROID_READING_LIST_SERVICE=
|
||||
MOZ_ANDROID_SEARCH_ACTIVITY=
|
||||
MOZ_ANDROID_DOWNLOADS_INTEGRATION=
|
||||
MOZ_ANDROID_GCM=
|
||||
MOZ_ANDROID_MLS_STUMBLER=
|
||||
MOZ_ANDROID_SHARE_OVERLAY=
|
||||
MOZ_EXCLUDE_HYPHENATION_DICTIONARIES=
|
||||
@ -3911,6 +3912,14 @@ MOZ_ARG_WITH_STRING(adjust-sdk-keyfile,
|
||||
MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN=`cat $withval`)
|
||||
AC_SUBST(MOZ_INSTALL_TRACKING_ADJUST_SDK_APP_TOKEN)
|
||||
|
||||
# Allow specifying a GCM sender ID key file that contains the sender ID used for
|
||||
# GCM requests. Note that GCM sender IDs are not sensitive: see, for example,
|
||||
# http://stackoverflow.com/a/18216063.
|
||||
MOZ_ARG_WITH_STRING(gcm-senderid-keyfile,
|
||||
[ --with-gcm-senderid-keyfile=file GCM sender ID for GCM requests],
|
||||
MOZ_ANDROID_GCM_SENDERID=`cat $withval`)
|
||||
AC_SUBST(MOZ_ANDROID_GCM_SENDERID)
|
||||
|
||||
# Whether to include optional-but-large font files in the final APK.
|
||||
# We want this in mobile/android/confvars.sh, so it goes early.
|
||||
MOZ_ARG_DISABLE_BOOL(android-include-fonts,
|
||||
@ -4580,6 +4589,7 @@ dnl values set by configure.sh above.
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ANDROID_GOOGLE_PLAY_SERVICES
|
||||
MOZ_ANDROID_GOOGLE_CLOUD_MESSAGING
|
||||
|
||||
|
||||
dnl ========================================================
|
||||
@ -4886,6 +4896,13 @@ if test -n "$MOZ_SWITCHBOARD"; then
|
||||
AC_DEFINE(MOZ_SWITCHBOARD)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable GCM on Android.
|
||||
dnl ========================================================
|
||||
if test -n "$MOZ_ANDROID_GCM"; then
|
||||
AC_DEFINE(MOZ_ANDROID_GCM)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable IPDL's "expensive" unit tests
|
||||
dnl ========================================================
|
||||
@ -8592,6 +8609,7 @@ AC_SUBST(MOZ_WEBSMS_BACKEND)
|
||||
AC_SUBST(MOZ_ANDROID_BEAM)
|
||||
AC_SUBST(MOZ_LOCALE_SWITCHER)
|
||||
AC_SUBST(MOZ_DISABLE_GECKOVIEW)
|
||||
AC_SUBST(MOZ_ANDROID_GCM)
|
||||
AC_SUBST(MOZ_ANDROID_GECKOLIBS_AAR)
|
||||
AC_SUBST(MOZ_ANDROID_READING_LIST_SERVICE)
|
||||
AC_SUBST(MOZ_ANDROID_SEARCH_ACTIVITY)
|
||||
|
@ -25,8 +25,15 @@ function test() {
|
||||
}
|
||||
|
||||
function performTest() {
|
||||
// Make sure that the search box becomes focused when pressing ctrl+f - Bug 1211038
|
||||
gEditor.focus();
|
||||
synthesizeKeyFromKeyTag(gDebugger.document.getElementById("tokenSearchKey"));
|
||||
let focusedEl = Services.focus.focusedElement;
|
||||
focusedEl = focusedEl.ownerDocument.getBindingParent(focusedEl) || focusedEl;
|
||||
is(focusedEl, gDebugger.document.getElementById("searchbox"), "Searchbox is focused");
|
||||
|
||||
setText(gSearchBox, "#html");
|
||||
|
||||
|
||||
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true }, gDebugger);
|
||||
is(gFiltering.searchData.toSource(), '["#", ["", "html"]]',
|
||||
"The searchbox data wasn't parsed correctly.");
|
||||
@ -44,7 +51,7 @@ function performTest() {
|
||||
"The searchbox data wasn't parsed correctly.");
|
||||
ok(isCaretPos(gPanel, 3, 15),
|
||||
"The editor didn't jump to the correct line.");
|
||||
|
||||
|
||||
setText(gSearchBox, ":12");
|
||||
is(gFiltering.searchData.toSource(), '[":", ["", 12]]',
|
||||
"The searchbox data wasn't parsed correctly.");
|
||||
|
@ -1215,3 +1215,30 @@ function getSplitConsole(toolbox, win) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This can be removed once debugger uses shared-head.js (bug 1181838)
|
||||
function synthesizeKeyFromKeyTag(key) {
|
||||
is(key && key.tagName, "key", "Successfully retrieved the <key> node");
|
||||
|
||||
let modifiersAttr = key.getAttribute("modifiers");
|
||||
|
||||
let name = null;
|
||||
|
||||
if (key.getAttribute("keycode"))
|
||||
name = key.getAttribute("keycode");
|
||||
else if (key.getAttribute("key"))
|
||||
name = key.getAttribute("key");
|
||||
|
||||
isnot(name, null, "Successfully retrieved keycode/key");
|
||||
|
||||
let modifiers = {
|
||||
shiftKey: !!modifiersAttr.match("shift"),
|
||||
ctrlKey: !!modifiersAttr.match("control"),
|
||||
altKey: !!modifiersAttr.match("alt"),
|
||||
metaKey: !!modifiersAttr.match("meta"),
|
||||
accelKey: !!modifiersAttr.match("accel")
|
||||
};
|
||||
|
||||
info("Synthesizing key " + name + " " + JSON.stringify(modifiers));
|
||||
EventUtils.synthesizeKey(name, modifiers);
|
||||
}
|
||||
|
@ -3,25 +3,16 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// @TODO 1215606
|
||||
// Use this assert instead of utils when fixed.
|
||||
// const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { breakdownEquals, createSnapshot, assert } = require("../utils");
|
||||
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { breakdownEquals, createSnapshot } = require("../utils");
|
||||
const { actions, snapshotState: states } = require("../constants");
|
||||
const { takeCensus } = require("./snapshot");
|
||||
const { refreshSelectedCensus } = require("./snapshot");
|
||||
|
||||
const setBreakdownAndRefresh = exports.setBreakdownAndRefresh = function (heapWorker, breakdown) {
|
||||
return function *(dispatch, getState) {
|
||||
// Clears out all stored census data and sets
|
||||
// the breakdown
|
||||
// Clears out all stored census data and sets the breakdown.
|
||||
dispatch(setBreakdown(breakdown));
|
||||
let snapshot = getState().snapshots.find(s => s.selected);
|
||||
|
||||
// If selected snapshot does not have updated census if the breakdown
|
||||
// changed, retake the census with new breakdown
|
||||
if (snapshot && !breakdownEquals(snapshot.breakdown, breakdown)) {
|
||||
yield dispatch(takeCensus(heapWorker, snapshot));
|
||||
}
|
||||
yield dispatch(refreshSelectedCensus(heapWorker));
|
||||
};
|
||||
};
|
||||
|
||||
@ -32,7 +23,6 @@ const setBreakdownAndRefresh = exports.setBreakdownAndRefresh = function (heapWo
|
||||
* @param {Breakdown} breakdown
|
||||
*/
|
||||
const setBreakdown = exports.setBreakdown = function (breakdown) {
|
||||
// @TODO 1215606
|
||||
assert(typeof breakdown === "object" && breakdown.by,
|
||||
`Breakdowns must be an object with a \`by\` property, attempted to set: ${uneval(breakdown)}`);
|
||||
|
||||
|
18
devtools/client/memory/actions/inverted.js
Normal file
18
devtools/client/memory/actions/inverted.js
Normal file
@ -0,0 +1,18 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { actions } = require("../constants");
|
||||
const { refreshSelectedCensus } = require("./snapshot");
|
||||
|
||||
const toggleInverted = exports.toggleInverted = function () {
|
||||
return { type: actions.TOGGLE_INVERTED };
|
||||
};
|
||||
|
||||
exports.toggleInvertedAndRefresh = function (heapWorker) {
|
||||
return function* (dispatch, getState) {
|
||||
dispatch(toggleInverted());
|
||||
yield dispatch(refreshSelectedCensus(heapWorker));
|
||||
};
|
||||
};
|
@ -6,5 +6,6 @@
|
||||
DevToolsModules(
|
||||
'allocations.js',
|
||||
'breakdown.js',
|
||||
'inverted.js',
|
||||
'snapshot.js',
|
||||
)
|
||||
|
@ -3,10 +3,8 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
// @TODO 1215606
|
||||
// Use this assert instead of utils when fixed.
|
||||
// const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { getSnapshot, breakdownEquals, createSnapshot, assert } = require("../utils");
|
||||
const { assert, reportException } = require("devtools/shared/DevToolsUtils");
|
||||
const { getSnapshot, breakdownEquals, createSnapshot } = require("../utils");
|
||||
const { actions, snapshotState: states } = require("../constants");
|
||||
|
||||
/**
|
||||
@ -20,8 +18,11 @@ const { actions, snapshotState: states } = require("../constants");
|
||||
const takeSnapshotAndCensus = exports.takeSnapshotAndCensus = function (front, heapWorker) {
|
||||
return function *(dispatch, getState) {
|
||||
let snapshot = yield dispatch(takeSnapshot(front));
|
||||
|
||||
yield dispatch(readSnapshot(heapWorker, snapshot));
|
||||
yield dispatch(takeCensus(heapWorker, snapshot));
|
||||
if (snapshot.state === states.READ) {
|
||||
yield dispatch(takeCensus(heapWorker, snapshot));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@ -35,10 +36,7 @@ const takeSnapshotAndCensus = exports.takeSnapshotAndCensus = function (front, h
|
||||
const selectSnapshotAndRefresh = exports.selectSnapshotAndRefresh = function (heapWorker, snapshot) {
|
||||
return function *(dispatch, getState) {
|
||||
dispatch(selectSnapshot(snapshot));
|
||||
|
||||
// Attempt to take another census; if the snapshot already is using
|
||||
// the correct breakdown, this will noop.
|
||||
yield dispatch(takeCensus(heapWorker, snapshot));
|
||||
yield dispatch(refreshSelectedCensus(heapWorker));
|
||||
};
|
||||
};
|
||||
|
||||
@ -51,9 +49,16 @@ const takeSnapshot = exports.takeSnapshot = function (front) {
|
||||
dispatch({ type: actions.TAKE_SNAPSHOT_START, snapshot });
|
||||
dispatch(selectSnapshot(snapshot));
|
||||
|
||||
let path = yield front.saveHeapSnapshot();
|
||||
dispatch({ type: actions.TAKE_SNAPSHOT_END, snapshot, path });
|
||||
let path;
|
||||
try {
|
||||
path = yield front.saveHeapSnapshot();
|
||||
} catch (error) {
|
||||
reportException("takeSnapshot", error);
|
||||
dispatch({ type: actions.SNAPSHOT_ERROR, snapshot, error });
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: actions.TAKE_SNAPSHOT_END, snapshot, path });
|
||||
return snapshot;
|
||||
};
|
||||
};
|
||||
@ -67,12 +72,18 @@ const takeSnapshot = exports.takeSnapshot = function (front) {
|
||||
*/
|
||||
const readSnapshot = exports.readSnapshot = function readSnapshot (heapWorker, snapshot) {
|
||||
return function *(dispatch, getState) {
|
||||
// @TODO 1215606
|
||||
assert(snapshot.state === states.SAVED,
|
||||
"Should only read a snapshot once");
|
||||
`Should only read a snapshot once. Found snapshot in state ${snapshot.state}`);
|
||||
|
||||
dispatch({ type: actions.READ_SNAPSHOT_START, snapshot });
|
||||
yield heapWorker.readHeapSnapshot(snapshot.path);
|
||||
try {
|
||||
yield heapWorker.readHeapSnapshot(snapshot.path);
|
||||
} catch (error) {
|
||||
reportException("readSnapshot", error);
|
||||
dispatch({ type: actions.SNAPSHOT_ERROR, snapshot, error });
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({ type: actions.READ_SNAPSHOT_END, snapshot });
|
||||
};
|
||||
};
|
||||
@ -87,15 +98,15 @@ const readSnapshot = exports.readSnapshot = function readSnapshot (heapWorker, s
|
||||
*/
|
||||
const takeCensus = exports.takeCensus = function (heapWorker, snapshot) {
|
||||
return function *(dispatch, getState) {
|
||||
// @TODO 1215606
|
||||
assert([states.READ, states.SAVED_CENSUS].includes(snapshot.state),
|
||||
"Can only take census of snapshots in READ or SAVED_CENSUS state");
|
||||
`Can only take census of snapshots in READ or SAVED_CENSUS state, found ${snapshot.state}`);
|
||||
|
||||
let census;
|
||||
let inverted = getState().inverted;
|
||||
let breakdown = getState().breakdown;
|
||||
|
||||
// If breakdown hasn't changed, don't do anything
|
||||
if (breakdownEquals(breakdown, snapshot.breakdown)) {
|
||||
// If breakdown and inversion haven't changed, don't do anything.
|
||||
if (inverted === snapshot.inverted && breakdownEquals(breakdown, snapshot.breakdown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -103,12 +114,45 @@ const takeCensus = exports.takeCensus = function (heapWorker, snapshot) {
|
||||
// that the breakdown used for the census is the same as
|
||||
// the state's breakdown.
|
||||
do {
|
||||
inverted = getState().inverted;
|
||||
breakdown = getState().breakdown;
|
||||
dispatch({ type: actions.TAKE_CENSUS_START, snapshot, breakdown });
|
||||
census = yield heapWorker.takeCensus(snapshot.path, { breakdown }, { asTreeNode: true });
|
||||
} while (!breakdownEquals(breakdown, getState().breakdown));
|
||||
dispatch({ type: actions.TAKE_CENSUS_START, snapshot, inverted, breakdown });
|
||||
let opts = inverted ? { asInvertedTreeNode: true } : { asTreeNode: true };
|
||||
|
||||
dispatch({ type: actions.TAKE_CENSUS_END, snapshot, breakdown, census });
|
||||
try {
|
||||
census = yield heapWorker.takeCensus(snapshot.path, { breakdown }, opts);
|
||||
} catch(error) {
|
||||
reportException("takeCensus", error);
|
||||
dispatch({ type: actions.SNAPSHOT_ERROR, snapshot, error });
|
||||
return;
|
||||
}
|
||||
}
|
||||
while (inverted !== getState().inverted ||
|
||||
!breakdownEquals(breakdown, getState().breakdown));
|
||||
|
||||
dispatch({ type: actions.TAKE_CENSUS_END, snapshot, breakdown, inverted, census });
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh the selected snapshot's census data, if need be (for example,
|
||||
* breakdown configuration changed).
|
||||
*
|
||||
* @param {HeapAnalysesClient} heapWorker
|
||||
*/
|
||||
const refreshSelectedCensus = exports.refreshSelectedCensus = function (heapWorker) {
|
||||
return function*(dispatch, getState) {
|
||||
let snapshot = getState().snapshots.find(s => s.selected);
|
||||
|
||||
// Intermediate snapshot states will get handled by the task action that is
|
||||
// orchestrating them. For example, if the snapshot's state is
|
||||
// SAVING_CENSUS, then the takeCensus action will keep taking a census until
|
||||
// the inverted property matches the inverted state. If the snapshot is
|
||||
// still in the process of being saved or read, the takeSnapshotAndCensus
|
||||
// task action will follow through and ensure that a census is taken.
|
||||
if (snapshot && snapshot.state === states.SAVED_CENSUS) {
|
||||
yield dispatch(takeCensus(heapWorker, snapshot));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/cl
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { toggleRecordingAllocationStacks } = require("./actions/allocations");
|
||||
const { setBreakdownAndRefresh } = require("./actions/breakdown");
|
||||
const { toggleInvertedAndRefresh } = require("./actions/inverted");
|
||||
const { selectSnapshotAndRefresh, takeSnapshotAndCensus } = require("./actions/snapshot");
|
||||
const { breakdownNameToSpec, getBreakdownDisplayData } = require("./utils");
|
||||
const Toolbar = createFactory(require("./components/toolbar"));
|
||||
@ -39,6 +40,7 @@ const App = createClass({
|
||||
heapWorker,
|
||||
breakdown,
|
||||
allocations,
|
||||
inverted
|
||||
} = this.props;
|
||||
|
||||
let selectedSnapshot = snapshots.find(s => s.selected);
|
||||
@ -53,7 +55,10 @@ const App = createClass({
|
||||
dispatch(setBreakdownAndRefresh(heapWorker, breakdownNameToSpec(breakdown))),
|
||||
onToggleRecordAllocationStacks: () =>
|
||||
dispatch(toggleRecordingAllocationStacks(front)),
|
||||
allocations
|
||||
allocations,
|
||||
inverted,
|
||||
onToggleInverted: () =>
|
||||
dispatch(toggleInvertedAndRefresh(heapWorker))
|
||||
}),
|
||||
|
||||
dom.div({ id: "memory-tool-container" }, [
|
||||
|
@ -3,9 +3,10 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { DOM: dom, createClass, PropTypes, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const { safeErrorString } = require("devtools/shared/DevToolsUtils");
|
||||
const Tree = createFactory(require("./tree"));
|
||||
const TreeItem = createFactory(require("./tree-item"));
|
||||
const { getSnapshotStatusText } = require("../utils");
|
||||
const { getSnapshotStatusTextFull } = require("../utils");
|
||||
const { snapshotState: states } = require("../constants");
|
||||
const { snapshot: snapshotModel } = require("../models");
|
||||
const TAKE_SNAPSHOT_TEXT = "Take snapshot";
|
||||
@ -40,8 +41,6 @@ function createTreeProperties (census) {
|
||||
let map = createParentMap(census);
|
||||
|
||||
return {
|
||||
// getParent only used for focusing parents when child selected;
|
||||
// handle this later?
|
||||
getParent: node => map(node.id),
|
||||
getChildren: node => node.children || [],
|
||||
renderItem: (item, depth, focused, arrow) => new TreeItem({ item, depth, focused, arrow }),
|
||||
@ -67,26 +66,37 @@ const Heap = module.exports = createClass({
|
||||
|
||||
render() {
|
||||
let { snapshot, onSnapshotClick } = this.props;
|
||||
let pane;
|
||||
let census = snapshot ? snapshot.census : null;
|
||||
let state = snapshot ? snapshot.state : "initial";
|
||||
let statusText = snapshot ? getSnapshotStatusTextFull(snapshot) : "";
|
||||
let content;
|
||||
|
||||
switch (state) {
|
||||
case "initial":
|
||||
pane = dom.div({ className: "heap-view-panel", "data-state": "initial" },
|
||||
dom.button({ className: "take-snapshot", onClick: onSnapshotClick }, TAKE_SNAPSHOT_TEXT)
|
||||
);
|
||||
content = dom.button({
|
||||
className: "devtools-toolbarbutton take-snapshot",
|
||||
onClick: onSnapshotClick,
|
||||
// Want to use the [standalone] tag to leverage our styles,
|
||||
// but React hates that evidently
|
||||
"data-standalone": true,
|
||||
"data-text-only": true,
|
||||
}, TAKE_SNAPSHOT_TEXT)
|
||||
break;
|
||||
case states.ERROR:
|
||||
content = [
|
||||
dom.span({ className: "snapshot-status error" }, statusText),
|
||||
dom.pre({}, safeErrorString(snapshot.error || new Error("blahblah"))),
|
||||
];
|
||||
break;
|
||||
case states.SAVING:
|
||||
case states.SAVED:
|
||||
case states.READING:
|
||||
case states.READ:
|
||||
case states.SAVING_CENSUS:
|
||||
pane = dom.div({ className: "heap-view-panel", "data-state": state },
|
||||
getSnapshotStatusText(snapshot));
|
||||
content = dom.span({ className: "snapshot-status devtools-throbber" }, statusText)
|
||||
break;
|
||||
case states.SAVED_CENSUS:
|
||||
pane = dom.div({ className: "heap-view-panel", "data-state": "loaded" },
|
||||
content = [
|
||||
dom.div({ className: "header" },
|
||||
dom.span({ className: "heap-tree-item-bytes" }, "Bytes"),
|
||||
dom.span({ className: "heap-tree-item-count" }, "Count"),
|
||||
@ -95,9 +105,10 @@ const Heap = module.exports = createClass({
|
||||
dom.span({ className: "heap-tree-item-name" }, "Name")
|
||||
),
|
||||
Tree(createTreeProperties(snapshot.census))
|
||||
);
|
||||
];
|
||||
break;
|
||||
}
|
||||
let pane = dom.div({ className: "heap-view-panel", "data-state": state }, content);
|
||||
|
||||
return (
|
||||
dom.div({ id: "heap-view", "data-state": state }, pane)
|
||||
|
@ -16,7 +16,9 @@ const Toolbar = module.exports = createClass({
|
||||
onTakeSnapshotClick: PropTypes.func.isRequired,
|
||||
onBreakdownChange: PropTypes.func.isRequired,
|
||||
onToggleRecordAllocationStacks: PropTypes.func.isRequired,
|
||||
allocations: models.allocations
|
||||
allocations: models.allocations,
|
||||
onToggleInverted: PropTypes.func.isRequired,
|
||||
inverted: PropTypes.bool.isRequired,
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -26,6 +28,8 @@ const Toolbar = module.exports = createClass({
|
||||
breakdowns,
|
||||
onToggleRecordAllocationStacks,
|
||||
allocations,
|
||||
onToggleInverted,
|
||||
inverted
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -37,6 +41,16 @@ const Toolbar = module.exports = createClass({
|
||||
onChange: e => onBreakdownChange(e.target.value),
|
||||
}, breakdowns.map(({ name, displayName }) => DOM.option({ value: name }, displayName))),
|
||||
|
||||
DOM.label({}, [
|
||||
DOM.input({
|
||||
type: "checkbox",
|
||||
checked: inverted,
|
||||
onChange: onToggleInverted,
|
||||
}),
|
||||
// TODO bug 1214799
|
||||
"Invert tree"
|
||||
]),
|
||||
|
||||
DOM.label({}, [
|
||||
DOM.input({
|
||||
type: "checkbox",
|
||||
@ -47,7 +61,7 @@ const Toolbar = module.exports = createClass({
|
||||
// TODO bug 1214799
|
||||
"Record allocation stacks"
|
||||
])
|
||||
])
|
||||
])
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -2,8 +2,12 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { isSavedFrame } = require("devtools/shared/DevToolsUtils");
|
||||
const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
|
||||
|
||||
const INDENT = 10;
|
||||
const MAX_SOURCE_LENGTH = 200;
|
||||
|
||||
|
||||
/**
|
||||
* An arrow that displays whether its node is expanded (▼) or collapsed
|
||||
@ -15,15 +19,34 @@ const TreeItem = module.exports = createClass({
|
||||
render() {
|
||||
let { item, depth, arrow, focused } = this.props;
|
||||
|
||||
return dom.div({ className: "heap-tree-item" },
|
||||
return dom.div({ className: `heap-tree-item ${focused ? "focused" :""}` },
|
||||
dom.span({ className: "heap-tree-item-bytes" }, item.bytes),
|
||||
dom.span({ className: "heap-tree-item-count" }, item.count),
|
||||
dom.span({ className: "heap-tree-item-total-bytes" }, item.totalBytes),
|
||||
dom.span({ className: "heap-tree-item-total-count" }, item.totalCount),
|
||||
dom.span({ className: "heap-tree-item-name", style: { marginLeft: depth * INDENT }},
|
||||
arrow,
|
||||
item.name
|
||||
this.toLabel(item.name)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
toLabel(name) {
|
||||
return isSavedFrame(name)
|
||||
? this.savedFrameToLabel(name)
|
||||
: String(name);
|
||||
},
|
||||
|
||||
savedFrameToLabel(frame) {
|
||||
return [
|
||||
dom.span({ className: "heap-tree-item-function-display-name" },
|
||||
frame.functionDisplayFrame || ""),
|
||||
dom.span({ className: "heap-tree-item-at" }, "@"),
|
||||
dom.span({ className: "heap-tree-item-source" }, frame.source.slice(0, MAX_SOURCE_LENGTH)),
|
||||
dom.span({ className: "heap-tree-item-colon" }, ":"),
|
||||
dom.span({ className: "heap-tree-item-line" }, frame.line),
|
||||
dom.span({ className: "heap-tree-item-colon" }, ":"),
|
||||
dom.span({ className: "heap-tree-item-column" }, frame.column)
|
||||
];
|
||||
}
|
||||
});
|
||||
|
@ -26,6 +26,12 @@ actions.TOGGLE_RECORD_ALLOCATION_STACKS_END = "toggle-record-allocation-stacks-e
|
||||
// Fired by UI to select a snapshot to view.
|
||||
actions.SELECT_SNAPSHOT = "select-snapshot";
|
||||
|
||||
// Fired to toggle tree inversion on or off.
|
||||
actions.TOGGLE_INVERTED = "toggle-inverted";
|
||||
|
||||
// Fired when there is an error processing a snapshot or taking a census.
|
||||
actions.SNAPSHOT_ERROR = "snapshot-error";
|
||||
|
||||
// Options passed to MemoryFront's startRecordingAllocations never change.
|
||||
exports.ALLOCATION_RECORDING_OPTIONS = {
|
||||
probability: 1,
|
||||
@ -71,10 +77,14 @@ const snapshotState = exports.snapshotState = {};
|
||||
* Various states a snapshot can be in.
|
||||
* An FSM describing snapshot states:
|
||||
*
|
||||
* SAVING -> SAVED -> READING -> READ <- <- <- SAVED_CENSUS
|
||||
* ↘ ↗
|
||||
* SAVING_CENSUS
|
||||
* SAVING -> SAVED -> READING -> READ <- <- <- SAVED_CENSUS
|
||||
* ↘ ↗
|
||||
* SAVING_CENSUS
|
||||
*
|
||||
* Any of these states may go to the ERROR state, from which they can never
|
||||
* leave (mwah ha ha ha!)
|
||||
*/
|
||||
snapshotState.ERROR = "snapshot-state-error";
|
||||
snapshotState.SAVING = "snapshot-state-saving";
|
||||
snapshotState.SAVED = "snapshot-state-saved";
|
||||
snapshotState.READING = "snapshot-state-reading";
|
||||
|
@ -31,6 +31,10 @@ let snapshotModel = exports.snapshot = PropTypes.shape({
|
||||
census: PropTypes.object,
|
||||
// The breakdown used to generate the current census
|
||||
breakdown: breakdownModel,
|
||||
// Whether the currently cached census tree is inverted or not.
|
||||
inverted: PropTypes.bool,
|
||||
// If an error was thrown while processing this snapshot, the `Error` instance is attached here.
|
||||
error: PropTypes.object,
|
||||
// State the snapshot is in
|
||||
// @see ./constants.js
|
||||
state: function (props, propName) {
|
||||
@ -63,7 +67,7 @@ let appModel = exports.app = {
|
||||
// {MemoryFront} Used to communicate with platform
|
||||
front: PropTypes.instanceOf(MemoryFront),
|
||||
// Allocations recording related data.
|
||||
allocations: allocationsModel,
|
||||
allocations: allocationsModel.isRequired,
|
||||
// {HeapAnalysesClient} Used to interface with snapshots
|
||||
heapWorker: PropTypes.instanceOf(HeapAnalysesClient),
|
||||
// The breakdown object DSL describing how we want
|
||||
@ -72,4 +76,6 @@ let appModel = exports.app = {
|
||||
breakdown: breakdownModel.isRequired,
|
||||
// List of reference to all snapshots taken
|
||||
snapshots: PropTypes.arrayOf(snapshotModel).isRequired,
|
||||
// True iff we want the tree displayed inverted.
|
||||
inverted: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
@ -1,126 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This file contains the tree view, displaying all the samples and frames
|
||||
* received from the proviler in a tree-like structure.
|
||||
*/
|
||||
|
||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||
const { Heritage } = require("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
|
||||
const { AbstractTreeItem } = require("resource://devtools/client/shared/widgets/AbstractTreeItem.jsm");
|
||||
|
||||
const INDENTATION = exports.INDENTATION = 16; // px
|
||||
const DEFAULT_AUTO_EXPAND_DEPTH = 2;
|
||||
const COURSE_TYPES = ["objects", "scripts", "strings", "other"];
|
||||
|
||||
/**
|
||||
* Every instance of a `CensusView` represents a row in the census tree. The same
|
||||
* parent node is used for all rows.
|
||||
*
|
||||
* @param CensusView parent
|
||||
* The CensusView considered the parent row. Should be null
|
||||
* for root node.
|
||||
* @param {CensusTreeNode} censusTreeNode
|
||||
* Data from `takeCensus` transformed via `CensusTreeNode`.
|
||||
* @see browser/toolkit/heapsnapshot/census-tree-node.js
|
||||
* @param number level [optional]
|
||||
* The indentation level in the call tree. The root node is at level 0.
|
||||
* @param boolean hidden [optional]
|
||||
* Whether this node should be hidden and not contribute to depth/level
|
||||
* calculations. Defaults to false.
|
||||
* @param number autoExpandDepth [optional]
|
||||
* The depth to which the tree should automatically expand. Defaults to
|
||||
* the caller's `autoExpandDepth` if a caller exists, otherwise defaults
|
||||
* to DEFAULT_AUTO_EXPAND_DEPTH.
|
||||
*/
|
||||
function CensusView ({ caller, censusTreeNode, level, hidden, autoExpandDepth }) {
|
||||
AbstractTreeItem.call(this, { parent: caller, level: level|0 - (hidden ? 1 : 0) });
|
||||
|
||||
this.autoExpandDepth = autoExpandDepth != null
|
||||
? autoExpandDepth
|
||||
: caller ? caller.autoExpandDepth
|
||||
: DEFAULT_AUTO_EXPAND_DEPTH;
|
||||
|
||||
this.caller = caller;
|
||||
this.censusTreeNode = censusTreeNode;
|
||||
this.hidden = hidden;
|
||||
};
|
||||
|
||||
CensusView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||
/**
|
||||
* Creates the view for this tree node.
|
||||
* @param nsIDOMNode document
|
||||
* @param nsIDOMNode arrowNode
|
||||
* @return nsIDOMNode
|
||||
*/
|
||||
_displaySelf: function (document, arrowNode) {
|
||||
let data = this.censusTreeNode;
|
||||
|
||||
let cells = [];
|
||||
|
||||
// Only use an arrow if there are children
|
||||
if (data.children && data.children.length) {
|
||||
cells.push(arrowNode);
|
||||
}
|
||||
|
||||
cells.push(this._createCell(document, data.name, "name"));
|
||||
|
||||
if (data.bytes != null) {
|
||||
cells.push(this._createCell(document, data.bytes, "bytes"));
|
||||
}
|
||||
if (data.count != null) {
|
||||
cells.push(this._createCell(document, data.count, "count"));
|
||||
}
|
||||
|
||||
let targetNode = document.createElement("li");
|
||||
targetNode.className = "heap-tree-item";
|
||||
targetNode.style.MozMarginStart = `${this.level * INDENTATION}px`;
|
||||
if (this.hidden) {
|
||||
targetNode.style.display = "none";
|
||||
}
|
||||
|
||||
for (let i = 0; i < cells.length; i++) {
|
||||
targetNode.appendChild(cells[i]);
|
||||
}
|
||||
|
||||
return targetNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Populates this node in the call tree with the corresponding "callees".
|
||||
* These are defined in the `frame` data source for this call view.
|
||||
* @param array:AbstractTreeItem children
|
||||
*/
|
||||
_populateSelf: function (children) {
|
||||
let newLevel = this.level + 1;
|
||||
let data = this.censusTreeNode;
|
||||
|
||||
if (data.children) {
|
||||
for (let node of data.children) {
|
||||
children.push(new CensusView({
|
||||
caller: this,
|
||||
level: newLevel,
|
||||
censusTreeNode: node,
|
||||
}));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Functions creating each cell in this call view.
|
||||
* Invoked by `_displaySelf`.
|
||||
*/
|
||||
_createCell: function (doc, value, type) {
|
||||
let cell = doc.createElement("span");
|
||||
cell.className = "plain heap-tree-cell";
|
||||
cell.setAttribute("type", type);
|
||||
cell.innerHTML = value;
|
||||
return cell;
|
||||
},
|
||||
});
|
||||
|
||||
exports.CensusView = CensusView;
|
@ -1,8 +0,0 @@
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'census-view.js',
|
||||
)
|
@ -6,7 +6,6 @@
|
||||
DIRS += [
|
||||
'actions',
|
||||
'components',
|
||||
'modules',
|
||||
'reducers',
|
||||
]
|
||||
|
||||
@ -22,5 +21,4 @@ DevToolsModules(
|
||||
)
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
@ -7,3 +7,4 @@ exports.allocations = require("./reducers/allocations");
|
||||
exports.snapshots = require("./reducers/snapshots");
|
||||
exports.breakdown = require("./reducers/breakdown");
|
||||
exports.errors = require("./reducers/errors");
|
||||
exports.inverted = require("./reducers/inverted");
|
||||
|
10
devtools/client/memory/reducers/inverted.js
Normal file
10
devtools/client/memory/reducers/inverted.js
Normal file
@ -0,0 +1,10 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const { actions } = require("../constants");
|
||||
|
||||
module.exports = function (inverted = false, action) {
|
||||
return action.type === actions.TOGGLE_INVERTED ? !inverted : inverted;
|
||||
};
|
@ -7,5 +7,6 @@ DevToolsModules(
|
||||
'allocations.js',
|
||||
'breakdown.js',
|
||||
'errors.js',
|
||||
'inverted.js',
|
||||
'snapshots.js',
|
||||
)
|
||||
|
@ -7,6 +7,13 @@ const { getSnapshot } = require("../utils");
|
||||
|
||||
let handlers = Object.create({});
|
||||
|
||||
handlers[actions.SNAPSHOT_ERROR] = function (snapshots, action) {
|
||||
let snapshot = getSnapshot(snapshots, action.snapshot);
|
||||
snapshot.state = states.ERROR;
|
||||
snapshot.error = action.error;
|
||||
return [...snapshots];
|
||||
};
|
||||
|
||||
handlers[actions.TAKE_SNAPSHOT_START] = function (snapshots, { snapshot }) {
|
||||
return [...snapshots, snapshot];
|
||||
};
|
||||
@ -38,6 +45,7 @@ handlers[actions.TAKE_CENSUS_START] = function (snapshots, action) {
|
||||
snapshot.state = states.SAVING_CENSUS;
|
||||
snapshot.census = null;
|
||||
snapshot.breakdown = action.breakdown;
|
||||
snapshot.inverted = action.inverted;
|
||||
return [...snapshots];
|
||||
};
|
||||
|
||||
@ -46,6 +54,7 @@ handlers[actions.TAKE_CENSUS_END] = function (snapshots, action) {
|
||||
snapshot.state = states.SAVED_CENSUS;
|
||||
snapshot.census = action.census;
|
||||
snapshot.breakdown = action.breakdown;
|
||||
snapshot.inverted = action.inverted;
|
||||
return [...snapshots];
|
||||
};
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
[DEFAULT]
|
||||
tags = devtools
|
||||
skip-if = buildapp == 'b2g' || os == 'android'
|
||||
support-files =
|
||||
head.js
|
||||
|
||||
[test_census-view-01.html]
|
@ -1,12 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
var CC = Components.Constructor;
|
||||
|
||||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
@ -1,103 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1067491 - Test taking a census over the RDP.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Census Tree 01</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/light-theme.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/common.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/widgets.css" type="text/css" />
|
||||
<link href="chrome://devtools/skin/themes/memory.css" type="text/css" />
|
||||
</head>
|
||||
<body>
|
||||
<ul id="container" style="width:100%;height:300px;"></ul>
|
||||
<pre id="test">
|
||||
<script src="head.js" type="application/javascript;version=1.8"></script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
var { censusReportToCensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node");
|
||||
var { INDENTATION, CensusView } = require("devtools/client/memory/modules/census-view");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
const countBreakdown = { by: "count", count: true, bytes: true };
|
||||
|
||||
const BREAKDOWN = {
|
||||
by: "coarseType",
|
||||
objects: { by: "objectClass", then: countBreakdown },
|
||||
strings: countBreakdown,
|
||||
scripts: countBreakdown,
|
||||
other: { by: "internalType", then: countBreakdown },
|
||||
};
|
||||
|
||||
const REPORT = {
|
||||
"objects": {
|
||||
"Function": { bytes: 10, count: 1 },
|
||||
"Array": { bytes: 20, count: 2 },
|
||||
},
|
||||
"strings": { bytes: 10, count: 1 },
|
||||
"scripts": { bytes: 20, count: 2 },
|
||||
"other": {
|
||||
"js::Shape": { bytes: 30, count: 3 },
|
||||
"js::Shape2": { bytes: 40, count: 4 }
|
||||
},
|
||||
};
|
||||
|
||||
const EXPECTED_ROWS = [
|
||||
{ level: 0, name: "other", bytes: 0, count: 0 },
|
||||
{ level: 1, name: "js::Shape2", bytes: 40, count: 4, },
|
||||
{ level: 1, name: "js::Shape", bytes: 30, count: 3, },
|
||||
{ level: 0, name: "objects", bytes: 0, count: 0 },
|
||||
{ level: 1, name: "Array", bytes: 20, count: 2, },
|
||||
{ level: 1, name: "Function", bytes: 10, count: 1, },
|
||||
{ level: 0, name: "scripts", bytes: 20, count: 2, },
|
||||
{ level: 0, name: "strings", bytes: 10, count: 1, },
|
||||
];
|
||||
var censusTreeNode = censusReportToCensusTreeNode(BREAKDOWN, REPORT);
|
||||
|
||||
var view = new CensusView({
|
||||
censusTreeNode: censusTreeNode,
|
||||
hidden: true
|
||||
});
|
||||
|
||||
view.attachTo(document.querySelector("#container"));
|
||||
|
||||
var ul = document.querySelector("#container");
|
||||
var children = Array.from(ul.children).filter(n => n.style.display !== "none");
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var el = children[i];
|
||||
var expected = EXPECTED_ROWS[i];
|
||||
var nameEl = el.querySelector(".heap-tree-cell[type='name']");
|
||||
var bytesEl = el.querySelector(".heap-tree-cell[type='bytes']");
|
||||
var countEl = el.querySelector(".heap-tree-cell[type='count']");
|
||||
|
||||
is(nameEl.innerHTML, expected.name,
|
||||
`correct name "${expected.name}" in heap tree`);
|
||||
|
||||
is(el.style.MozMarginStart, (INDENTATION * expected.level) + "px",
|
||||
`correct indentation for ${expected.name}`);
|
||||
|
||||
if ("bytes" in expected) {
|
||||
is(bytesEl.innerHTML, String(expected.bytes),
|
||||
`correct bytes "${expected.bytes}" in heap tree`);
|
||||
} else {
|
||||
ok(!bytesEl, `no bytes correctly displayed for ${expected.name}`);
|
||||
}
|
||||
|
||||
if ("count" in expected) {
|
||||
is(countEl.innerHTML, String(expected.count),
|
||||
`correct count "${expected.count}" in heap tree`);
|
||||
} else {
|
||||
ok(!countEl, `no count correctly displayed for ${expected.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,64 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that changing inverted state properly refreshes the selected census.
|
||||
|
||||
let { breakdowns, snapshotState: states } = require("devtools/client/memory/constants");
|
||||
let { toggleInvertedAndRefresh } = require("devtools/client/memory/actions/inverted");
|
||||
let { takeSnapshotAndCensus, selectSnapshotAndRefresh } = require("devtools/client/memory/actions/snapshot");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
let front = new StubbedMemoryFront();
|
||||
let heapWorker = new HeapAnalysesClient();
|
||||
yield front.attach();
|
||||
let store = Store();
|
||||
let { getState, dispatch } = store;
|
||||
|
||||
equal(getState().inverted, false, "not inverted by default");
|
||||
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS]);
|
||||
ok(true, "saved 3 snapshots and took a census of each of them");
|
||||
|
||||
dispatch(toggleInvertedAndRefresh(heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS,
|
||||
states.SAVING_CENSUS]);
|
||||
ok(true, "toggling inverted should recompute the selected snapshot's census");
|
||||
|
||||
equal(getState().inverted, true, "now inverted");
|
||||
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS]);
|
||||
|
||||
equal(getState().snapshots[0].inverted, false);
|
||||
equal(getState().snapshots[1].inverted, false);
|
||||
equal(getState().snapshots[2].inverted, true);
|
||||
|
||||
dispatch(selectSnapshotAndRefresh(heapWorker, getState().snapshots[1]));
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS,
|
||||
states.SAVING_CENSUS,
|
||||
states.SAVED_CENSUS]);
|
||||
ok(true, "selecting non-inverted census should trigger a recompute");
|
||||
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS,
|
||||
states.SAVED_CENSUS]);
|
||||
|
||||
equal(getState().snapshots[0].inverted, false);
|
||||
equal(getState().snapshots[1].inverted, true);
|
||||
equal(getState().snapshots[2].inverted, true);
|
||||
|
||||
heapWorker.destroy();
|
||||
yield front.detach();
|
||||
});
|
@ -0,0 +1,46 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that changing inverted state in the middle of taking a snapshot results
|
||||
// in an inverted census.
|
||||
|
||||
let { snapshotState: states } = require("devtools/client/memory/constants");
|
||||
let { toggleInverted, toggleInvertedAndRefresh } = require("devtools/client/memory/actions/inverted");
|
||||
let { takeSnapshotAndCensus, selectSnapshotAndRefresh } = require("devtools/client/memory/actions/snapshot");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
let front = new StubbedMemoryFront();
|
||||
let heapWorker = new HeapAnalysesClient();
|
||||
yield front.attach();
|
||||
let store = Store();
|
||||
let { getState, dispatch } = store;
|
||||
|
||||
dispatch(takeSnapshotAndCensus(front, heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVING]);
|
||||
|
||||
dispatch(toggleInverted());
|
||||
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
|
||||
ok(getState().inverted,
|
||||
"should want inverted trees");
|
||||
ok(getState().snapshots[0].inverted,
|
||||
"snapshot-we-were-in-the-middle-of-saving's census should be inverted");
|
||||
|
||||
dispatch(toggleInvertedAndRefresh(heapWorker));
|
||||
yield waitUntilSnapshotState(store, [states.SAVING_CENSUS]);
|
||||
ok(true, "toggling inverted retriggers census");
|
||||
ok(!getState().inverted, "no long inverted");
|
||||
|
||||
dispatch(toggleInverted());
|
||||
yield waitUntilSnapshotState(store, [states.SAVED_CENSUS]);
|
||||
ok(getState().inverted, "inverted again");
|
||||
ok(getState().snapshots[0].inverted,
|
||||
"census-we-were-in-the-middle-of-recomputing should be inverted again");
|
||||
|
||||
heapWorker.destroy();
|
||||
yield front.detach();
|
||||
});
|
@ -0,0 +1,29 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test toggling the top level inversion state of the tree.
|
||||
|
||||
let { toggleInverted } = require("devtools/client/memory/actions/inverted");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
let front = new StubbedMemoryFront();
|
||||
let heapWorker = new HeapAnalysesClient();
|
||||
yield front.attach();
|
||||
let store = Store();
|
||||
const { getState, dispatch } = store;
|
||||
|
||||
equal(getState().inverted, false, "not inverted by default");
|
||||
|
||||
dispatch(toggleInverted());
|
||||
equal(getState().inverted, true, "now inverted after toggling");
|
||||
|
||||
dispatch(toggleInverted());
|
||||
equal(getState().inverted, false, "not inverted again after toggling again");
|
||||
|
||||
heapWorker.destroy();
|
||||
yield front.detach();
|
||||
});
|
@ -5,6 +5,9 @@ tail =
|
||||
firefox-appdir = browser
|
||||
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||
|
||||
[test_action-toggle-inverted.js]
|
||||
[test_action-toggle-inverted-and-refresh-01.js]
|
||||
[test_action-toggle-inverted-and-refresh-02.js]
|
||||
[test_action-toggle-recording-allocations.js]
|
||||
[test_action-select-snapshot.js]
|
||||
[test_action-set-breakdown.js]
|
||||
|
@ -2,24 +2,17 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { assert } = require("devtools/shared/DevToolsUtils");
|
||||
const { Preferences } = require("resource://gre/modules/Preferences.jsm");
|
||||
const CUSTOM_BREAKDOWN_PREF = "devtools.memory.custom-breakdowns";
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { snapshotState: states, breakdowns } = require("./constants");
|
||||
const FULL_ERROR_TEXT = "There was an error processing this snapshot.";
|
||||
const ERROR_SNAPSHOT_TEXT = "⚠ Error!";
|
||||
const SAVING_SNAPSHOT_TEXT = "Saving snapshot...";
|
||||
const READING_SNAPSHOT_TEXT = "Reading snapshot...";
|
||||
const SAVING_CENSUS_TEXT = "Taking heap census...";
|
||||
|
||||
// @TODO 1215606
|
||||
// Use DevToolsUtils.assert when fixed.
|
||||
exports.assert = function (condition, message) {
|
||||
if (!condition) {
|
||||
const err = new Error("Assertion failure: " + message);
|
||||
DevToolsUtils.reportException("DevToolsUtils.assert", err);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array of objects with the unique key `name`
|
||||
* and `displayName` for each breakdown.
|
||||
@ -94,15 +87,18 @@ exports.breakdownNameToSpec = function (name) {
|
||||
|
||||
/**
|
||||
* Returns a string representing a readable form of the snapshot's state.
|
||||
* More brief than `getSnapshotStatusText`.
|
||||
*
|
||||
* @param {Snapshot} snapshot
|
||||
* @return {String}
|
||||
*/
|
||||
exports.getSnapshotStatusText = function (snapshot) {
|
||||
exports.assert((snapshot || {}).state,
|
||||
assert((snapshot || {}).state,
|
||||
`Snapshot must have expected state, found ${(snapshot || {}).state}.`);
|
||||
|
||||
switch (snapshot.state) {
|
||||
case states.ERROR:
|
||||
return ERROR_SNAPSHOT_TEXT;
|
||||
case states.SAVING:
|
||||
return SAVING_SNAPSHOT_TEXT;
|
||||
case states.SAVED:
|
||||
@ -118,10 +114,27 @@ exports.getSnapshotStatusText = function (snapshot) {
|
||||
return "";
|
||||
}
|
||||
|
||||
DevToolsUtils.reportException(`Snapshot in unexpected state: ${snapshot.state}`);
|
||||
assert(false, `Snapshot in unexpected state: ${snapshot.state}`);
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing a readable form of the snapshot's state;
|
||||
* more verbose than `getSnapshotStatusText`.
|
||||
*
|
||||
* @param {Snapshot} snapshot
|
||||
* @return {String}
|
||||
*/
|
||||
exports.getSnapshotStatusTextFull = function (snapshot) {
|
||||
assert((snapshot || {}).state,
|
||||
`Snapshot must have expected state, found ${(snapshot || {}).state}.`);
|
||||
switch (snapshot.state) {
|
||||
case states.ERROR:
|
||||
return FULL_ERROR_TEXT;
|
||||
}
|
||||
return exports.getSnapshotStatusText(snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an array of snapshots and a snapshot and returns
|
||||
* the snapshot instance in `snapshots` that matches
|
||||
|
@ -3091,7 +3091,8 @@
|
||||
|
||||
if (cm.state.focused && op.updateInput)
|
||||
cm.display.input.reset(op.typing);
|
||||
if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
|
||||
if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
|
||||
ensureFocus(op.cm);
|
||||
}
|
||||
|
||||
function endOperation_finish(op) {
|
||||
|
@ -25,7 +25,8 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
|
||||
.theme-body {
|
||||
overflow: hidden;
|
||||
background-color: var(--theme-body-background);
|
||||
/* Not sure why .theme-body declares it as `background` and overrides */
|
||||
background-color: var(--theme-toolbar-background) !important;
|
||||
}
|
||||
|
||||
#memory-tool-container {
|
||||
@ -45,7 +46,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
* toolbars.inc.css contains definitions for .devtools-button,
|
||||
* I wager that many of the below styles can be rolled into that
|
||||
*/
|
||||
.devtools-button.take-snapshot {
|
||||
.devtools-toolbar .devtools-button.take-snapshot {
|
||||
margin: 2px 1px;
|
||||
padding: 1px;
|
||||
border-width: 0px;
|
||||
@ -55,7 +56,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
.devtools-button.take-snapshot::before {
|
||||
.devtools-toolbar .devtools-button.take-snapshot::before {
|
||||
background-image: url(images/command-screenshot.png);
|
||||
-moz-appearance: none;
|
||||
width: 16px;
|
||||
@ -65,7 +66,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.devtools-button.take-snapshot::before {
|
||||
.devtools-toolbar .devtools-button.take-snapshot::before {
|
||||
background-image: url(images/command-screenshot@2x.png);
|
||||
}
|
||||
}
|
||||
@ -109,9 +110,10 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border-color: var(--theme-splitter-color);
|
||||
color: var(--theme-body-color-alt);
|
||||
border-left-width: 1px;
|
||||
border-color: var(--theme-splitter-color);
|
||||
border-style: solid;
|
||||
border-width: 0px 1px 0px 0px;
|
||||
}
|
||||
|
||||
.list > li {
|
||||
@ -120,6 +122,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
border-bottom: 1px solid rgba(128,128,128,0.15);
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.list > li.selected {
|
||||
@ -148,16 +151,37 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
#heap-view {
|
||||
flex: 1 1 auto;
|
||||
border-color: var(--theme-splitter-color);
|
||||
color: var(--theme-body-color)
|
||||
color: var(--theme-body-color);
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
#heap-view .heap-view-panel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--theme-toolbar-background)
|
||||
}
|
||||
|
||||
#heap-view .heap-view-panel .snapshot-status, #heap-view .take-snapshot {
|
||||
font-size: 120%;
|
||||
display: block;
|
||||
margin: 65px auto;
|
||||
}
|
||||
|
||||
#heap-view .heap-view-panel .snapshot-status {
|
||||
width: 500px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#heap-view .take-snapshot {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#heap-view .heap-view-panel[data-state="snapshot-state-error"] pre {
|
||||
background-color: var(--theme-body-background);
|
||||
overflow-y: scroll;
|
||||
height: 100px;
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,6 +195,7 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
.tree {
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
background-color: var(--theme-body-background);
|
||||
}
|
||||
|
||||
.tree .header {
|
||||
@ -206,8 +231,9 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
background-color: var(--row-hover-background-color);
|
||||
}
|
||||
|
||||
.tree-node:focus {
|
||||
.tree-node:focus, .heap-tree-item.focused {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.header {
|
||||
@ -244,3 +270,20 @@ html, .theme-body, #app, #memory-tool, #memory-tool-container {
|
||||
.heap-tree-item-name {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.error::before {
|
||||
content: "";
|
||||
background-image: url(chrome://devtools/skin/themes/images/webconsole.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 72px 60px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
display: inline-block;
|
||||
|
||||
background-position: -24px -24px;
|
||||
margin: 2px 5px 0 0;
|
||||
max-height: 12px;
|
||||
}
|
||||
.theme-light .error::before {
|
||||
background-image: url(chrome://devtools/skin/themes/images/webconsole.svg#light-icons);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@
|
||||
outline-offset: -4px;
|
||||
}
|
||||
|
||||
.devtools-toolbarbutton[standalone] {
|
||||
.devtools-toolbarbutton[standalone], .devtools-toolbarbutton[data-standalone] {
|
||||
-moz-margin-end: 5px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
@ -164,10 +164,12 @@
|
||||
|
||||
/* Text-only buttons */
|
||||
.theme-light .devtools-toolbarbutton[label]:not([text-as-image]):not([type=menu-button]),
|
||||
.theme-light .devtools-toolbarbutton[data-text-only],
|
||||
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image] {
|
||||
background-color: rgba(170, 170, 170, .2); /* Splitter */
|
||||
}
|
||||
.theme-dark .devtools-toolbarbutton[label]:not([text-as-image]):not([type=menu-button]),
|
||||
.theme-dark .devtools-toolbarbutton[data-text-only],
|
||||
.theme-dark #toolbox-buttons .devtools-toolbarbutton[text-as-image] {
|
||||
background-color: rgba(0, 0, 0, .2); /* Splitter */
|
||||
}
|
||||
@ -270,7 +272,7 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.devtools-button[standalone] {
|
||||
.devtools-button[standalone], .devtools-button[data-standalone] {
|
||||
min-height: 32px;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
@ -818,3 +818,10 @@ exports.isGenerator = function (fn) {
|
||||
exports.isPromise = function (p) {
|
||||
return p && typeof p.then === "function";
|
||||
};
|
||||
|
||||
/**
|
||||
* Return true if `thing` is a SavedFrame, false otherwise.
|
||||
*/
|
||||
exports.isSavedFrame = function (thing) {
|
||||
return Object.prototype.toString.call(thing) === "[object SavedFrame]";
|
||||
};
|
||||
|
@ -110,7 +110,7 @@ message Node {
|
||||
bytes typeName = 2;
|
||||
uint64 typeNameRef = 3;
|
||||
}
|
||||
|
||||
|
||||
optional uint64 size = 4;
|
||||
repeated Edge edges = 5;
|
||||
optional StackFrame allocationStack = 6;
|
||||
|
@ -104,6 +104,15 @@ parseMessage(ZeroCopyInputStream& stream, MessageType& message)
|
||||
// 64MB limit is applied per-message rather than to the whole stream.
|
||||
CodedInputStream codedStream(&stream);
|
||||
|
||||
// The protobuf message nesting that core dumps exhibit is dominated by
|
||||
// allocation stacks' frames. In the most deeply nested case, each frame has
|
||||
// two messages: a StackFrame message and a StackFrame::Data message. These
|
||||
// frames are on top of a small constant of other messages. There are a
|
||||
// MAX_STACK_DEPTH number of frames, so we multiply this by 3 to make room for
|
||||
// the two messages per frame plus some head room for the constant number of
|
||||
// non-dominating messages.
|
||||
codedStream.SetRecursionLimit(HeapSnapshot::MAX_STACK_DEPTH * 3);
|
||||
|
||||
// Because protobuf messages aren't self-delimiting, we serialize each message
|
||||
// preceeded by its size in bytes. When deserializing, we read this size and
|
||||
// then limit reading from the stream to the given byte size. If we didn't,
|
||||
@ -115,7 +124,8 @@ parseMessage(ZeroCopyInputStream& stream, MessageType& message)
|
||||
|
||||
auto limit = codedStream.PushLimit(size);
|
||||
if (NS_WARN_IF(!message.ParseFromCodedStream(&codedStream)) ||
|
||||
NS_WARN_IF(!codedStream.ConsumedEntireMessage()))
|
||||
NS_WARN_IF(!codedStream.ConsumedEntireMessage()) ||
|
||||
NS_WARN_IF(codedStream.BytesUntilLimit() != 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -909,7 +919,8 @@ class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter
|
||||
return true;
|
||||
}
|
||||
|
||||
protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame) {
|
||||
protobuf::StackFrame* getProtobufStackFrame(JS::ubi::StackFrame& frame,
|
||||
size_t depth = 1) {
|
||||
// NB: de-duplicated string properties must be written in the same order
|
||||
// here as they are read in `HeapSnapshot::saveStackFrame` or else indices
|
||||
// in references to already serialized strings will be off.
|
||||
@ -957,8 +968,8 @@ class MOZ_STACK_CLASS StreamWriter : public CoreDumpWriter
|
||||
}
|
||||
|
||||
auto parent = frame.parent();
|
||||
if (parent) {
|
||||
auto protobufParent = getProtobufStackFrame(parent);
|
||||
if (parent && depth < HeapSnapshot::MAX_STACK_DEPTH) {
|
||||
auto protobufParent = getProtobufStackFrame(parent, depth + 1);
|
||||
if (!protobufParent)
|
||||
return nullptr;
|
||||
data->set_allocated_parent(protobufParent);
|
||||
|
@ -71,6 +71,13 @@ class HeapSnapshot final : public nsISupports
|
||||
bool saveStackFrame(const protobuf::StackFrame& frame,
|
||||
StackFrameId& outFrameId);
|
||||
|
||||
public:
|
||||
// The maximum number of stack frames that we will serialize into a core
|
||||
// dump. This helps prevent over-recursion in the protobuf library when
|
||||
// deserializing stacks.
|
||||
static const size_t MAX_STACK_DEPTH = 60;
|
||||
|
||||
private:
|
||||
// If present, a timestamp in the same units that `PR_Now` gives.
|
||||
Maybe<uint64_t> timestamp;
|
||||
|
||||
|
@ -0,0 +1,70 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that we can save a core dump with very deep allocation stacks and read
|
||||
// it back into a HeapSnapshot.
|
||||
|
||||
function stackDepth(stack) {
|
||||
return stack ? 1 + stackDepth(stack.parent) : 0;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// Create a Debugger observing a debuggee's allocations.
|
||||
const debuggee = new Cu.Sandbox(null);
|
||||
const dbg = new Debugger(debuggee);
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
|
||||
// Allocate some objects in the debuggee that will have their allocation
|
||||
// stacks recorded by the Debugger.
|
||||
|
||||
debuggee.eval("this.objects = []");
|
||||
debuggee.eval(
|
||||
(function recursiveAllocate(n) {
|
||||
if (n <= 0)
|
||||
return;
|
||||
|
||||
// Make sure to recurse before pushing the object so that when TCO is
|
||||
// implemented sometime in the future, it doesn't invalidate this test.
|
||||
recursiveAllocate(n - 1);
|
||||
this.objects.push({});
|
||||
}).toString()
|
||||
);
|
||||
debuggee.eval("recursiveAllocate = recursiveAllocate.bind(this);");
|
||||
debuggee.eval("recursiveAllocate(200);");
|
||||
|
||||
// Now save a snapshot that will include the allocation stacks and read it
|
||||
// back again.
|
||||
|
||||
const filePath = ChromeUtils.saveHeapSnapshot({ runtime: true });
|
||||
ok(true, "Should be able to save a snapshot.");
|
||||
|
||||
const snapshot = ChromeUtils.readHeapSnapshot(filePath);
|
||||
ok(snapshot, "Should be able to read a heap snapshot");
|
||||
ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot");
|
||||
|
||||
const report = snapshot.takeCensus({
|
||||
breakdown: { by: "allocationStack",
|
||||
then: { by: "count", bytes: true, count: true },
|
||||
noStack: { by: "count", bytes: true, count: true }
|
||||
}
|
||||
});
|
||||
|
||||
// Keep this synchronized with `HeapSnapshot::MAX_STACK_DEPTH`!
|
||||
const MAX_STACK_DEPTH = 60;
|
||||
|
||||
let foundStacks = false;
|
||||
report.forEach((v, k) => {
|
||||
if (k === "noStack") {
|
||||
return;
|
||||
}
|
||||
|
||||
foundStacks = true;
|
||||
const depth = stackDepth(k);
|
||||
dumpn("Stack depth is " + depth);
|
||||
ok(depth <= MAX_STACK_DEPTH,
|
||||
"Every stack should have depth less than or equal to the maximum stack depth");
|
||||
});
|
||||
ok(foundStacks);
|
||||
|
||||
do_test_finished();
|
||||
}
|
@ -34,6 +34,7 @@ support-files =
|
||||
[test_HeapAnalyses_takeCensus_06.js]
|
||||
[test_HeapAnalyses_takeCensus_07.js]
|
||||
[test_HeapSnapshot_creationTime_01.js]
|
||||
[test_HeapSnapshot_deepStack_01.js]
|
||||
[test_HeapSnapshot_takeCensus_01.js]
|
||||
[test_HeapSnapshot_takeCensus_02.js]
|
||||
[test_HeapSnapshot_takeCensus_03.js]
|
||||
|
@ -16,12 +16,14 @@ import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.login.Engaged;
|
||||
import org.mozilla.gecko.fxa.login.State;
|
||||
import org.mozilla.gecko.restrictions.Restriction;
|
||||
import org.mozilla.gecko.sync.SyncConfiguration;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
@ -32,6 +34,8 @@ import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class to manage Android Accounts corresponding to Firefox Accounts.
|
||||
@ -57,7 +61,8 @@ public class AccountsHelper implements NativeEventListener {
|
||||
"Accounts:Create",
|
||||
"Accounts:DeleteFirefoxAccount",
|
||||
"Accounts:Exist",
|
||||
"Accounts:ProfileUpdated");
|
||||
"Accounts:ProfileUpdated",
|
||||
"Accounts:ShowSyncPreferences");
|
||||
}
|
||||
|
||||
public synchronized void uninit() {
|
||||
@ -72,7 +77,8 @@ public class AccountsHelper implements NativeEventListener {
|
||||
"Accounts:Create",
|
||||
"Accounts:DeleteFirefoxAccount",
|
||||
"Accounts:Exist",
|
||||
"Accounts:ProfileUpdated");
|
||||
"Accounts:ProfileUpdated",
|
||||
"Accounts:ShowSyncPreferences");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,6 +119,26 @@ public class AccountsHelper implements NativeEventListener {
|
||||
profileServerEndpoint,
|
||||
state,
|
||||
AndroidFxAccount.DEFAULT_AUTHORITIES_TO_SYNC_AUTOMATICALLY_MAP);
|
||||
|
||||
final String[] declinedSyncEngines = json.optStringArray("declinedSyncEngines", null);
|
||||
if (declinedSyncEngines != null) {
|
||||
Log.i(LOGTAG, "User has selected engines; storing to prefs.");
|
||||
final Map<String, Boolean> selectedEngines = new HashMap<String, Boolean>();
|
||||
for (String enabledSyncEngine : SyncConfiguration.validEngineNames()) {
|
||||
selectedEngines.put(enabledSyncEngine, true);
|
||||
}
|
||||
for (String declinedSyncEngine : declinedSyncEngines) {
|
||||
selectedEngines.put(declinedSyncEngine, false);
|
||||
}
|
||||
// The "forms" engine has the same state as the "history" engine.
|
||||
selectedEngines.put("forms", selectedEngines.get("history"));
|
||||
FxAccountUtils.pii(LOGTAG, "User selected engines: " + selectedEngines.toString());
|
||||
try {
|
||||
SyncConfiguration.storeSelectedEnginesToPrefs(fxAccount.getSyncPrefs(), selectedEngines);
|
||||
} catch (UnsupportedEncodingException | GeneralSecurityException e) {
|
||||
Log.e(LOGTAG, "Got exception storing selected engines; ignoring.", e);
|
||||
}
|
||||
}
|
||||
} catch (URISyntaxException | GeneralSecurityException | UnsupportedEncodingException e) {
|
||||
Log.w(LOGTAG, "Got exception creating Firefox Account from JSON; ignoring.", e);
|
||||
if (callback != null) {
|
||||
@ -270,6 +296,17 @@ public class AccountsHelper implements NativeEventListener {
|
||||
}
|
||||
final AndroidFxAccount androidFxAccount = new AndroidFxAccount(mContext, account);
|
||||
androidFxAccount.fetchProfileJSON();
|
||||
} else if ("Accounts:ShowSyncPreferences".equals(event)) {
|
||||
final Account account = FirefoxAccounts.getFirefoxAccount(mContext);
|
||||
if (account == null) {
|
||||
Log.w(LOGTAG, "Can't change show Sync preferences of non-existent Firefox Account!; ignored");
|
||||
return;
|
||||
}
|
||||
// We don't necessarily have an Activity context here, so we always start in a new task.
|
||||
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_STATUS);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +116,20 @@ public class AppConstants {
|
||||
false;
|
||||
//#endif
|
||||
|
||||
public static final boolean MOZ_ANDROID_GCM =
|
||||
//#ifdef MOZ_ANDROID_GCM
|
||||
true;
|
||||
//#else
|
||||
false;
|
||||
//#endif
|
||||
|
||||
public static final String MOZ_ANDROID_GCM_SENDERID =
|
||||
//#ifdef MOZ_ANDROID_GCM_SENDERID
|
||||
"@MOZ_ANDROID_GCM_SENDERID@";
|
||||
//#else
|
||||
null;
|
||||
//#endif
|
||||
|
||||
public static final String MOZ_CHILD_PROCESS_NAME = "@MOZ_CHILD_PROCESS_NAME@";
|
||||
public static final String MOZ_UPDATE_CHANNEL = "@MOZ_UPDATE_CHANNEL@";
|
||||
public static final String OMNIJAR_NAME = "@OMNIJAR_NAME@";
|
||||
|
@ -18,12 +18,16 @@ import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.SuggestedSites;
|
||||
import org.mozilla.gecko.db.TabsAccessor;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
import org.mozilla.gecko.favicons.LoadFaviconTask;
|
||||
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
|
||||
import org.mozilla.gecko.favicons.decoders.IconDirectoryEntry;
|
||||
import org.mozilla.gecko.firstrun.FirstrunPane;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
|
||||
import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
|
||||
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
@ -82,6 +86,7 @@ import org.mozilla.gecko.widget.ButtonToast;
|
||||
import org.mozilla.gecko.widget.ButtonToast.ToastListener;
|
||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ContentResolver;
|
||||
@ -104,6 +109,8 @@ import android.nfc.NfcEvent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.StrictMode;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.WorkerThread;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
@ -3229,16 +3236,13 @@ public class BrowserApp extends GeckoApp
|
||||
if (itemId == R.id.send_to_device) {
|
||||
tab = Tabs.getInstance().getSelectedTab();
|
||||
if (tab != null) {
|
||||
String url = tab.getURL();
|
||||
if (url != null) {
|
||||
if (AboutPages.isAboutReader(url)) {
|
||||
url = ReaderModeUtils.getUrlFromAboutReader(url);
|
||||
final Tab selectedTab = tab;
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleSendToDevice(selectedTab);
|
||||
}
|
||||
Intent sendToDeviceIntent = GeckoAppShell.getShareIntent(getContext(), url,
|
||||
"text/plain", tab.getDisplayTitle());
|
||||
sendToDeviceIntent.setClass(getContext(), ShareDialog.class);
|
||||
startActivity(sendToDeviceIntent);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -3368,6 +3372,46 @@ public class BrowserApp extends GeckoApp
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a press to the send to device button in the browser menu. The
|
||||
* expected states when the user presses the button are:
|
||||
* * Not signed in: open to FxA sign-up
|
||||
* * Signed in but no other devices: display toast with a message
|
||||
* explaining they should connect another device to use this feature
|
||||
* * Signed in but >= 1 other device: display device list
|
||||
*/
|
||||
@WorkerThread
|
||||
private void handleSendToDevice(@NonNull final Tab selectedTab) {
|
||||
final Account account = FirefoxAccounts.getFirefoxAccount(this);
|
||||
if (account == null) {
|
||||
// TODO (bug 1217164): Go back to previous tab on back press
|
||||
final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
|
||||
intent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES);
|
||||
startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
final BrowserDB browserDB = GeckoProfile.get(this).getDB();
|
||||
final TabsAccessor tabsAccessor = browserDB.getTabsAccessor();
|
||||
final int remoteClientCount = tabsAccessor.getRemoteClientCount(this);
|
||||
if (remoteClientCount == 0) {
|
||||
final Toast toast = Toast.makeText(this, R.string.menu_no_synced_devices, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
|
||||
} else {
|
||||
String url = selectedTab.getURL();
|
||||
if (url != null) {
|
||||
if (AboutPages.isAboutReader(url)) {
|
||||
url = ReaderModeUtils.getUrlFromAboutReader(url);
|
||||
}
|
||||
final Intent sendToDeviceIntent = GeckoAppShell.getShareIntent(getContext(), url,
|
||||
"text/plain", selectedTab.getDisplayTitle());
|
||||
sendToDeviceIntent.setClass(getContext(), ShareDialog.class);
|
||||
startActivity(sendToDeviceIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemLongClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.reload) {
|
||||
|
@ -74,6 +74,14 @@ ifdef MOZ_NATIVE_DEVICES
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_ANDROID_GCM
|
||||
JAVA_CLASSPATH += \
|
||||
$(ANDROID_PLAY_SERVICES_BASE_AAR_LIB) \
|
||||
$(ANDROID_PLAY_SERVICES_BASEMENT_AAR_LIB) \
|
||||
$(ANDROID_PLAY_SERVICES_GCM_AAR_LIB) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
JAVA_CLASSPATH := $(subst $(NULL) ,:,$(strip $(JAVA_CLASSPATH)))
|
||||
|
||||
# Library jars that we're bundling: these are subject to Proguard before inclusion
|
||||
@ -96,6 +104,18 @@ ifdef MOZ_NATIVE_DEVICES
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_ANDROID_GCM
|
||||
java_bundled_libs += \
|
||||
$(ANDROID_PLAY_SERVICES_BASE_AAR_LIB) \
|
||||
$(ANDROID_PLAY_SERVICES_BASEMENT_AAR_LIB) \
|
||||
$(ANDROID_PLAY_SERVICES_GCM_AAR_LIB) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
# uniq purloined from http://stackoverflow.com/a/16151140.
|
||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||
|
||||
java_bundled_libs := $(call uniq,$(java_bundled_libs))
|
||||
java_bundled_libs := $(subst $(NULL) ,:,$(strip $(java_bundled_libs)))
|
||||
|
||||
# All the jars we're compiling from source. (not to be confused with
|
||||
@ -371,6 +391,7 @@ generated/android/support/v7/recyclerview/R.java: .aapt.deps ;
|
||||
generated/com/google/android/gms/R.java: .aapt.deps ;
|
||||
generated/com/google/android/gms/base/R.java: .aapt.deps ;
|
||||
generated/com/google/android/gms/cast/R.java: .aapt.deps ;
|
||||
generated/com/google/android/gms/gcm/R.java: .aapt.deps ;
|
||||
|
||||
gecko.ap_: .aapt.deps ;
|
||||
R.txt: .aapt.deps ;
|
||||
|
@ -300,16 +300,13 @@ public class BrowserContract {
|
||||
public static final String POSITION = "position";
|
||||
}
|
||||
|
||||
public static final class Clients {
|
||||
public static final class Clients implements CommonColumns {
|
||||
private Clients() {}
|
||||
public static final Uri CONTENT_RECENCY_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "clients_recency");
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(TABS_AUTHORITY_URI, "clients");
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/client";
|
||||
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/client";
|
||||
|
||||
// Implicit rowid in SQL table.
|
||||
public static final String ROWID = "rowid";
|
||||
|
||||
// Client-provided name string. Could conceivably be null.
|
||||
public static final String NAME = "name";
|
||||
|
||||
|
@ -39,7 +39,7 @@ import android.util.Log;
|
||||
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final String LOGTAG = "GeckoBrowserDBHelper";
|
||||
|
||||
public static final int DATABASE_VERSION = 24;
|
||||
public static final int DATABASE_VERSION = 25;
|
||||
public static final String DATABASE_NAME = "browser.db";
|
||||
|
||||
final protected Context mContext;
|
||||
@ -197,12 +197,13 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
" ON " + TABLE_CLIENTS + "(" + BrowserContract.Clients.GUID + ")");
|
||||
}
|
||||
|
||||
private void createTabsTable(SQLiteDatabase db) {
|
||||
private boolean didCreateTabsTable = false;
|
||||
private void createTabsTable(SQLiteDatabase db, final String tableName) {
|
||||
debug("Creating tabs.db: " + db.getPath());
|
||||
debug("Creating " + TABLE_TABS + " table");
|
||||
debug("Creating " + tableName + " table");
|
||||
|
||||
// Table for each tab on any client.
|
||||
db.execSQL("CREATE TABLE " + TABLE_TABS + "(" +
|
||||
db.execSQL("CREATE TABLE " + tableName + "(" +
|
||||
BrowserContract.Tabs._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||
BrowserContract.Tabs.CLIENT_GUID + " TEXT," +
|
||||
BrowserContract.Tabs.TITLE + " TEXT," +
|
||||
@ -210,14 +211,18 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
BrowserContract.Tabs.HISTORY + " TEXT," +
|
||||
BrowserContract.Tabs.FAVICON + " TEXT," +
|
||||
BrowserContract.Tabs.LAST_USED + " INTEGER," +
|
||||
BrowserContract.Tabs.POSITION + " INTEGER" +
|
||||
BrowserContract.Tabs.POSITION + " INTEGER, " +
|
||||
"FOREIGN KEY (" + BrowserContract.Tabs.CLIENT_GUID + ") REFERENCES " +
|
||||
TABLE_CLIENTS + "(" + BrowserContract.Clients.GUID + ") ON DELETE CASCADE" +
|
||||
");");
|
||||
}
|
||||
|
||||
private void createTabsTableIndices(SQLiteDatabase db, final String tableName) {
|
||||
// Indices on CLIENT_GUID and POSITION.
|
||||
db.execSQL("CREATE INDEX " + TabsProvider.INDEX_TABS_GUID +
|
||||
" ON " + TABLE_TABS + "(" + BrowserContract.Tabs.CLIENT_GUID + ")");
|
||||
" ON " + tableName + "(" + BrowserContract.Tabs.CLIENT_GUID + ")");
|
||||
db.execSQL("CREATE INDEX " + TabsProvider.INDEX_TABS_POSITION +
|
||||
" ON " + TABLE_TABS + "(" + BrowserContract.Tabs.POSITION + ")");
|
||||
" ON " + tableName + "(" + BrowserContract.Tabs.POSITION + ")");
|
||||
}
|
||||
|
||||
// Insert a client row for our local Fennec client.
|
||||
@ -341,9 +346,12 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
createHistoryTable(db);
|
||||
createFaviconsTable(db);
|
||||
createThumbnailsTable(db);
|
||||
createTabsTable(db);
|
||||
createClientsTable(db);
|
||||
createLocalClient(db);
|
||||
createTabsTable(db, TABLE_TABS);
|
||||
didCreateTabsTable = true;
|
||||
createTabsTableIndices(db, TABLE_TABS);
|
||||
|
||||
|
||||
createBookmarksWithFaviconsView(db);
|
||||
createHistoryWithFaviconsView(db);
|
||||
@ -366,8 +374,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
* @param destinationDB The destination database.
|
||||
*/
|
||||
public void copyTabsDB(File tabsDBFile, SQLiteDatabase destinationDB) {
|
||||
createTabsTable(destinationDB);
|
||||
createClientsTable(destinationDB);
|
||||
createTabsTable(destinationDB, TABLE_TABS);
|
||||
didCreateTabsTable = true;
|
||||
createTabsTableIndices(destinationDB, TABLE_TABS);
|
||||
|
||||
SQLiteDatabase oldTabsDB = null;
|
||||
try {
|
||||
@ -987,6 +997,41 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom24to25(SQLiteDatabase db) {
|
||||
if (didCreateTabsTable) {
|
||||
debug("No need to rev tabs schema; foreign key constraint exists.");
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Rewriting tabs table.");
|
||||
createTabsTable(db, "tmp_tabs");
|
||||
|
||||
// Remove indexes. We don't need them now, and we'll be throwing away the table.
|
||||
db.execSQL("DROP INDEX IF EXISTS " + TabsProvider.INDEX_TABS_GUID);
|
||||
db.execSQL("DROP INDEX IF EXISTS " + TabsProvider.INDEX_TABS_POSITION);
|
||||
|
||||
db.execSQL("INSERT INTO tmp_tabs (" +
|
||||
// Here are the columns we can preserve.
|
||||
BrowserContract.Tabs._ID + ", " +
|
||||
BrowserContract.Tabs.CLIENT_GUID + ", " +
|
||||
BrowserContract.Tabs.TITLE + ", " +
|
||||
BrowserContract.Tabs.URL + ", " +
|
||||
BrowserContract.Tabs.HISTORY + ", " +
|
||||
BrowserContract.Tabs.FAVICON + ", " +
|
||||
BrowserContract.Tabs.LAST_USED + ", " +
|
||||
BrowserContract.Tabs.POSITION +
|
||||
") " +
|
||||
"SELECT " +
|
||||
"_id, client_guid, title, url, history, favicon, last_used, position" +
|
||||
" FROM " + TABLE_TABS);
|
||||
|
||||
// Now switch these tables over and recreate the indices.
|
||||
db.execSQL("DROP TABLE " + TABLE_TABS);
|
||||
db.execSQL("ALTER TABLE tmp_tabs RENAME TO " + TABLE_TABS);
|
||||
createTabsTableIndices(db, TABLE_TABS);
|
||||
didCreateTabsTable =true;
|
||||
}
|
||||
|
||||
private void createV19CombinedView(SQLiteDatabase db) {
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
|
||||
@ -1062,6 +1107,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
case 24:
|
||||
upgradeDatabaseFrom23to24(db);
|
||||
break;
|
||||
|
||||
case 25:
|
||||
upgradeDatabaseFrom24to25(db);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,20 @@ public class LocalTabsAccessor implements TabsAccessor {
|
||||
clientsRecencyUriWithProfile = DBUtils.appendProfileWithDefault(profileName, BrowserContract.Clients.CONTENT_RECENCY_URI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemoteClientCount(final Context context) {
|
||||
final Cursor remoteClientsCursor = getRemoteClientsByRecencyCursor(context);
|
||||
if (remoteClientsCursor == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return remoteClientsCursor.getCount();
|
||||
} finally {
|
||||
remoteClientsCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a List of just RemoteClients from a cursor.
|
||||
* The supplied cursor should be grouped by guid and sorted by most recently used.
|
||||
|
@ -117,6 +117,11 @@ class StubTabsAccessor implements TabsAccessor {
|
||||
public StubTabsAccessor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemoteClientCount(Context context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RemoteClient> getClientsWithoutTabsByRecencyFromCursor(Cursor cursor) {
|
||||
return new ArrayList<>();
|
||||
|
@ -17,6 +17,7 @@ public interface TabsAccessor {
|
||||
public void onQueryTabsComplete(List<RemoteClient> clients);
|
||||
}
|
||||
|
||||
public int getRemoteClientCount(Context context);
|
||||
public Cursor getRemoteClientsByRecencyCursor(Context context);
|
||||
public Cursor getRemoteTabsCursor(Context context);
|
||||
public Cursor getRemoteTabsCursor(Context context, int limit);
|
||||
|
@ -162,14 +162,13 @@ public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
switch (match) {
|
||||
case CLIENTS_ID:
|
||||
trace("Delete on CLIENTS_ID: " + uri);
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients.ROWID));
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients._ID));
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||
// fall through
|
||||
case CLIENTS:
|
||||
trace("Delete on CLIENTS: " + uri);
|
||||
// Delete from both TABLE_TABS and TABLE_CLIENTS.
|
||||
deleteValues(uri, selection, selectionArgs, TABLE_TABS);
|
||||
deleted = deleteValues(uri, selection, selectionArgs, TABLE_CLIENTS);
|
||||
break;
|
||||
|
||||
@ -236,7 +235,7 @@ public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
switch (match) {
|
||||
case CLIENTS_ID:
|
||||
trace("Update on CLIENTS_ID: " + uri);
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients.ROWID));
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients._ID));
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||
// fall through
|
||||
@ -297,7 +296,7 @@ public class TabsProvider extends SharedBrowserDatabaseProvider {
|
||||
|
||||
case CLIENTS_ID:
|
||||
trace("Query is on CLIENTS_ID: " + uri);
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients.ROWID));
|
||||
selection = DBUtils.concatenateWhere(selection, selectColumn(TABLE_CLIENTS, Clients._ID));
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||
// fall through
|
||||
|
@ -145,6 +145,12 @@
|
||||
are found. -->
|
||||
<!ENTITY overlay_no_synced_devices "No Firefox Account connected devices found">
|
||||
|
||||
<!-- Localization note (menu_no_synced_devices): Used in a toast when the user
|
||||
clicks on the button to send a tab to another device and there are no
|
||||
other devices present. This label should briefly inform the user that they
|
||||
need another connected device in order to use the feature. -->
|
||||
<!ENTITY menu_no_synced_devices "Send this tab to another connected device">
|
||||
|
||||
<!ENTITY pref_category_search3 "Search">
|
||||
<!ENTITY pref_category_search_summary "Customize your search providers">
|
||||
<!ENTITY pref_category_display "Display">
|
||||
|
@ -690,6 +690,28 @@ if CONFIG['MOZ_NATIVE_DEVICES']:
|
||||
ANDROID_EXTRA_RES_DIRS += ['%' + CONFIG['ANDROID_PLAY_SERVICES_CAST_AAR_RES']]
|
||||
resjar.generated_sources += ['com/google/android/gms/cast/R.java']
|
||||
|
||||
if CONFIG['MOZ_ANDROID_GCM']:
|
||||
gbjar.extra_jars += [
|
||||
CONFIG['ANDROID_PLAY_SERVICES_BASE_AAR_LIB'],
|
||||
CONFIG['ANDROID_PLAY_SERVICES_BASEMENT_AAR_LIB'],
|
||||
CONFIG['ANDROID_PLAY_SERVICES_GCM_AAR_LIB'],
|
||||
]
|
||||
|
||||
if CONFIG['ANDROID_PLAY_SERVICES_BASE_AAR']:
|
||||
ANDROID_EXTRA_PACKAGES += ['com.google.android.gms']
|
||||
ANDROID_EXTRA_RES_DIRS += ['%' + CONFIG['ANDROID_PLAY_SERVICES_BASE_AAR_RES']]
|
||||
resjar.generated_sources += ['com/google/android/gms/R.java']
|
||||
|
||||
if CONFIG['ANDROID_PLAY_SERVICES_BASEMENT_AAR']:
|
||||
ANDROID_EXTRA_PACKAGES += ['com.google.android.gms']
|
||||
ANDROID_EXTRA_RES_DIRS += ['%' + CONFIG['ANDROID_PLAY_SERVICES_BASEMENT_AAR_RES']]
|
||||
resjar.generated_sources += ['com/google/android/gms/R.java']
|
||||
|
||||
if CONFIG['ANDROID_PLAY_SERVICES_GCM_AAR']:
|
||||
ANDROID_EXTRA_PACKAGES += ['com.google.android.gms.gcm']
|
||||
ANDROID_EXTRA_RES_DIRS += ['%' + CONFIG['ANDROID_PLAY_SERVICES_GCM_AAR_RES']]
|
||||
resjar.generated_sources += ['com/google/android/gms/gcm/R.java']
|
||||
|
||||
gbjar.extra_jars += [CONFIG['ANDROID_APPCOMPAT_V7_AAR_LIB']]
|
||||
gbjar.extra_jars += [CONFIG['ANDROID_DESIGN_AAR_LIB']]
|
||||
gbjar.extra_jars += [CONFIG['ANDROID_RECYCLERVIEW_V7_AAR_LIB']]
|
||||
@ -835,11 +857,12 @@ ANDROID_ASSETS_DIRS += [
|
||||
for var in ('MOZ_ANDROID_ANR_REPORTER', 'MOZ_LINKER_EXTRACT', 'MOZ_DEBUG',
|
||||
'MOZ_ANDROID_SEARCH_ACTIVITY', 'MOZ_NATIVE_DEVICES', 'MOZ_ANDROID_MLS_STUMBLER',
|
||||
'MOZ_ANDROID_SHARE_OVERLAY', 'MOZ_ANDROID_DOWNLOADS_INTEGRATION', 'MOZ_INSTALL_TRACKING',
|
||||
'MOZ_ANDROID_GCM',
|
||||
'MOZ_ANDROID_TAB_QUEUE', 'MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = 1
|
||||
|
||||
for var in ('MOZ_UPDATER', 'MOZ_PKG_SPECIAL'):
|
||||
for var in ('MOZ_UPDATER', 'MOZ_PKG_SPECIAL', 'MOZ_ANDROID_GCM_SENDERID'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
|
@ -136,6 +136,7 @@
|
||||
<string name="overlay_share_no_url">&overlay_share_no_url;</string>
|
||||
<string name="overlay_share_select_device">&overlay_share_select_device;</string>
|
||||
<string name="overlay_no_synced_devices">&overlay_no_synced_devices;</string>
|
||||
<string name="menu_no_synced_devices">&menu_no_synced_devices;</string>
|
||||
|
||||
<string name="settings">&settings;</string>
|
||||
<string name="settings_title">&settings_title;</string>
|
||||
|
@ -355,32 +355,28 @@ public class FennecTabsRepository extends Repository {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all non-local clients and remote tabs.
|
||||
*
|
||||
* This function doesn't delete non-local clients due to bug in TabsProvider. Refer Bug 1025128.
|
||||
*
|
||||
* Upon remote tabs deletion, the clients without tabs are not shown in UI.
|
||||
* Deletes all non-local clients and their associated remote tabs.
|
||||
*/
|
||||
public static void deleteNonLocalClientsAndTabs(Context context) {
|
||||
final String nonLocalTabsSelection = BrowserContract.Tabs.CLIENT_GUID + " IS NOT NULL";
|
||||
final String nonLocalClientSelection = BrowserContract.Clients.GUID + " IS NOT NULL";
|
||||
|
||||
ContentProviderClient tabsProvider = context.getContentResolver()
|
||||
.acquireContentProviderClient(BrowserContractHelpers.TABS_CONTENT_URI);
|
||||
if (tabsProvider == null) {
|
||||
Logger.warn(LOG_TAG, "Unable to create tabsProvider!");
|
||||
ContentProviderClient clientsProvider = context.getContentResolver()
|
||||
.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
|
||||
if (clientsProvider == null) {
|
||||
Logger.warn(LOG_TAG, "Unable to create clientsProvider!");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Logger.info(LOG_TAG, "Clearing all non-local tabs for default profile.");
|
||||
tabsProvider.delete(BrowserContractHelpers.TABS_CONTENT_URI, nonLocalTabsSelection, null);
|
||||
Logger.info(LOG_TAG, "Clearing all non-local clients and their associated remote tabs for default profile.");
|
||||
clientsProvider.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, nonLocalClientSelection, null);
|
||||
} catch (RemoteException e) {
|
||||
Logger.warn(LOG_TAG, "Error while deleting", e);
|
||||
} finally {
|
||||
try {
|
||||
tabsProvider.release();
|
||||
clientsProvider.release();
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception releasing tabsProvider!", e);
|
||||
Logger.warn(LOG_TAG, "Got exception releasing clientsProvider!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,6 +102,11 @@ MOZ_ANDROID_TAB_QUEUE=1
|
||||
# Use the low-memory GC tuning.
|
||||
export JS_GC_SMALL_CHUNK_SIZE=1
|
||||
|
||||
# Enable GCM registration on Nightly builds only.
|
||||
if test "$NIGHTLY_BUILD"; then
|
||||
MOZ_ANDROID_GCM=1
|
||||
fi
|
||||
|
||||
# Enable Firefox Account avatars.
|
||||
MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES=1
|
||||
|
||||
|
@ -128,6 +128,9 @@ spoon {
|
||||
if (gradle.startParameter.taskNames.contains('runBrowserTests')) {
|
||||
spoonPackageName = 'org.mozilla.tests.browser.junit3'
|
||||
}
|
||||
if (gradle.startParameter.taskNames.contains('runBackgroundTests')) {
|
||||
spoonPackageName = 'org.mozilla.gecko.background'
|
||||
}
|
||||
if (project.hasProperty('spoonPackageName')) {
|
||||
// Command line overrides everything.
|
||||
spoonPackageName = project.spoonPackageName
|
||||
@ -147,4 +150,7 @@ afterEvaluate {
|
||||
task runBrowserTests {
|
||||
dependsOn tasks["spoonDebugAndroidTest"]
|
||||
}
|
||||
task runBackgroundTests {
|
||||
dependsOn tasks["spoonDebugAndroidTest"]
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,12 @@ dependencies {
|
||||
compile 'com.google.android.gms:play-services-cast:8.1.0'
|
||||
}
|
||||
|
||||
if (mozconfig.substs.MOZ_ANDROID_GCM) {
|
||||
compile 'com.google.android.gms:play-services-basement:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-base:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-gcm:8.1.0'
|
||||
}
|
||||
|
||||
compile project(':thirdparty')
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
|
@ -117,7 +117,7 @@ class MachCommands(MachCommandBase):
|
||||
# Test code.
|
||||
srcdir('app/src/robocop_harness/org/mozilla/gecko', 'build/mobile/robocop')
|
||||
srcdir('app/src/robocop/org/mozilla/gecko/tests', 'mobile/android/tests/browser/robocop')
|
||||
srcdir('app/src/background/org/mozilla/gecko/background', 'mobile/android/tests/background/junit3/src')
|
||||
srcdir('app/src/background', 'mobile/android/tests/background/junit3/src')
|
||||
srcdir('app/src/browser', 'mobile/android/tests/browser/junit3/src')
|
||||
srcdir('app/src/javaaddons', 'mobile/android/tests/javaaddons/src')
|
||||
# Test libraries.
|
||||
|
@ -158,5 +158,17 @@ var Accounts = Object.freeze({
|
||||
return Messaging.sendRequestForResult({
|
||||
type: "Accounts:DeleteFirefoxAccount",
|
||||
});
|
||||
},
|
||||
|
||||
showSyncPreferences: function () {
|
||||
// Only show Sync preferences of an existing Android Account.
|
||||
return Accounts.getFirefoxAccount().then(account => {
|
||||
if (!account) {
|
||||
throw new Error("Can't show Sync preferences of non-existent Firefox Account!");
|
||||
}
|
||||
return Messaging.sendRequestForResult({
|
||||
type: "Accounts:ShowSyncPreferences"
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -30,6 +30,7 @@ const COMMAND_LOGIN = "fxaccounts:login";
|
||||
const COMMAND_CHANGE_PASSWORD = "fxaccounts:change_password";
|
||||
const COMMAND_DELETE_ACCOUNT = "fxaccounts:delete_account";
|
||||
const COMMAND_PROFILE_CHANGE = "profile:change";
|
||||
const COMMAND_SYNC_PREFERENCES = "fxaccounts:sync_preferences";
|
||||
|
||||
const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
|
||||
|
||||
@ -350,6 +351,13 @@ this.FxAccountsWebChannel.prototype = {
|
||||
});
|
||||
break;
|
||||
|
||||
case COMMAND_SYNC_PREFERENCES:
|
||||
Accounts.showSyncPreferences()
|
||||
.catch(e => {
|
||||
log.e(e.toString());
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
log.w("Ignoring unrecognized FxAccountsWebChannel command: " + JSON.stringify(command));
|
||||
break;
|
||||
|
@ -5,107 +5,107 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
background_junit3_sources = [
|
||||
'src/common/TestAndroidLogWriters.java',
|
||||
'src/common/TestBrowserContractHelpers.java',
|
||||
'src/common/TestDateUtils.java',
|
||||
'src/common/TestUtils.java',
|
||||
'src/common/TestWaitHelper.java',
|
||||
'src/db/AndroidBrowserRepositoryTestCase.java',
|
||||
'src/db/TestAndroidBrowserBookmarksRepository.java',
|
||||
'src/db/TestAndroidBrowserHistoryDataExtender.java',
|
||||
'src/db/TestAndroidBrowserHistoryRepository.java',
|
||||
'src/db/TestBookmarks.java',
|
||||
'src/db/TestCachedSQLiteOpenHelper.java',
|
||||
'src/db/TestClientsDatabase.java',
|
||||
'src/db/TestClientsDatabaseAccessor.java',
|
||||
'src/db/TestFennecTabsRepositorySession.java',
|
||||
'src/db/TestFennecTabsStorage.java',
|
||||
'src/db/TestFormHistoryRepositorySession.java',
|
||||
'src/db/TestPasswordsRepository.java',
|
||||
'src/fxa/authenticator/TestAccountPickler.java',
|
||||
'src/fxa/TestAccountLoader.java',
|
||||
'src/fxa/TestBrowserIDKeyPairGeneration.java',
|
||||
'src/fxa/TestFirefoxAccounts.java',
|
||||
'src/healthreport/MockDatabaseEnvironment.java',
|
||||
'src/healthreport/MockHealthReportDatabaseStorage.java',
|
||||
'src/healthreport/MockHealthReportSQLiteOpenHelper.java',
|
||||
'src/healthreport/MockProfileInformationCache.java',
|
||||
'src/healthreport/prune/TestHealthReportPruneService.java',
|
||||
'src/healthreport/prune/TestPrunePolicyDatabaseStorage.java',
|
||||
'src/healthreport/TestEnvironmentBuilder.java',
|
||||
'src/healthreport/TestEnvironmentV1HashAppender.java',
|
||||
'src/healthreport/TestHealthReportBroadcastService.java',
|
||||
'src/healthreport/TestHealthReportDatabaseStorage.java',
|
||||
'src/healthreport/TestHealthReportGenerator.java',
|
||||
'src/healthreport/TestHealthReportProvider.java',
|
||||
'src/healthreport/TestHealthReportSQLiteOpenHelper.java',
|
||||
'src/healthreport/TestProfileInformationCache.java',
|
||||
'src/healthreport/upload/TestAndroidSubmissionClient.java',
|
||||
'src/healthreport/upload/TestHealthReportUploadService.java',
|
||||
'src/helpers/AndroidSyncTestCase.java',
|
||||
'src/helpers/BackgroundServiceTestCase.java',
|
||||
'src/helpers/DBHelpers.java',
|
||||
'src/helpers/DBProviderTestCase.java',
|
||||
'src/helpers/FakeProfileTestCase.java',
|
||||
'src/nativecode/test/TestNativeCrypto.java',
|
||||
'src/sync/AndroidSyncTestCaseWithAccounts.java',
|
||||
'src/sync/helpers/BookmarkHelpers.java',
|
||||
'src/sync/helpers/DefaultBeginDelegate.java',
|
||||
'src/sync/helpers/DefaultCleanDelegate.java',
|
||||
'src/sync/helpers/DefaultDelegate.java',
|
||||
'src/sync/helpers/DefaultFetchDelegate.java',
|
||||
'src/sync/helpers/DefaultFinishDelegate.java',
|
||||
'src/sync/helpers/DefaultGuidsSinceDelegate.java',
|
||||
'src/sync/helpers/DefaultSessionCreationDelegate.java',
|
||||
'src/sync/helpers/DefaultStoreDelegate.java',
|
||||
'src/sync/helpers/ExpectBeginDelegate.java',
|
||||
'src/sync/helpers/ExpectBeginFailDelegate.java',
|
||||
'src/sync/helpers/ExpectFetchDelegate.java',
|
||||
'src/sync/helpers/ExpectFetchSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectFinishDelegate.java',
|
||||
'src/sync/helpers/ExpectFinishFailDelegate.java',
|
||||
'src/sync/helpers/ExpectGuidsSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectInvalidRequestFetchDelegate.java',
|
||||
'src/sync/helpers/ExpectInvalidTypeStoreDelegate.java',
|
||||
'src/sync/helpers/ExpectManyStoredDelegate.java',
|
||||
'src/sync/helpers/ExpectNoGUIDsSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectNoStoreDelegate.java',
|
||||
'src/sync/helpers/ExpectStoreCompletedDelegate.java',
|
||||
'src/sync/helpers/ExpectStoredDelegate.java',
|
||||
'src/sync/helpers/HistoryHelpers.java',
|
||||
'src/sync/helpers/PasswordHelpers.java',
|
||||
'src/sync/helpers/SessionTestHelper.java',
|
||||
'src/sync/helpers/SimpleSuccessBeginDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessCreationDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessFetchDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessFinishDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessStoreDelegate.java',
|
||||
'src/sync/TestAccountPickler.java',
|
||||
'src/sync/TestClientsStage.java',
|
||||
'src/sync/TestConfigurationMigrator.java',
|
||||
'src/sync/TestResetting.java',
|
||||
'src/sync/TestSendTabData.java',
|
||||
'src/sync/TestStoreTracking.java',
|
||||
'src/sync/TestSyncAccounts.java',
|
||||
'src/sync/TestSyncAuthenticatorService.java',
|
||||
'src/sync/TestSyncConfiguration.java',
|
||||
'src/sync/TestTabsRecord.java',
|
||||
'src/sync/TestUpgradeRequired.java',
|
||||
'src/sync/TestWebURLFinder.java',
|
||||
'src/telemetry/TestTelemetryRecorder.java',
|
||||
'src/testhelpers/BaseMockServerSyncStage.java',
|
||||
'src/testhelpers/CommandHelpers.java',
|
||||
'src/testhelpers/DefaultGlobalSessionCallback.java',
|
||||
'src/testhelpers/JPakeNumGeneratorFixed.java',
|
||||
'src/testhelpers/MockAbstractNonRepositorySyncStage.java',
|
||||
'src/testhelpers/MockClientsDatabaseAccessor.java',
|
||||
'src/testhelpers/MockClientsDataDelegate.java',
|
||||
'src/testhelpers/MockGlobalSession.java',
|
||||
'src/testhelpers/MockPrefsGlobalSession.java',
|
||||
'src/testhelpers/MockRecord.java',
|
||||
'src/testhelpers/MockServerSyncStage.java',
|
||||
'src/testhelpers/MockSharedPreferences.java',
|
||||
'src/testhelpers/StubDelegate.java',
|
||||
'src/testhelpers/WaitHelper.java',
|
||||
'src/testhelpers/WBORepository.java',
|
||||
'src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java',
|
||||
'src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java',
|
||||
'src/org/mozilla/gecko/background/common/TestDateUtils.java',
|
||||
'src/org/mozilla/gecko/background/common/TestUtils.java',
|
||||
'src/org/mozilla/gecko/background/common/TestWaitHelper.java',
|
||||
'src/org/mozilla/gecko/background/db/AndroidBrowserRepositoryTestCase.java',
|
||||
'src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java',
|
||||
'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java',
|
||||
'src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java',
|
||||
'src/org/mozilla/gecko/background/db/TestBookmarks.java',
|
||||
'src/org/mozilla/gecko/background/db/TestCachedSQLiteOpenHelper.java',
|
||||
'src/org/mozilla/gecko/background/db/TestClientsDatabase.java',
|
||||
'src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java',
|
||||
'src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java',
|
||||
'src/org/mozilla/gecko/background/db/TestFennecTabsStorage.java',
|
||||
'src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java',
|
||||
'src/org/mozilla/gecko/background/db/TestPasswordsRepository.java',
|
||||
'src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java',
|
||||
'src/org/mozilla/gecko/background/fxa/TestAccountLoader.java',
|
||||
'src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java',
|
||||
'src/org/mozilla/gecko/background/fxa/TestFirefoxAccounts.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/MockDatabaseEnvironment.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/MockHealthReportDatabaseStorage.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/MockHealthReportSQLiteOpenHelper.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/MockProfileInformationCache.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/prune/TestHealthReportPruneService.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/prune/TestPrunePolicyDatabaseStorage.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestEnvironmentBuilder.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestEnvironmentV1HashAppender.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestHealthReportBroadcastService.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestHealthReportDatabaseStorage.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestHealthReportGenerator.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestHealthReportProvider.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestHealthReportSQLiteOpenHelper.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/TestProfileInformationCache.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/upload/TestAndroidSubmissionClient.java',
|
||||
'src/org/mozilla/gecko/background/healthreport/upload/TestHealthReportUploadService.java',
|
||||
'src/org/mozilla/gecko/background/helpers/AndroidSyncTestCase.java',
|
||||
'src/org/mozilla/gecko/background/helpers/BackgroundServiceTestCase.java',
|
||||
'src/org/mozilla/gecko/background/helpers/DBHelpers.java',
|
||||
'src/org/mozilla/gecko/background/helpers/DBProviderTestCase.java',
|
||||
'src/org/mozilla/gecko/background/helpers/FakeProfileTestCase.java',
|
||||
'src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java',
|
||||
'src/org/mozilla/gecko/background/sync/AndroidSyncTestCaseWithAccounts.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/BookmarkHelpers.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultBeginDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultCleanDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultFetchDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultFinishDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultGuidsSinceDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultSessionCreationDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/DefaultStoreDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectBeginFailDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectFetchSinceDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectFinishFailDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectGuidsSinceDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidRequestFetchDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectInvalidTypeStoreDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectManyStoredDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectNoGUIDsSinceDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectNoStoreDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectStoreCompletedDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/ExpectStoredDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/HistoryHelpers.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/PasswordHelpers.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestAccountPickler.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestClientsStage.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestConfigurationMigrator.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestResetting.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestSendTabData.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestStoreTracking.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestSyncAccounts.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestSyncAuthenticatorService.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestTabsRecord.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestUpgradeRequired.java',
|
||||
'src/org/mozilla/gecko/background/sync/TestWebURLFinder.java',
|
||||
'src/org/mozilla/gecko/background/telemetry/TestTelemetryRecorder.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/JPakeNumGeneratorFixed.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockRecord.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/StubDelegate.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/WaitHelper.java',
|
||||
'src/org/mozilla/gecko/background/testhelpers/WBORepository.java',
|
||||
]
|
||||
|
@ -1,47 +1,47 @@
|
||||
[DEFAULT]
|
||||
subsuite = background
|
||||
|
||||
[src/common/TestAndroidLogWriters.java]
|
||||
[src/common/TestBrowserContractHelpers.java]
|
||||
[src/common/TestDateUtils.java]
|
||||
[src/common/TestUtils.java]
|
||||
[src/common/TestWaitHelper.java]
|
||||
[src/db/TestAndroidBrowserBookmarksRepository.java]
|
||||
[src/db/TestAndroidBrowserHistoryDataExtender.java]
|
||||
[src/db/TestAndroidBrowserHistoryRepository.java]
|
||||
[src/db/TestBookmarks.java]
|
||||
[src/db/TestCachedSQLiteOpenHelper.java]
|
||||
[src/db/TestClientsDatabase.java]
|
||||
[src/db/TestClientsDatabaseAccessor.java]
|
||||
[src/db/TestFennecTabsRepositorySession.java]
|
||||
[src/db/TestFennecTabsStorage.java]
|
||||
[src/db/TestFormHistoryRepositorySession.java]
|
||||
[src/db/TestPasswordsRepository.java]
|
||||
[src/fxa/TestBrowserIDKeyPairGeneration.java]
|
||||
[src/fxa/authenticator/TestAccountPickler.java]
|
||||
[src/healthreport/TestEnvironmentBuilder.java]
|
||||
[src/healthreport/TestEnvironmentV1HashAppender.java]
|
||||
[src/healthreport/TestHealthReportBroadcastService.java]
|
||||
[src/healthreport/TestHealthReportDatabaseStorage.java]
|
||||
[src/healthreport/TestHealthReportGenerator.java]
|
||||
[src/healthreport/TestHealthReportProvider.java]
|
||||
[src/healthreport/TestHealthReportSQLiteOpenHelper.java]
|
||||
[src/healthreport/TestProfileInformationCache.java]
|
||||
[src/healthreport/prune/TestHealthReportPruneService.java]
|
||||
[src/healthreport/prune/TestPrunePolicyDatabaseStorage.java]
|
||||
[src/healthreport/upload/TestAndroidSubmissionClient.java]
|
||||
[src/healthreport/upload/TestHealthReportUploadService.java]
|
||||
[src/nativecode/test/TestNativeCrypto.java]
|
||||
[src/sync/TestAccountPickler.java]
|
||||
[src/sync/TestClientsStage.java]
|
||||
[src/sync/TestConfigurationMigrator.java]
|
||||
[src/sync/TestResetting.java]
|
||||
[src/sync/TestSendTabData.java]
|
||||
[src/sync/TestStoreTracking.java]
|
||||
[src/sync/TestSyncAccounts.java]
|
||||
[src/sync/TestSyncAuthenticatorService.java]
|
||||
[src/sync/TestSyncConfiguration.java]
|
||||
[src/sync/TestTabsRecord.java]
|
||||
[src/sync/TestUpgradeRequired.java]
|
||||
[src/sync/TestWebURLFinder.java]
|
||||
[src/telemetry/TestTelemetryRecorder.java]
|
||||
[src/org/mozilla/gecko/background/common/TestAndroidLogWriters.java]
|
||||
[src/org/mozilla/gecko/background/common/TestBrowserContractHelpers.java]
|
||||
[src/org/mozilla/gecko/background/common/TestDateUtils.java]
|
||||
[src/org/mozilla/gecko/background/common/TestUtils.java]
|
||||
[src/org/mozilla/gecko/background/common/TestWaitHelper.java]
|
||||
[src/org/mozilla/gecko/background/db/TestAndroidBrowserBookmarksRepository.java]
|
||||
[src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryDataExtender.java]
|
||||
[src/org/mozilla/gecko/background/db/TestAndroidBrowserHistoryRepository.java]
|
||||
[src/org/mozilla/gecko/background/db/TestBookmarks.java]
|
||||
[src/org/mozilla/gecko/background/db/TestCachedSQLiteOpenHelper.java]
|
||||
[src/org/mozilla/gecko/background/db/TestClientsDatabase.java]
|
||||
[src/org/mozilla/gecko/background/db/TestClientsDatabaseAccessor.java]
|
||||
[src/org/mozilla/gecko/background/db/TestFennecTabsRepositorySession.java]
|
||||
[src/org/mozilla/gecko/background/db/TestFennecTabsStorage.java]
|
||||
[src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java]
|
||||
[src/org/mozilla/gecko/background/db/TestPasswordsRepository.java]
|
||||
[src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java]
|
||||
[src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestEnvironmentBuilder.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestEnvironmentV1HashAppender.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestHealthReportBroadcastService.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestHealthReportDatabaseStorage.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestHealthReportGenerator.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestHealthReportProvider.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestHealthReportSQLiteOpenHelper.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/TestProfileInformationCache.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/prune/TestHealthReportPruneService.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/prune/TestPrunePolicyDatabaseStorage.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/upload/TestAndroidSubmissionClient.java]
|
||||
[src/org/mozilla/gecko/background/healthreport/upload/TestHealthReportUploadService.java]
|
||||
[src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestAccountPickler.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestClientsStage.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestConfigurationMigrator.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestResetting.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestSendTabData.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestStoreTracking.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestSyncAccounts.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestSyncAuthenticatorService.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestTabsRecord.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestUpgradeRequired.java]
|
||||
[src/org/mozilla/gecko/background/sync/TestWebURLFinder.java]
|
||||
[src/org/mozilla/gecko/background/telemetry/TestTelemetryRecorder.java]
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user