зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c. a=merge
This commit is contained in:
Коммит
bc0492cc53
|
@ -347,6 +347,14 @@ function injectLoopAPI(targetWindow) {
|
|||
}
|
||||
},
|
||||
|
||||
logInToFxA: {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
value: function() {
|
||||
return MozLoopService.logInToFxA();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Copies passed string onto the system clipboard.
|
||||
*
|
||||
|
|
|
@ -780,6 +780,10 @@ this.MozLoopService = {
|
|||
* @return {Promise} that resolves when the FxA login flow is complete.
|
||||
*/
|
||||
logInToFxA: function() {
|
||||
if (gFxAOAuthTokenData) {
|
||||
return Promise.resolve(gFxAOAuthTokenData);
|
||||
}
|
||||
|
||||
return MozLoopServiceInternal.promiseFxAOAuthAuthorization().then(response => {
|
||||
return MozLoopServiceInternal.promiseFxAOAuthToken(response.code, response.state);
|
||||
}).then(tokenData => {
|
||||
|
|
|
@ -194,6 +194,9 @@ loop.conversation = (function(OT, mozL10n) {
|
|||
this.navigate("call/declineAndBlock", {trigger: true});
|
||||
}.bind(this));
|
||||
this._conversation.once("call:incoming", this.startCall, this);
|
||||
this._conversation.once("change:publishedStream", this._checkConnected, this);
|
||||
this._conversation.once("change:subscribedStream", this._checkConnected, this);
|
||||
|
||||
this._client.requestCallsInfo(loopVersion, function(err, sessionData) {
|
||||
if (err) {
|
||||
console.error("Failed to get the sessionData", err);
|
||||
|
@ -235,11 +238,24 @@ loop.conversation = (function(OT, mozL10n) {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the streams have been connected, and notifies the
|
||||
* websocket that the media is now connected.
|
||||
*/
|
||||
_checkConnected: function() {
|
||||
// Check we've had both local and remote streams connected before
|
||||
// sending the media up message.
|
||||
if (this._conversation.streamsConnected()) {
|
||||
this._websocket.mediaUp();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Accepts an incoming call.
|
||||
*/
|
||||
accept: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
this._websocket.accept();
|
||||
this._conversation.incoming();
|
||||
},
|
||||
|
||||
|
|
|
@ -194,6 +194,9 @@ loop.conversation = (function(OT, mozL10n) {
|
|||
this.navigate("call/declineAndBlock", {trigger: true});
|
||||
}.bind(this));
|
||||
this._conversation.once("call:incoming", this.startCall, this);
|
||||
this._conversation.once("change:publishedStream", this._checkConnected, this);
|
||||
this._conversation.once("change:subscribedStream", this._checkConnected, this);
|
||||
|
||||
this._client.requestCallsInfo(loopVersion, function(err, sessionData) {
|
||||
if (err) {
|
||||
console.error("Failed to get the sessionData", err);
|
||||
|
@ -235,11 +238,24 @@ loop.conversation = (function(OT, mozL10n) {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the streams have been connected, and notifies the
|
||||
* websocket that the media is now connected.
|
||||
*/
|
||||
_checkConnected: function() {
|
||||
// Check we've had both local and remote streams connected before
|
||||
// sending the media up message.
|
||||
if (this._conversation.streamsConnected()) {
|
||||
this._websocket.mediaUp();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Accepts an incoming call.
|
||||
*/
|
||||
accept: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
this._websocket.accept();
|
||||
this._conversation.incoming();
|
||||
},
|
||||
|
||||
|
|
|
@ -77,24 +77,22 @@ loop.panel = (function(_, mozL10n) {
|
|||
__("display_name_available_status");
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "footer"},
|
||||
React.DOM.div({className: "do-not-disturb"},
|
||||
React.DOM.div({className: "dnd-status", onClick: this.showDropdownMenu},
|
||||
React.DOM.span(null, availabilityText),
|
||||
React.DOM.i({className: availabilityStatus})
|
||||
React.DOM.div({className: "do-not-disturb"},
|
||||
React.DOM.p({className: "dnd-status", onClick: this.showDropdownMenu},
|
||||
React.DOM.span(null, availabilityText),
|
||||
React.DOM.i({className: availabilityStatus})
|
||||
),
|
||||
React.DOM.ul({className: availabilityDropdown,
|
||||
onMouseLeave: this.hideDropdownMenu},
|
||||
React.DOM.li({onClick: this.changeAvailability("available"),
|
||||
className: "dnd-menu-item dnd-make-available"},
|
||||
React.DOM.i({className: "status status-available"}),
|
||||
React.DOM.span(null, __("display_name_available_status"))
|
||||
),
|
||||
React.DOM.ul({className: availabilityDropdown,
|
||||
onMouseLeave: this.hideDropdownMenu},
|
||||
React.DOM.li({onClick: this.changeAvailability("available"),
|
||||
className: "dnd-menu-item dnd-make-available"},
|
||||
React.DOM.i({className: "status status-available"}),
|
||||
React.DOM.span(null, __("display_name_available_status"))
|
||||
),
|
||||
React.DOM.li({onClick: this.changeAvailability("do-not-disturb"),
|
||||
className: "dnd-menu-item dnd-make-unavailable"},
|
||||
React.DOM.i({className: "status status-dnd"}),
|
||||
React.DOM.span(null, __("display_name_dnd_status"))
|
||||
)
|
||||
React.DOM.li({onClick: this.changeAvailability("do-not-disturb"),
|
||||
className: "dnd-menu-item dnd-make-unavailable"},
|
||||
React.DOM.i({className: "status status-dnd"}),
|
||||
React.DOM.span(null, __("display_name_dnd_status"))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -272,6 +270,10 @@ loop.panel = (function(_, mozL10n) {
|
|||
callUrl: React.PropTypes.string
|
||||
},
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.div(null,
|
||||
|
@ -279,7 +281,12 @@ loop.panel = (function(_, mozL10n) {
|
|||
notifier: this.props.notifier,
|
||||
callUrl: this.props.callUrl}),
|
||||
ToSView(null),
|
||||
AvailabilityDropdown(null)
|
||||
React.DOM.div({className: "footer"},
|
||||
AvailabilityDropdown(null),
|
||||
React.DOM.a({className: "signin-link", href: "#", onClick: this.handleSignUpLinkClick},
|
||||
__("panel_footer_signin_or_signup_link")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -77,26 +77,24 @@ loop.panel = (function(_, mozL10n) {
|
|||
__("display_name_available_status");
|
||||
|
||||
return (
|
||||
<div className="footer">
|
||||
<div className="do-not-disturb">
|
||||
<div className="dnd-status" onClick={this.showDropdownMenu}>
|
||||
<span>{availabilityText}</span>
|
||||
<i className={availabilityStatus}></i>
|
||||
</div>
|
||||
<ul className={availabilityDropdown}
|
||||
onMouseLeave={this.hideDropdownMenu}>
|
||||
<li onClick={this.changeAvailability("available")}
|
||||
className="dnd-menu-item dnd-make-available">
|
||||
<i className="status status-available"></i>
|
||||
<span>{__("display_name_available_status")}</span>
|
||||
</li>
|
||||
<li onClick={this.changeAvailability("do-not-disturb")}
|
||||
className="dnd-menu-item dnd-make-unavailable">
|
||||
<i className="status status-dnd"></i>
|
||||
<span>{__("display_name_dnd_status")}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="do-not-disturb">
|
||||
<p className="dnd-status" onClick={this.showDropdownMenu}>
|
||||
<span>{availabilityText}</span>
|
||||
<i className={availabilityStatus}></i>
|
||||
</p>
|
||||
<ul className={availabilityDropdown}
|
||||
onMouseLeave={this.hideDropdownMenu}>
|
||||
<li onClick={this.changeAvailability("available")}
|
||||
className="dnd-menu-item dnd-make-available">
|
||||
<i className="status status-available"></i>
|
||||
<span>{__("display_name_available_status")}</span>
|
||||
</li>
|
||||
<li onClick={this.changeAvailability("do-not-disturb")}
|
||||
className="dnd-menu-item dnd-make-unavailable">
|
||||
<i className="status status-dnd"></i>
|
||||
<span>{__("display_name_dnd_status")}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -272,6 +270,10 @@ loop.panel = (function(_, mozL10n) {
|
|||
callUrl: React.PropTypes.string
|
||||
},
|
||||
|
||||
handleSignUpLinkClick: function() {
|
||||
navigator.mozLoop.logInToFxA();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
|
@ -279,7 +281,12 @@ loop.panel = (function(_, mozL10n) {
|
|||
notifier={this.props.notifier}
|
||||
callUrl={this.props.callUrl} />
|
||||
<ToSView />
|
||||
<AvailabilityDropdown />
|
||||
<div className="footer">
|
||||
<AvailabilityDropdown />
|
||||
<a className="signin-link" href="#" onClick={this.handleSignUpLinkClick}>
|
||||
{__("panel_footer_signin_or_signup_link")}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -138,6 +138,17 @@
|
|||
border: 1px solid #888;
|
||||
}
|
||||
|
||||
/* Sign in/up link */
|
||||
|
||||
.signin-link {
|
||||
display: none; /* XXX This should be removed as soon bugs 1047144 & 979845 land */
|
||||
line-height: 100%;
|
||||
font-size: .9em;
|
||||
text-decoration: none;
|
||||
color: #888;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* Terms of Service */
|
||||
|
||||
.terms-service {
|
||||
|
@ -157,14 +168,17 @@
|
|||
/* Footer */
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
align-content: stretch;
|
||||
align-items: flex-start;
|
||||
font-size: 1em;
|
||||
border-top: 1px solid #D1D1D1;
|
||||
background: #EAEAEA;
|
||||
color: #7F7F7F;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 14px;
|
||||
flex-direction: row;
|
||||
padding: 14px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,12 @@ loop.shared.models = (function() {
|
|||
// other peer ("audio" or "audio-video")
|
||||
selectedCallType: undefined, // The selected type for the call that was
|
||||
// initiated ("audio" or "audio-video")
|
||||
callToken: undefined // Incoming call token.
|
||||
callToken: undefined, // Incoming call token.
|
||||
// Used for blocking a call url
|
||||
subscribedStream: false, // Used to indicate that a stream has been
|
||||
// subscribed to
|
||||
publishedStream: false // Used to indicate that a stream has been
|
||||
// published
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -219,6 +223,39 @@ loop.shared.models = (function() {
|
|||
return undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Publishes a local stream.
|
||||
*
|
||||
* @param {Publisher} publisher The publisher object to publish
|
||||
* to the session.
|
||||
*/
|
||||
publish: function(publisher) {
|
||||
this.session.publish(publisher);
|
||||
this.set("publishedStream", true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Subscribes to a remote stream.
|
||||
*
|
||||
* @param {Stream} stream The remote stream to subscribe to.
|
||||
* @param {DOMElement} element The element to display the stream in.
|
||||
* @param {Object} config The display properties to set on the stream as
|
||||
* documented in:
|
||||
* https://tokbox.com/opentok/libraries/client/js/reference/Session.html#subscribe
|
||||
*/
|
||||
subscribe: function(stream, element, config) {
|
||||
this.session.subscribe(stream, element, config);
|
||||
this.set("subscribedStream", true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if a stream has been published and a stream has been
|
||||
* subscribed to.
|
||||
*/
|
||||
streamsConnected: function() {
|
||||
return this.get("publishedStream") && this.get("subscribedStream");
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a loop-server error, which has an optional `errno` property which
|
||||
* is server error identifier.
|
||||
|
|
|
@ -278,13 +278,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
*/
|
||||
_streamCreated: function(event) {
|
||||
var incoming = this.getDOMNode().querySelector(".remote");
|
||||
event.streams.forEach(function(stream) {
|
||||
if (stream.connection.connectionId !==
|
||||
this.props.model.session.connection.connectionId) {
|
||||
this.props.model.session.subscribe(stream, incoming,
|
||||
this.publisherConfig);
|
||||
}
|
||||
}, this);
|
||||
this.props.model.subscribe(event.stream, incoming, this.publisherConfig);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -321,7 +315,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
});
|
||||
}.bind(this));
|
||||
|
||||
this.props.model.session.publish(this.publisher);
|
||||
this.props.model.publish(this.publisher);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -278,13 +278,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
*/
|
||||
_streamCreated: function(event) {
|
||||
var incoming = this.getDOMNode().querySelector(".remote");
|
||||
event.streams.forEach(function(stream) {
|
||||
if (stream.connection.connectionId !==
|
||||
this.props.model.session.connection.connectionId) {
|
||||
this.props.model.session.subscribe(stream, incoming,
|
||||
this.publisherConfig);
|
||||
}
|
||||
}, this);
|
||||
this.props.model.subscribe(event.stream, incoming, this.publisherConfig);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -321,7 +315,7 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
});
|
||||
}.bind(this));
|
||||
|
||||
this.props.model.session.publish(this.publisher);
|
||||
this.props.model.publish(this.publisher);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -127,6 +127,27 @@ loop.CallConnectionWebSocket = (function() {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies the server that the user has accepted the call.
|
||||
*/
|
||||
accept: function() {
|
||||
this._send({
|
||||
messageType: "action",
|
||||
event: "accept"
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies the server that the outgoing media is up, and the
|
||||
* incoming media is being received.
|
||||
*/
|
||||
mediaUp: function() {
|
||||
this._send({
|
||||
messageType: "action",
|
||||
event: "media-up"
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends data on the websocket.
|
||||
*
|
||||
|
|
|
@ -410,6 +410,18 @@ loop.webapp = (function($, _, OT, webL10n) {
|
|||
this._websocket.on("progress", this._handleWebSocketProgress, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the streams have been connected, and notifies the
|
||||
* websocket that the media is now connected.
|
||||
*/
|
||||
_checkConnected: function() {
|
||||
// Check we've had both local and remote streams connected before
|
||||
// sending the media up message.
|
||||
if (this._conversation.streamsConnected()) {
|
||||
this._websocket.mediaUp();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to receive websocket progress and to determine how to handle
|
||||
* it if appropraite.
|
||||
|
@ -495,6 +507,8 @@ loop.webapp = (function($, _, OT, webL10n) {
|
|||
client: this._client
|
||||
});
|
||||
this._conversation.once("call:outgoing:setup", this.setupOutgoingCall, this);
|
||||
this._conversation.once("change:publishedStream", this._checkConnected, this);
|
||||
this._conversation.once("change:subscribedStream", this._checkConnected, this);
|
||||
this.loadReactComponent(startView);
|
||||
},
|
||||
|
||||
|
|
|
@ -410,6 +410,18 @@ loop.webapp = (function($, _, OT, webL10n) {
|
|||
this._websocket.on("progress", this._handleWebSocketProgress, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the streams have been connected, and notifies the
|
||||
* websocket that the media is now connected.
|
||||
*/
|
||||
_checkConnected: function() {
|
||||
// Check we've had both local and remote streams connected before
|
||||
// sending the media up message.
|
||||
if (this._conversation.streamsConnected()) {
|
||||
this._websocket.mediaUp();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to receive websocket progress and to determine how to handle
|
||||
* it if appropraite.
|
||||
|
@ -495,6 +507,8 @@ loop.webapp = (function($, _, OT, webL10n) {
|
|||
client: this._client
|
||||
});
|
||||
this._conversation.once("call:outgoing:setup", this.setupOutgoingCall, this);
|
||||
this._conversation.once("change:publishedStream", this._checkConnected, this);
|
||||
this._conversation.once("change:subscribedStream", this._checkConnected, this);
|
||||
this.loadReactComponent(startView);
|
||||
},
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ describe("loop.conversation", function() {
|
|||
},
|
||||
setLoopCharPref: sandbox.stub(),
|
||||
getLoopCharPref: sandbox.stub(),
|
||||
getLoopBoolPref: sandbox.stub(),
|
||||
startAlerting: function() {},
|
||||
stopAlerting: function() {},
|
||||
ensureRegistered: function() {},
|
||||
|
@ -311,14 +312,35 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
|
||||
describe("#accept", function() {
|
||||
beforeEach(function() {
|
||||
conversation.setIncomingSessionData({
|
||||
sessionId: "sessionId",
|
||||
sessionToken: "sessionToken",
|
||||
apiKey: "apiKey",
|
||||
callType: "callType",
|
||||
callId: "Hello",
|
||||
progressURL: "http://progress.example.com",
|
||||
websocketToken: 123
|
||||
});
|
||||
router._setupWebSocketAndCallView();
|
||||
|
||||
sandbox.stub(router._websocket, "accept");
|
||||
sandbox.stub(navigator.mozLoop, "stopAlerting");
|
||||
});
|
||||
|
||||
it("should initiate the conversation", function() {
|
||||
router.accept();
|
||||
|
||||
sinon.assert.calledOnce(conversation.incoming);
|
||||
});
|
||||
|
||||
it("should notify the websocket of the user acceptance", function() {
|
||||
router.accept();
|
||||
|
||||
sinon.assert.calledOnce(router._websocket.accept);
|
||||
});
|
||||
|
||||
it("should stop alerting", function() {
|
||||
sandbox.stub(navigator.mozLoop, "stopAlerting");
|
||||
router.accept();
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
|
||||
|
@ -531,6 +553,49 @@ describe("loop.conversation", function() {
|
|||
sinon.assert.calledOnce(router.navigate);
|
||||
sinon.assert.calledWith(router.navigate, "call/feedback");
|
||||
});
|
||||
|
||||
describe("Published and Subscribed Streams", function() {
|
||||
beforeEach(function() {
|
||||
router._websocket = {
|
||||
mediaUp: sinon.spy()
|
||||
};
|
||||
router.incoming("fakeVersion");
|
||||
});
|
||||
|
||||
describe("publishStream", function() {
|
||||
it("should not notify the websocket if only one stream is up",
|
||||
function() {
|
||||
conversation.set("publishedStream", true);
|
||||
|
||||
sinon.assert.notCalled(router._websocket.mediaUp);
|
||||
});
|
||||
|
||||
it("should notify the websocket that media is up if both streams" +
|
||||
"are connected", function() {
|
||||
conversation.set("subscribedStream", true);
|
||||
conversation.set("publishedStream", true);
|
||||
|
||||
sinon.assert.calledOnce(router._websocket.mediaUp);
|
||||
});
|
||||
});
|
||||
|
||||
describe("subscribedStream", function() {
|
||||
it("should not notify the websocket if only one stream is up",
|
||||
function() {
|
||||
conversation.set("subscribedStream", true);
|
||||
|
||||
sinon.assert.notCalled(router._websocket.mediaUp);
|
||||
});
|
||||
|
||||
it("should notify the websocket that media is up if both streams" +
|
||||
"are connected", function() {
|
||||
conversation.set("publishedStream", true);
|
||||
conversation.set("subscribedStream", true);
|
||||
|
||||
sinon.assert.calledOnce(router._websocket.mediaUp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -217,12 +217,23 @@ describe("loop.panel", function() {
|
|||
}));
|
||||
});
|
||||
|
||||
describe("FxA sign in/up link", function() {
|
||||
it("should trigger the FxA sign in/up process when clicking the link",
|
||||
function() {
|
||||
navigator.mozLoop.logInToFxA = sandbox.stub();
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
view.getDOMNode().querySelector(".signin-link"));
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.logInToFxA);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#render", function() {
|
||||
it("should render a ToSView", function() {
|
||||
TestUtils.findRenderedComponentWithType(view, loop.panel.ToSView);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("loop.panel.CallUrlResult", function() {
|
||||
|
|
|
@ -357,15 +357,14 @@ describe("loop.shared.views", function() {
|
|||
sinon.assert.calledOnce(fakeSDK.initPublisher);
|
||||
});
|
||||
|
||||
it("should publish remote streams on session:stream-created",
|
||||
it("should publish remote stream on session:stream-created",
|
||||
function() {
|
||||
var s1 = {connection: {connectionId: 42}};
|
||||
var s2 = {connection: {connectionId: 43}};
|
||||
|
||||
model.trigger("session:stream-created", {streams: [s1, s2]});
|
||||
model.trigger("session:stream-created", {stream: s1});
|
||||
|
||||
sinon.assert.calledOnce(fakeSession.subscribe);
|
||||
sinon.assert.calledWith(fakeSession.subscribe, s2);
|
||||
sinon.assert.calledWith(fakeSession.subscribe, s1);
|
||||
});
|
||||
|
||||
it("should unpublish local stream on session:ended", function() {
|
||||
|
|
|
@ -148,6 +148,34 @@ describe("loop.CallConnectionWebSocket", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#accept", function() {
|
||||
it("should send an accept message to the server", function() {
|
||||
callWebSocket.promiseConnect();
|
||||
|
||||
callWebSocket.accept();
|
||||
|
||||
sinon.assert.calledOnce(dummySocket.send);
|
||||
sinon.assert.calledWithExactly(dummySocket.send, JSON.stringify({
|
||||
messageType: "action",
|
||||
event: "accept"
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("#mediaUp", function() {
|
||||
it("should send a media-up message to the server", function() {
|
||||
callWebSocket.promiseConnect();
|
||||
|
||||
callWebSocket.mediaUp();
|
||||
|
||||
sinon.assert.calledOnce(dummySocket.send);
|
||||
sinon.assert.calledWithExactly(dummySocket.send, JSON.stringify({
|
||||
messageType: "action",
|
||||
event: "media-up"
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("Events", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(callWebSocket, "trigger");
|
||||
|
|
|
@ -415,6 +415,49 @@ describe("loop.webapp", function() {
|
|||
sinon.assert.calledWithMatch(router.navigate, "call/fakeToken");
|
||||
});
|
||||
|
||||
describe("Published and Subscribed Streams", function() {
|
||||
beforeEach(function() {
|
||||
router._websocket = {
|
||||
mediaUp: sinon.spy()
|
||||
};
|
||||
router.initiate();
|
||||
});
|
||||
|
||||
describe("publishStream", function() {
|
||||
it("should not notify the websocket if only one stream is up",
|
||||
function() {
|
||||
conversation.set("publishedStream", true);
|
||||
|
||||
sinon.assert.notCalled(router._websocket.mediaUp);
|
||||
});
|
||||
|
||||
it("should notify the websocket that media is up if both streams" +
|
||||
"are connected", function() {
|
||||
conversation.set("subscribedStream", true);
|
||||
conversation.set("publishedStream", true);
|
||||
|
||||
sinon.assert.calledOnce(router._websocket.mediaUp);
|
||||
});
|
||||
});
|
||||
|
||||
describe("subscribedStream", function() {
|
||||
it("should not notify the websocket if only one stream is up",
|
||||
function() {
|
||||
conversation.set("subscribedStream", true);
|
||||
|
||||
sinon.assert.notCalled(router._websocket.mediaUp);
|
||||
});
|
||||
|
||||
it("should notify the websocket that media is up if both streams" +
|
||||
"are connected", function() {
|
||||
conversation.set("publishedStream", true);
|
||||
conversation.set("subscribedStream", true);
|
||||
|
||||
sinon.assert.calledOnce(router._websocket.mediaUp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#setupOutgoingCall", function() {
|
||||
beforeEach(function() {
|
||||
router.initiate();
|
||||
|
|
|
@ -166,7 +166,9 @@ let CommandUtils = {
|
|||
command.state.onChange(target, onChange);
|
||||
onChange("", { target: target });
|
||||
document.defaultView.addEventListener("unload", () => {
|
||||
command.state.offChange(target, onChange);
|
||||
if (command.state.offChange) {
|
||||
command.state.offChange(target, onChange);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,3 +68,5 @@ share_email_body2=Please click this link to call me:\r\n\r\n{{callUrl}}
|
|||
share_button=Email
|
||||
copy_url_button=Copy
|
||||
copied_url_button=Copied!
|
||||
|
||||
panel_footer_signin_or_signup_link=Sign In or Sign Up
|
||||
|
|
|
@ -1792,6 +1792,21 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
}
|
||||
|
||||
@media (-moz-mac-yosemite-theme) {
|
||||
.searchbar-textbox,
|
||||
#urlbar {
|
||||
border-color: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 0 0 #aeaeae, 1px 2px 0 0 #d8d8d8;
|
||||
background-image: none;
|
||||
}
|
||||
.searchbar-textbox:-moz-window-inactive,
|
||||
#urlbar:-moz-window-inactive {
|
||||
box-shadow: none;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
}
|
||||
|
||||
#urlbar[focused="true"],
|
||||
.searchbar-textbox[focused="true"] {
|
||||
border-color: -moz-mac-focusring;
|
||||
|
|
|
@ -19,9 +19,9 @@ ifndef JAVA_BOOTCLASSPATH
|
|||
JAVA_BOOTCLASSPATH = $(ANDROID_SDK)/android.jar
|
||||
endif
|
||||
|
||||
# For Android, we default to 1.5
|
||||
# For Android, we default to 1.7
|
||||
ifndef JAVA_VERSION
|
||||
JAVA_VERSION = 1.5
|
||||
JAVA_VERSION = 1.7
|
||||
endif
|
||||
|
||||
JAVAC_FLAGS = \
|
||||
|
|
18
configure.in
18
configure.in
|
@ -5622,6 +5622,24 @@ if test -n "${JAVA_BIN_PATH}" -o \
|
|||
if test -z "$KEYTOOL" -o "$KEYTOOL" = ":"; then
|
||||
AC_MSG_ERROR([The program keytool was not found. Set \$JAVA_HOME to your Java SDK directory or use --with-java-bin-path={java-bin-dir}])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for minimum required javac version = 1.7])
|
||||
|
||||
dnl Javac spits out something like `javac 1.7.0`. This line cuts off the 'javac'
|
||||
_javac_version=$($JAVAC -version 2>&1 | cut -d ' ' -f 2)
|
||||
|
||||
dnl Here, we extract the major (1) and minor (7) version numbers from the
|
||||
dnl acquired version string.
|
||||
_javac_major_version=$(echo $_javac_version | cut -d '.' -f 1)
|
||||
_javac_minor_version=$(echo $_javac_version | cut -d '.' -f 2)
|
||||
|
||||
AC_MSG_RESULT([$_javac_version])
|
||||
|
||||
dnl Fail if we have a version other than 1.7.X
|
||||
if test "$_javac_major_version" -ne "1" -o \
|
||||
\( "$_javac_minor_version" -ne "7" \); then
|
||||
AC_MSG_ERROR([javac 1.7 is required.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
|
|
|
@ -138,6 +138,10 @@ struct Paths {
|
|||
* system.
|
||||
*/
|
||||
nsString macLocalApplicationsDir;
|
||||
/**
|
||||
* The user's trash directory.
|
||||
*/
|
||||
nsString macTrashDir;
|
||||
#endif // defined(XP_MACOSX)
|
||||
|
||||
Paths()
|
||||
|
@ -158,6 +162,7 @@ struct Paths {
|
|||
#if defined(XP_MACOSX)
|
||||
macUserLibDir.SetIsVoid(true);
|
||||
macLocalApplicationsDir.SetIsVoid(true);
|
||||
macTrashDir.SetIsVoid(true);
|
||||
#endif // defined(XP_MACOSX)
|
||||
}
|
||||
};
|
||||
|
@ -306,6 +311,7 @@ nsresult InitOSFileConstants()
|
|||
#if defined(XP_MACOSX)
|
||||
GetPathToSpecialDir(NS_MAC_USER_LIB_DIR, paths->macUserLibDir);
|
||||
GetPathToSpecialDir(NS_OSX_LOCAL_APPLICATIONS_DIR, paths->macLocalApplicationsDir);
|
||||
GetPathToSpecialDir(NS_MAC_TRASH_DIR, paths->macTrashDir);
|
||||
#endif // defined(XP_MACOSX)
|
||||
|
||||
gPaths = paths.forget();
|
||||
|
@ -980,6 +986,10 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
|
|||
if (!SetStringProperty(cx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetStringProperty(cx, objPath, "macTrashDir", gPaths->macTrashDir)) {
|
||||
return false;
|
||||
}
|
||||
#endif // defined(XP_MACOSX)
|
||||
|
||||
// sqlite3 is linked from different places depending on the platform
|
||||
|
|
|
@ -494,6 +494,10 @@ Tester.prototype = {
|
|||
promise = ContentSearch.destroy();
|
||||
}
|
||||
|
||||
// Simulate memory pressure so that we're forced to free more resources
|
||||
// and thus get rid of more false leaks like already terminated workers.
|
||||
Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
|
||||
|
||||
// Schedule GC and CC runs before finishing in order to detect
|
||||
// DOM windows leaked by our tests or the tested code. Note that we
|
||||
// use a shrinking GC so that the JS engine will discard JIT code and
|
||||
|
|
|
@ -73,6 +73,7 @@ add_task(function* test_desktop_paths() {
|
|||
|
||||
compare_paths(OS.Constants.Path.macUserLibDir, "ULibDir");
|
||||
compare_paths(OS.Constants.Path.macLocalApplicationsDir, "LocApp");
|
||||
compare_paths(OS.Constants.Path.macTrashDir, "Trsh");
|
||||
});
|
||||
|
||||
// Open libxul
|
||||
|
|
Загрузка…
Ссылка в новой задаче