зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1148307 - Part 4 - use data channel in substitution for TCP session transport (in-process), r=smaug
--HG-- rename : dom/presentation/tests/mochitest/test_presentation_receiver.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html rename : dom/presentation/tests/mochitest/test_presentation_receiver_establish_connection_error.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html rename : dom/presentation/tests/mochitest/test_presentation_receiver_establish_connection_timeout.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html rename : dom/presentation/tests/mochitest/test_presentation_receiver_oop.html => dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html rename : dom/presentation/tests/mochitest/test_presentation_sender.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender.html rename : dom/presentation/tests/mochitest/test_presentation_sender_default_request.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_default_request.html rename : dom/presentation/tests/mochitest/test_presentation_sender_disconnect.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_disconnect.html rename : dom/presentation/tests/mochitest/test_presentation_sender_establish_connection_error.html => dom/presentation/tests/mochitest/test_presentation_tcp_sender_establish_connection_error.html
This commit is contained in:
Родитель
fee05caf8c
Коммит
a8a1aaba30
|
@ -131,7 +131,7 @@ PresentationRequest::StartWithDevice(const nsAString& aDeviceId,
|
|||
|
||||
nsCOMPtr<nsIPresentationServiceCallback> callback =
|
||||
new PresentationRequesterCallback(this, mUrl, id, promise);
|
||||
rv = service->StartSession(mUrl, id, origin, aDeviceId, callback);
|
||||
rv = service->StartSession(mUrl, id, origin, aDeviceId, GetOwner()->WindowID(), callback);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
|
|
@ -388,6 +388,7 @@ PresentationService::StartSession(const nsAString& aUrl,
|
|||
const nsAString& aSessionId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aDeviceId,
|
||||
uint64_t aWindowId,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -400,6 +401,13 @@ PresentationService::StartSession(const nsAString& aUrl,
|
|||
new PresentationControllingInfo(aUrl, aSessionId, aCallback);
|
||||
mSessionInfo.Put(aSessionId, info);
|
||||
|
||||
// Only track the info when an actual window ID, which would never be 0, is
|
||||
// provided (for an in-process sender page).
|
||||
if (aWindowId != 0) {
|
||||
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDeviceRequest> request =
|
||||
new PresentationDeviceRequest(aUrl, aSessionId, aOrigin);
|
||||
|
||||
|
@ -614,7 +622,7 @@ PresentationService::NotifyReceiverReady(const nsAString& aSessionId,
|
|||
// Only track the responding info when an actual window ID, which would never
|
||||
// be 0, is provided (for an in-process receiver page).
|
||||
if (aWindowId != 0) {
|
||||
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
|
||||
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
|
@ -637,6 +645,16 @@ PresentationService::UntrackSessionInfo(const nsAString& aSessionId)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationService::GetWindowIdBySessionId(const nsAString& aSessionId,
|
||||
uint64_t* aWindowId)
|
||||
{
|
||||
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool
|
||||
PresentationService::IsSessionAccessible(const nsAString& aSessionId,
|
||||
base::ProcessId aProcessId)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIFrameLoader.h"
|
||||
#include "nsIMutableArray.h"
|
||||
|
@ -153,8 +154,6 @@ TCPPresentationChannelDescription::GetType(uint8_t* aRetVal)
|
|||
return NS_ERROR_INVALID_POINTER;
|
||||
}
|
||||
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// Only support TCP socket for now.
|
||||
*aRetVal = nsIPresentationChannelDescription::TYPE_TCP;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -171,11 +170,9 @@ TCPPresentationChannelDescription::GetTcpAddress(nsIArray** aRetVal)
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// Ultimately we may use all the available addresses. DataChannel appears
|
||||
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||
// only exposed on Firefox OS where the first IP appears enough for most
|
||||
// scenarios.
|
||||
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
|
||||
// into account. And at the first stage Presentation API is only exposed on
|
||||
// Firefox OS where the first IP appears enough for most scenarios.
|
||||
nsCOMPtr<nsISupportsCString> address = do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
|
||||
if (NS_WARN_IF(!address)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
@ -202,8 +199,6 @@ TCPPresentationChannelDescription::GetTcpPort(uint16_t* aRetVal)
|
|||
NS_IMETHODIMP
|
||||
TCPPresentationChannelDescription::GetDataChannelSDP(nsAString& aDataChannelSDP)
|
||||
{
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// Only support TCP socket for now.
|
||||
aDataChannelSDP.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -241,6 +236,8 @@ PresentationSessionInfo::Shutdown(nsresult aReason)
|
|||
}
|
||||
|
||||
mIsResponderReady = false;
|
||||
|
||||
mBuilder = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -333,6 +330,22 @@ PresentationSessionInfo::UntrackFromService()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
PresentationSessionInfo::GetWindow()
|
||||
{
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint64_t windowId = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(service->GetWindowIdBySessionId(mSessionId, &windowId)))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nsGlobalWindow::GetInnerWindowWithId(windowId)->AsInner();
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
PresentationSessionInfo::IsAccessible(base::ProcessId aProcessId)
|
||||
{
|
||||
|
@ -428,11 +441,10 @@ PresentationSessionInfo::OnSessionTransport(nsIPresentationSessionTransport* tra
|
|||
NS_IMETHODIMP
|
||||
PresentationSessionInfo::OnError(nsresult reason)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
return ReplyError(reason);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* Implementation of PresentationControllingInfo
|
||||
*
|
||||
* During presentation session establishment, the sender expects the following
|
||||
|
@ -527,11 +539,10 @@ PresentationControllingInfo::GetAddress()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// Ultimately we may use all the available addresses. DataChannel appears
|
||||
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||
// only exposed on Firefox OS where the first IP appears enough for most
|
||||
// scenarios.
|
||||
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
|
||||
// into account. And at the first stage Presentation API is only exposed on
|
||||
// Firefox OS where the first IP appears enough for most scenarios.
|
||||
|
||||
nsAutoString ip;
|
||||
ip.Assign(ips[0]);
|
||||
|
||||
|
@ -633,9 +644,29 @@ NS_IMETHODIMP
|
|||
PresentationControllingInfo::NotifyOpened()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!Preferences::GetBool("dom.presentation.session_transport.data_channel.enable")) {
|
||||
// Build TCP session transport
|
||||
return GetAddress();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
|
||||
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
|
||||
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
|
||||
|
||||
return builder->BuildDataChannelTransport(nsIPresentationSessionTransportBuilder::TYPE_SENDER,
|
||||
GetWindow(),
|
||||
mControlChannel,
|
||||
this);
|
||||
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationControllingInfo::NotifyClosed(nsresult aReason)
|
||||
{
|
||||
|
@ -677,6 +708,7 @@ PresentationControllingInfo::OnSocketAccepted(nsIServerSocket* aServerSocket,
|
|||
return ReplyError(NS_ERROR_DOM_OPERATION_ERR);
|
||||
}
|
||||
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
|
||||
return builder->BuildTCPSenderTransport(aTransport, this);
|
||||
}
|
||||
|
||||
|
@ -703,7 +735,7 @@ PresentationControllingInfo::OnStopListening(nsIServerSocket* aServerSocket,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Implementation of PresentationPresentingInfo
|
||||
*
|
||||
* During presentation session establishment, the receiver expects the following
|
||||
|
@ -766,16 +798,21 @@ PresentationPresentingInfo::Shutdown(nsresult aReason)
|
|||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport* transport)
|
||||
{
|
||||
PresentationSessionInfo::OnSessionTransport(transport);
|
||||
nsresult rv = PresentationSessionInfo::OnSessionTransport(transport);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// send answer for TCP session transport
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
|
||||
// Prepare and send the answer.
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// In the current implementation of |PresentationSessionTransport|,
|
||||
// |GetSelfAddress| cannot return the real info when it's initialized via
|
||||
// |InitWithChannelDescription|. Yet this deficiency only affects the channel
|
||||
// |buildTCPReceiverTransport|. Yet this deficiency only affects the channel
|
||||
// description for the answer, which is not actually checked at requester side.
|
||||
nsCOMPtr<nsINetAddr> selfAddr;
|
||||
nsresult rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
|
||||
rv = mTransport->GetSelfAddress(getter_AddRefs(selfAddr));
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
nsCString address;
|
||||
|
@ -790,6 +827,9 @@ PresentationPresentingInfo::OnSessionTransport(nsIPresentationSessionTransport*
|
|||
return mControlChannel->SendAnswer(description);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationPresentingInfo::OnError(nsresult reason)
|
||||
{
|
||||
|
@ -799,6 +839,13 @@ PresentationPresentingInfo::OnError(nsresult reason)
|
|||
nsresult
|
||||
PresentationPresentingInfo::InitTransportAndSendAnswer()
|
||||
{
|
||||
uint8_t type = 0;
|
||||
nsresult rv = mRequesterDescription->GetType(&type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (type == nsIPresentationChannelDescription::TYPE_TCP) {
|
||||
// Establish a data transport channel |mTransport| to the sender and use
|
||||
// |this| as the callback.
|
||||
nsCOMPtr<nsIPresentationTCPSessionTransportBuilder> builder =
|
||||
|
@ -807,9 +854,43 @@ PresentationPresentingInfo::InitTransportAndSendAnswer()
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_TCP;
|
||||
return builder->BuildTCPReceiverTransport(mRequesterDescription, this);
|
||||
}
|
||||
|
||||
if (type == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
nsCOMPtr<nsIPresentationDataChannelSessionTransportBuilder> builder =
|
||||
do_CreateInstance("@mozilla.org/presentation/datachanneltransportbuilder;1");
|
||||
|
||||
if (NS_WARN_IF(!builder)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mBuilder = builder;
|
||||
mTransportType = nsIPresentationChannelDescription::TYPE_DATACHANNEL;
|
||||
rv = builder->BuildDataChannelTransport(nsIPresentationSessionTransportBuilder::TYPE_RECEIVER,
|
||||
GetWindow(),
|
||||
mControlChannel,
|
||||
this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// delegate |onOffer| to builder
|
||||
nsCOMPtr<nsIPresentationControlChannelListener> listener(do_QueryInterface(builder));
|
||||
|
||||
if (NS_WARN_IF(!listener)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return listener->OnOffer(mRequesterDescription);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false, "Unknown nsIPresentationChannelDescription type!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationPresentingInfo::UntrackFromService()
|
||||
{
|
||||
|
|
|
@ -111,10 +111,7 @@ protected:
|
|||
|
||||
nsresult ReplySuccess();
|
||||
|
||||
bool IsSessionReady()
|
||||
{
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
}
|
||||
virtual bool IsSessionReady() = 0;
|
||||
|
||||
virtual nsresult UntrackFromService();
|
||||
|
||||
|
@ -133,6 +130,11 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
// Should be nsIPresentationChannelDescription::TYPE_TCP/TYPE_DATACHANNEL
|
||||
uint8_t mTransportType = 0;
|
||||
|
||||
nsPIDOMWindowInner* GetWindow();
|
||||
|
||||
nsString mUrl;
|
||||
nsString mSessionId;
|
||||
bool mIsResponderReady;
|
||||
|
@ -143,6 +145,7 @@ protected:
|
|||
nsCOMPtr<nsIPresentationDevice> mDevice;
|
||||
nsCOMPtr<nsIPresentationSessionTransport> mTransport;
|
||||
nsCOMPtr<nsIPresentationControlChannel> mControlChannel;
|
||||
nsCOMPtr<nsIPresentationSessionTransportBuilder> mBuilder;
|
||||
};
|
||||
|
||||
// Session info with controlling browsing context (sender side) behaviors.
|
||||
|
@ -177,6 +180,18 @@ private:
|
|||
nsresult OnGetAddress(const nsACString& aAddress);
|
||||
|
||||
nsCOMPtr<nsIServerSocket> mServerSocket;
|
||||
|
||||
protected:
|
||||
bool IsSessionReady() override
|
||||
{
|
||||
if (mTransportType == nsIPresentationChannelDescription::TYPE_TCP) {
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
} else if (mTransportType == nsIPresentationChannelDescription::TYPE_DATACHANNEL) {
|
||||
// Established RTCDataChannel implies responder is ready.
|
||||
return mIsTransportReady;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Session info with presenting browsing context (receiver side) behaviors.
|
||||
|
@ -236,6 +251,12 @@ private:
|
|||
// The content parent communicating with the content process which the OOP
|
||||
// receiver page belongs to.
|
||||
nsCOMPtr<nsIContentParent> mContentParent;
|
||||
|
||||
protected:
|
||||
bool IsSessionReady() override
|
||||
{
|
||||
return mIsResponderReady && mIsTransportReady;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -151,11 +151,9 @@ PresentationTCPSessionTransport::BuildTCPReceiverTransport(nsIPresentationChanne
|
|||
return rv;
|
||||
}
|
||||
|
||||
// TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
// Ultimately we may use all the available addresses. DataChannel appears
|
||||
// more robust upon handling ICE. And at the first stage Presentation API is
|
||||
// only exposed on Firefox OS where the first IP appears enough for most
|
||||
// scenarios.
|
||||
// TODO bug 1228504 Take all IP addresses in PresentationChannelDescription
|
||||
// into account. And at the first stage Presentation API is only exposed on
|
||||
// Firefox OS where the first IP appears enough for most scenarios.
|
||||
nsCOMPtr<nsISupportsCString> supportStr = do_QueryElementAt(serverHosts, 0);
|
||||
if (NS_WARN_IF(!supportStr)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
|
|
@ -33,11 +33,6 @@ namespace dom {
|
|||
* presenting receiver side. The lifetime is managed in either
|
||||
* |PresentationControllingInfo| (sender side) or |PresentationPresentingInfo|
|
||||
* (receiver side) in PresentationSessionInfo.cpp.
|
||||
*
|
||||
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel.
|
||||
* The implementation over the TCP channel is primarily used for the early stage
|
||||
* of Presentation API (without SSL) and should be migrated to DataChannel with
|
||||
* full support soon.
|
||||
*/
|
||||
class PresentationTCPSessionTransport final : public nsIPresentationSessionTransport
|
||||
, public nsIPresentationTCPSessionTransportBuilder
|
||||
|
|
|
@ -39,6 +39,6 @@ interface nsIPresentationRespondingListener : nsISupports
|
|||
/*
|
||||
* Called when an incoming session connects.
|
||||
*/
|
||||
void notifySessionConnect(in uint64_t windowId,
|
||||
void notifySessionConnect(in unsigned long long windowId,
|
||||
in DOMString sessionId);
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ interface nsIPresentationServiceCallback : nsISupports
|
|||
void notifyError(in nsresult error);
|
||||
};
|
||||
|
||||
[scriptable, uuid(61864149-9838-4aa1-a21a-63eaf0b84a8c)]
|
||||
[scriptable, uuid(de42b741-5619-4650-b961-c2cebb572c95)]
|
||||
interface nsIPresentationService : nsISupports
|
||||
{
|
||||
/*
|
||||
|
@ -45,6 +45,10 @@ interface nsIPresentationService : nsISupports
|
|||
* @param origin: The url of requesting page.
|
||||
* @param deviceId: The specified device of handling this request, null string
|
||||
for prompt device selection dialog.
|
||||
* @param windowId: The inner window ID associated with the presentation
|
||||
* session. (0 implies no window ID since no actual window
|
||||
* uses 0 as its ID. Generally it's the case the window is
|
||||
* located in different process from this service)
|
||||
* @param callback: Invoke the callback when the operation is completed.
|
||||
* NotifySuccess() is called with |id| if a session is
|
||||
* established successfully with the selected device.
|
||||
|
@ -54,6 +58,7 @@ interface nsIPresentationService : nsISupports
|
|||
in DOMString sessionId,
|
||||
in DOMString origin,
|
||||
in DOMString deviceId,
|
||||
in unsigned long long windowId,
|
||||
in nsIPresentationServiceCallback callback);
|
||||
|
||||
/*
|
||||
|
@ -114,14 +119,14 @@ interface nsIPresentationService : nsISupports
|
|||
* @param windowId: The window ID associated with the listener.
|
||||
* @param listener: The listener to register.
|
||||
*/
|
||||
void registerRespondingListener(in uint64_t windowId,
|
||||
void registerRespondingListener(in unsigned long long windowId,
|
||||
in nsIPresentationRespondingListener listener);
|
||||
|
||||
/*
|
||||
* Unregister a responding listener. Must be called from the main thread.
|
||||
* @param windowId: The window ID associated with the listener.
|
||||
*/
|
||||
void unregisterRespondingListener(in uint64_t windowId);
|
||||
void unregisterRespondingListener(in unsigned long long windowId);
|
||||
|
||||
/*
|
||||
* Check if the presentation instance has an existent session ID at launch.
|
||||
|
@ -131,7 +136,7 @@ interface nsIPresentationService : nsISupports
|
|||
*
|
||||
* @param windowId: The inner window ID used to look up the session ID.
|
||||
*/
|
||||
DOMString getExistentSessionIdAtLaunch(in uint64_t windowId);
|
||||
DOMString getExistentSessionIdAtLaunch(in unsigned long long windowId);
|
||||
|
||||
/*
|
||||
* Notify the receiver page is ready for presentation use.
|
||||
|
@ -139,10 +144,11 @@ interface nsIPresentationService : nsISupports
|
|||
* @param sessionId: An ID to identify presentation session.
|
||||
* @param windowId: The inner window ID associated with the presentation
|
||||
* session. (0 implies no window ID since no actual window
|
||||
* uses 0 as its ID.)
|
||||
* uses 0 as its ID. Generally it's the case the window is
|
||||
* located in different process from this service)
|
||||
*/
|
||||
void notifyReceiverReady(in DOMString sessionId,
|
||||
[optional] in uint64_t windowId);
|
||||
[optional] in unsigned long long windowId);
|
||||
|
||||
/*
|
||||
* Untrack the relevant info about the presentation session if there's any.
|
||||
|
@ -150,4 +156,9 @@ interface nsIPresentationService : nsISupports
|
|||
* @param sessionId: An ID to identify presentation session.
|
||||
*/
|
||||
void untrackSessionInfo(in DOMString sessionId);
|
||||
|
||||
/*
|
||||
* The windowId for building RTCDataChannel session transport
|
||||
*/
|
||||
unsigned long long getWindowIdBySessionId(in DOMString sessionId);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
interface nsIPresentationChannelDescription;
|
||||
interface nsISocketTransport;
|
||||
interface nsIDOMWindow;
|
||||
interface mozIDOMWindow;
|
||||
interface nsIPresentationControlChannel;
|
||||
interface nsIPresentationSessionTransport;
|
||||
|
||||
|
@ -58,7 +58,7 @@ interface nsIPresentationDataChannelSessionTransportBuilder : nsIPresentationSes
|
|||
* |buildDataChannelTransport|.
|
||||
*/
|
||||
void buildDataChannelTransport(in uint8_t aType,
|
||||
in nsIDOMWindow aWindow,
|
||||
in mozIDOMWindow aWindow,
|
||||
in nsIPresentationControlChannel aControlChannel,
|
||||
in nsIPresentationSessionTransportBuilderListener aListener);
|
||||
};
|
||||
|
|
|
@ -50,12 +50,18 @@ PresentationIPCService::StartSession(const nsAString& aUrl,
|
|||
const nsAString& aSessionId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aDeviceId,
|
||||
uint64_t aWindowId,
|
||||
nsIPresentationServiceCallback* aCallback)
|
||||
{
|
||||
return SendRequest(aCallback, StartSessionRequest(nsAutoString(aUrl),
|
||||
nsAutoString(aSessionId),
|
||||
nsAutoString(aOrigin),
|
||||
nsAutoString(aDeviceId)));
|
||||
if (aWindowId != 0) {
|
||||
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
}
|
||||
|
||||
return SendRequest(aCallback, StartSessionRequest(nsString(aUrl),
|
||||
nsString(aSessionId),
|
||||
nsString(aOrigin),
|
||||
nsString(aDeviceId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -65,8 +71,8 @@ PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
|
|||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
MOZ_ASSERT(!aData.IsEmpty());
|
||||
|
||||
return SendRequest(nullptr, SendSessionMessageRequest(nsAutoString(aSessionId),
|
||||
nsAutoString(aData)));
|
||||
return SendRequest(nullptr, SendSessionMessageRequest(nsString(aSessionId),
|
||||
nsString(aData)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -74,7 +80,7 @@ PresentationIPCService::CloseSession(const nsAString& aSessionId)
|
|||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
return SendRequest(nullptr, CloseSessionRequest(nsAutoString(aSessionId)));
|
||||
return SendRequest(nullptr, CloseSessionRequest(nsString(aSessionId)));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -82,7 +88,7 @@ PresentationIPCService::TerminateSession(const nsAString& aSessionId)
|
|||
{
|
||||
MOZ_ASSERT(!aSessionId.IsEmpty());
|
||||
|
||||
return SendRequest(nullptr, TerminateSessionRequest(nsAutoString(aSessionId)));
|
||||
return SendRequest(nullptr, TerminateSessionRequest(nsString(aSessionId)));
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -131,7 +137,7 @@ PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
|
|||
|
||||
mSessionListeners.Put(aSessionId, aListener);
|
||||
if (sPresentationChild) {
|
||||
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsAutoString(aSessionId)));
|
||||
NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsString(aSessionId)));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -145,7 +151,7 @@ PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
|
|||
|
||||
mSessionListeners.Remove(aSessionId);
|
||||
if (sPresentationChild) {
|
||||
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
|
||||
NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsString(aSessionId)));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -175,6 +181,16 @@ PresentationIPCService::UnregisterRespondingListener(uint64_t aWindowId)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresentationIPCService::GetWindowIdBySessionId(const nsAString& aSessionId,
|
||||
uint64_t* aWindowId)
|
||||
{
|
||||
if (mRespondingWindowIds.Get(aSessionId, aWindowId)) {
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
|
||||
uint16_t aState)
|
||||
|
@ -250,10 +266,10 @@ PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId,
|
|||
}
|
||||
|
||||
// Track the responding info for an OOP receiver page.
|
||||
mRespondingSessionIds.Put(aWindowId, new nsAutoString(aSessionId));
|
||||
mRespondingSessionIds.Put(aWindowId, new nsString(aSessionId));
|
||||
mRespondingWindowIds.Put(aSessionId, aWindowId);
|
||||
|
||||
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsAutoString(aSessionId)));
|
||||
NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsString(aSessionId)));
|
||||
|
||||
// Release mCallback after using aSessionId
|
||||
// because aSessionId is held by mCallback.
|
||||
|
|
|
@ -186,7 +186,7 @@ PresentationParent::NotifyStateChange(const nsAString& aSessionId,
|
|||
uint16_t aState)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifySessionStateChange(nsAutoString(aSessionId), aState))) {
|
||||
!SendNotifySessionStateChange(nsString(aSessionId), aState))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -197,7 +197,7 @@ PresentationParent::NotifyMessage(const nsAString& aSessionId,
|
|||
const nsACString& aData)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifyMessage(nsAutoString(aSessionId), nsAutoCString(aData)))) {
|
||||
!SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -208,7 +208,7 @@ PresentationParent::NotifySessionConnect(uint64_t aWindowId,
|
|||
const nsAString& aSessionId)
|
||||
{
|
||||
if (NS_WARN_IF(mActorDestroyed ||
|
||||
!SendNotifySessionConnect(aWindowId, nsAutoString(aSessionId)))) {
|
||||
!SendNotifySessionConnect(aWindowId, nsString(aSessionId)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -218,6 +218,8 @@ bool
|
|||
PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Set window ID to 0 since the window is from content process.
|
||||
NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId, 0)));
|
||||
return true;
|
||||
}
|
||||
|
@ -251,8 +253,10 @@ nsresult
|
|||
PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
|
||||
{
|
||||
MOZ_ASSERT(mService);
|
||||
|
||||
// Set window ID to 0 since the window is from content process.
|
||||
return mService->StartSession(aRequest.url(), aRequest.sessionId(),
|
||||
aRequest.origin(), aRequest.deviceId(), this);
|
||||
aRequest.origin(), aRequest.deviceId(), 0, this);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -65,6 +65,10 @@ IPDL_SOURCES += [
|
|||
'ipc/PPresentationRequest.ipdl'
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../base'
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/Timer.jsm');
|
||||
|
||||
function registerMockedFactory(contractId, mockedClassId, mockedFactory) {
|
||||
var originalClassId, originalFactory;
|
||||
|
@ -49,7 +51,12 @@ addresses.appendElement(address, false);
|
|||
|
||||
const mockedChannelDescription = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationChannelDescription]),
|
||||
type: 1,
|
||||
get type() {
|
||||
if (Services.prefs.getBoolPref("dom.presentation.session_transport.data_channel.enable")) {
|
||||
return Ci.nsIPresentationChannelDescription.TYPE_DATACHANNEL;
|
||||
}
|
||||
return Ci.nsIPresentationChannelDescription.TYPE_TCP;
|
||||
},
|
||||
tcpAddress: addresses,
|
||||
tcpPort: 1234,
|
||||
};
|
||||
|
@ -199,6 +206,8 @@ const mockedDevicePrompt = {
|
|||
const mockedSessionTransport = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationSessionTransport,
|
||||
Ci.nsIPresentationTCPSessionTransportBuilder,
|
||||
Ci.nsIPresentationDataChannelSessionTransportBuilder,
|
||||
Ci.nsIPresentationControlChannelListener,
|
||||
Ci.nsIFactory]),
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter) {
|
||||
|
@ -220,10 +229,11 @@ const mockedSessionTransport = {
|
|||
this._listener = listener;
|
||||
this._type = Ci.nsIPresentationSessionTransportBuilder.TYPE_SENDER;
|
||||
|
||||
setTimeout(()=>{
|
||||
this._listener.onSessionTransport(this);
|
||||
this._listener = null;
|
||||
|
||||
this.simulateTransportReady();
|
||||
}, 0);
|
||||
},
|
||||
buildTCPReceiverTransport: function(description, listener) {
|
||||
this._listener = listener;
|
||||
|
@ -237,8 +247,25 @@ const mockedSessionTransport = {
|
|||
port: description.QueryInterface(Ci.nsIPresentationChannelDescription).tcpPort,
|
||||
};
|
||||
|
||||
setTimeout(()=>{
|
||||
this._listener.onSessionTransport(this);
|
||||
this._listener = null;
|
||||
}, 0);
|
||||
},
|
||||
// in-process case
|
||||
buildDataChannelTransport: function(type, window, controlChannel, listener) {
|
||||
dump("build data channel transport\n");
|
||||
this._listener = listener;
|
||||
this._type = type;
|
||||
|
||||
var hasNavigator = window ? (typeof window.navigator != "undefined") : false;
|
||||
sendAsyncMessage('check-navigator', hasNavigator);
|
||||
|
||||
setTimeout(()=>{
|
||||
this._listener.onSessionTransport(this);
|
||||
this._listener = null;
|
||||
this.simulateTransportReady();
|
||||
}, 0);
|
||||
},
|
||||
enableDataNotification: function() {
|
||||
sendAsyncMessage('data-transport-notification-enabled');
|
||||
|
@ -256,6 +283,10 @@ const mockedSessionTransport = {
|
|||
simulateIncomingMessage: function(message) {
|
||||
this._callback.QueryInterface(Ci.nsIPresentationSessionTransportCallback).notifyData(message);
|
||||
},
|
||||
onOffer: function(aOffer) {
|
||||
},
|
||||
onAnswer: function(aAnswer) {
|
||||
}
|
||||
};
|
||||
|
||||
const mockedNetworkInfo = {
|
||||
|
@ -311,6 +342,9 @@ originalFactoryData.push(registerMockedFactory("@mozilla.org/network/server-sock
|
|||
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/presentationtcpsessiontransport;1",
|
||||
uuidGenerator.generateUUID(),
|
||||
mockedSessionTransport));
|
||||
originalFactoryData.push(registerMockedFactory("@mozilla.org/presentation/datachanneltransportbuilder;1",
|
||||
uuidGenerator.generateUUID(),
|
||||
mockedSessionTransport));
|
||||
originalFactoryData.push(registerMockedFactory("@mozilla.org/network/manager;1",
|
||||
uuidGenerator.generateUUID(),
|
||||
mockedNetworkManager));
|
||||
|
|
|
@ -9,23 +9,28 @@ support-files =
|
|||
file_presentation_receiver_inner_iframe_oop.html
|
||||
file_presentation_non_receiver_inner_iframe_oop.html
|
||||
|
||||
|
||||
[test_presentation_dc_sender.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
|
||||
[test_presentation_dc_receiver.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
|
||||
[test_presentation_device_info.html]
|
||||
[test_presentation_device_info_permission.html]
|
||||
[test_presentation_sender_disconnect.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender_establish_connection_error.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender_default_request.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_sender_startWithDevice.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_receiver_establish_connection_error.html]
|
||||
[test_presentation_tcp_sender_disconnect.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_tcp_sender_establish_connection_error.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_tcp_sender.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_tcp_sender_default_request.html]
|
||||
skip-if = toolkit == 'android' # Bug 1129785
|
||||
[test_presentation_tcp_receiver_establish_connection_error.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android' || os == 'mac' || os == 'win' || buildapp == 'mulet') # Bug 1129785, Bug 1204709
|
||||
[test_presentation_receiver_establish_connection_timeout.html]
|
||||
[test_presentation_tcp_receiver_establish_connection_timeout.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
|
||||
[test_presentation_receiver.html]
|
||||
[test_presentation_tcp_receiver.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
|
||||
[test_presentation_receiver_oop.html]
|
||||
[test_presentation_tcp_receiver_oop.html]
|
||||
skip-if = (e10s || toolkit == 'gonk' || toolkit == 'android') # Bug 1129785
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for B2G PresentationConnection API at receiver side</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G PresentationConnection API at receiver side</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script type="application/javascript">
|
||||
|
||||
'use strict';
|
||||
|
||||
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
|
||||
var receiverUrl = SimpleTest.getTestFileURL('file_presentation_receiver.html');
|
||||
|
||||
var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
||||
function setup() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.sendAsyncMessage('trigger-device-add');
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('src', receiverUrl);
|
||||
|
||||
// This event is triggered when the iframe calls "postMessage".
|
||||
window.addEventListener('message', function listener(aEvent) {
|
||||
var message = aEvent.data;
|
||||
if (/^OK /.exec(message)) {
|
||||
ok(true, "Message from iframe: " + message);
|
||||
} else if (/^KO /.exec(message)) {
|
||||
ok(false, "Message from iframe: " + message);
|
||||
} else if (/^INFO /.exec(message)) {
|
||||
info("Message from iframe: " + message);
|
||||
} else if (/^COMMAND /.exec(message)) {
|
||||
var command = JSON.parse(message.replace(/^COMMAND /, ''));
|
||||
gScript.sendAsyncMessage(command.name, command.data);
|
||||
} else if (/^DONE$/.exec(message)) {
|
||||
ok(true, "Messaging from iframe complete.");
|
||||
window.removeEventListener('message', listener);
|
||||
|
||||
teardown();
|
||||
}
|
||||
}, false);
|
||||
|
||||
var promise = new Promise(function(aResolve, aReject) {
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
aResolve(iframe);
|
||||
});
|
||||
obs.notifyObservers(promise, 'setup-request-promise', null);
|
||||
|
||||
gScript.addMessageListener('offer-received', function offerReceivedHandler() {
|
||||
gScript.removeMessageListener('offer-received', offerReceivedHandler);
|
||||
info("An offer is received.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
|
||||
gScript.removeMessageListener('answer-sent', answerSentHandler);
|
||||
ok(aIsValid, "A valid answer is sent.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
|
||||
is(aReason, SpecialPowers.Cr.NS_OK, "The control channel is closed normally.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
|
||||
gScript.removeMessageListener('check-navigator', checknavigatorHandler);
|
||||
ok(aSuccess, "buildDataChannel get correct window object");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
|
||||
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
|
||||
info("Data notification is enabled for data transport channel.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
is(aReason, SpecialPowers.Cr.NS_OK, "The data transport should be closed normally.");
|
||||
});
|
||||
|
||||
aResolve();
|
||||
});
|
||||
}
|
||||
|
||||
function testIncomingSessionRequest() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
|
||||
gScript.removeMessageListener('receiver-launching', launchReceiverHandler);
|
||||
info("Trying to launch receiver page.");
|
||||
|
||||
ok(navigator.presentation, "navigator.presentation should be available in in-process pages.");
|
||||
ok(!navigator.presentation.receiver, "Non-receiving in-process pages shouldn't get a presentation receiver instance.");
|
||||
aResolve();
|
||||
});
|
||||
|
||||
gScript.sendAsyncMessage('trigger-incoming-session-request', receiverUrl);
|
||||
});
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
|
||||
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
|
||||
gScript.destroy();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
gScript.sendAsyncMessage('teardown');
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
setup().
|
||||
then(testIncomingSessionRequest);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.session_transport.data_channel.enable", true]]},
|
||||
runTests);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,208 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for B2G Presentation API at sender side</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1148307">Test for B2G Presentation API at sender side</a>
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
'use strict';
|
||||
|
||||
var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('PresentationSessionChromeScript.js'));
|
||||
var request;
|
||||
var connection;
|
||||
|
||||
function testSetup() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
request = new PresentationRequest("http://example.com");
|
||||
|
||||
request.getAvailability().then(
|
||||
function(aAvailability) {
|
||||
aAvailability.onchange = function() {
|
||||
aAvailability.onchange = null;
|
||||
ok(aAvailability.value, "Device should be available.");
|
||||
aResolve();
|
||||
}
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when getting availability: " + aError);
|
||||
teardown();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
|
||||
gScript.sendAsyncMessage('trigger-device-add');
|
||||
});
|
||||
}
|
||||
|
||||
function testStartConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('device-prompt', function devicePromptHandler() {
|
||||
gScript.removeMessageListener('device-prompt', devicePromptHandler);
|
||||
info("Device prompt is triggered.");
|
||||
gScript.sendAsyncMessage('trigger-device-prompt-select');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-established', function controlChannelEstablishedHandler() {
|
||||
gScript.removeMessageListener('control-channel-established', controlChannelEstablishedHandler);
|
||||
info("A control channel is established.");
|
||||
gScript.sendAsyncMessage('trigger-control-channel-open');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-opened', function controlChannelOpenedHandler(aReason) {
|
||||
gScript.removeMessageListener('control-channel-opened', controlChannelOpenedHandler);
|
||||
info("The control channel is opened.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
|
||||
info("The control channel is closed. " + aReason);
|
||||
});
|
||||
|
||||
gScript.addMessageListener('check-navigator', function checknavigatorHandler(aSuccess) {
|
||||
gScript.removeMessageListener('check-navigator', checknavigatorHandler);
|
||||
ok(aSuccess, "buildDataChannel get correct window object");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('offer-sent', function offerSentHandler(aIsValid) {
|
||||
gScript.removeMessageListener('offer-sent', offerSentHandler);
|
||||
ok(aIsValid, "A valid offer is sent out.");
|
||||
gScript.sendAsyncMessage('trigger-incoming-transport');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('answer-received', function answerReceivedHandler() {
|
||||
gScript.removeMessageListener('answer-received', answerReceivedHandler);
|
||||
info("An answer is received.");
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-initialized', function dataTransportInitializedHandler() {
|
||||
gScript.removeMessageListener('data-transport-initialized', dataTransportInitializedHandler);
|
||||
info("Data transport channel is initialized.");
|
||||
gScript.sendAsyncMessage('trigger-incoming-answer');
|
||||
});
|
||||
|
||||
gScript.addMessageListener('data-transport-notification-enabled', function dataTransportNotificationEnabledHandler() {
|
||||
gScript.removeMessageListener('data-transport-notification-enabled', dataTransportNotificationEnabledHandler);
|
||||
info("Data notification is enabled for data transport channel.");
|
||||
});
|
||||
|
||||
var connectionFromEvent;
|
||||
request.onconnectionavailable = function(aEvent) {
|
||||
request.onconnectionavailable = null;
|
||||
connectionFromEvent = aEvent.connection;
|
||||
ok(connectionFromEvent, "|connectionavailable| event is fired with a connection.");
|
||||
|
||||
if (connection) {
|
||||
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
|
||||
aResolve();
|
||||
}
|
||||
};
|
||||
|
||||
request.start().then(
|
||||
function(aConnection) {
|
||||
connection = aConnection;
|
||||
ok(connection, "Connection should be available.");
|
||||
ok(connection.id, "Connection ID should be set.");
|
||||
is(connection.state, "connected", "Connection state at sender side should be connected by default.");
|
||||
|
||||
if (connectionFromEvent) {
|
||||
is(connection, connectionFromEvent, "The connection from promise and the one from |connectionavailable| event should be the same.");
|
||||
aResolve();
|
||||
}
|
||||
},
|
||||
function(aError) {
|
||||
ok(false, "Error occurred when establishing a connection: " + aError);
|
||||
teardown();
|
||||
aReject();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function testSend() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
const outgoingMessage = "test outgoing message";
|
||||
|
||||
gScript.addMessageListener('message-sent', function messageSentHandler(aMessage) {
|
||||
gScript.removeMessageListener('message-sent', messageSentHandler);
|
||||
is(aMessage, outgoingMessage, "The message is sent out.");
|
||||
aResolve();
|
||||
});
|
||||
|
||||
connection.send(outgoingMessage);
|
||||
});
|
||||
}
|
||||
|
||||
function testIncomingMessage() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
const incomingMessage = "test incoming message";
|
||||
|
||||
connection.addEventListener('message', function messageHandler(aEvent) {
|
||||
connection.removeEventListener('message', messageHandler);
|
||||
is(aEvent.data, incomingMessage, "An incoming message should be received.");
|
||||
aResolve();
|
||||
});
|
||||
|
||||
gScript.sendAsyncMessage('trigger-incoming-message', incomingMessage);
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
info("The data transport is closed. " + aReason);
|
||||
});
|
||||
|
||||
connection.onstatechange = function() {
|
||||
connection.onstatechange = null;
|
||||
is(connection.state, "terminated", "Connection should be terminated.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
connection.terminate();
|
||||
});
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
gScript.addMessageListener('teardown-complete', function teardownCompleteHandler() {
|
||||
gScript.removeMessageListener('teardown-complete', teardownCompleteHandler);
|
||||
gScript.destroy();
|
||||
info('teardown-complete');
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
gScript.sendAsyncMessage('teardown');
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
ok(window.PresentationRequest, "PresentationRequest should be available.");
|
||||
|
||||
testSetup().
|
||||
then(testStartConnection).
|
||||
then(testSend).
|
||||
then(testIncomingMessage).
|
||||
then(testTerminateConnection).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.session_transport.data_channel.enable", true]]},
|
||||
runTests);
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -156,7 +156,6 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
//SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: true, context: document},
|
||||
|
|
|
@ -116,15 +116,13 @@ function runTests() {
|
|||
then(testIncomingSessionRequest);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -91,15 +91,13 @@ function runTests() {
|
|||
then(testIncomingSessionRequest);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -65,15 +65,13 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0],
|
||||
["dom.presentation.session_transport.data_channel.enable", false],
|
||||
["presentation.receiver.loading.timeout", 10]]},
|
||||
runTests);
|
||||
});
|
|
@ -157,7 +157,6 @@ function runTests() {
|
|||
then(testIncomingSessionRequest);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
|
@ -165,8 +164,7 @@ SpecialPowers.pushPermissions([
|
|||
{type: 'browser', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0],
|
||||
["dom.presentation.session_transport.data_channel.enable", false],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.ipc.browser_frames.oop_by_default", true]]},
|
||||
runTests);
|
|
@ -186,15 +186,13 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -134,15 +134,13 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -140,15 +140,13 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -344,15 +344,13 @@ function runTests() {
|
|||
then(teardown);
|
||||
}
|
||||
|
||||
SimpleTest.expectAssertions(0, 5);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions([
|
||||
{type: 'presentation-device-manage', allow: false, context: document},
|
||||
{type: 'presentation', allow: true, context: document},
|
||||
], function() {
|
||||
SpecialPowers.pushPrefEnv({ 'set': [["dom.presentation.enabled", true],
|
||||
["dom.presentation.test.enabled", true],
|
||||
["dom.presentation.test.stage", 0]]},
|
||||
["dom.presentation.session_transport.data_channel.enable", false]]},
|
||||
runTests);
|
||||
});
|
||||
|
|
@ -43,7 +43,7 @@ interface PresentationConnection : EventTarget {
|
|||
*
|
||||
* This function only works when the state is "connected".
|
||||
*
|
||||
* TODO bug 1148307 Implement PresentationSessionTransport with DataChannel to
|
||||
* TODO bug 1228474 Implement PresentationSessionTransport with DataChannel to
|
||||
* support other binary types.
|
||||
*/
|
||||
[Throws]
|
||||
|
|
|
@ -5064,6 +5064,7 @@ pref("dom.presentation.tcp_server.debug", false);
|
|||
pref("dom.presentation.discovery.enabled", false);
|
||||
pref("dom.presentation.discovery.timeout_ms", 10000);
|
||||
pref("dom.presentation.discoverable", false);
|
||||
pref("dom.presentation.session_transport.data_channel.enable", true);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#if !defined(RELEASE_BUILD) || defined(DEBUG)
|
||||
|
|
Загрузка…
Ссылка в новой задаче