Bug 1228526 - Part 1, support device filtering by requested presentation URL. r=smaug

MozReview-Commit-ID: JrqeavLGub1

--HG--
extra : rebase_source : fc2eca80d59dc36e97a7af8ed3de6597faf38703
This commit is contained in:
Shih-Chiang Chien 2016-08-26 10:59:27 +08:00
Родитель 6ac132dfe9
Коммит a2a2c152ab
15 изменённых файлов: 299 добавлений и 6 удалений

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Services.h"
#include "MainThreadUtils.h"
#include "nsArrayUtils.h"
#include "nsCategoryCache.h"
#include "nsCOMPtr.h"
#include "nsIMutableArray.h"
@ -148,7 +149,7 @@ PresentationDeviceManager::GetDeviceAvailable(bool* aRetVal)
}
NS_IMETHODIMP
PresentationDeviceManager::GetAvailableDevices(nsIArray** aRetVal)
PresentationDeviceManager::GetAvailableDevices(nsIArray* aPresentationUrls, nsIArray** aRetVal)
{
NS_ENSURE_ARG_POINTER(aRetVal);
MOZ_ASSERT(NS_IsMainThread());
@ -158,9 +159,42 @@ PresentationDeviceManager::GetAvailableDevices(nsIArray** aRetVal)
NS_DispatchToMainThread(
NewRunnableMethod(this, &PresentationDeviceManager::ForceDiscovery));
nsTArray<nsString> presentationUrls;
if (aPresentationUrls) {
uint32_t length;
nsresult rv = aPresentationUrls->GetLength(&length);
if (NS_SUCCEEDED(rv)) {
for (uint32_t i = 0; i < length; ++i) {
nsCOMPtr<nsISupportsString> isupportStr =
do_QueryElementAt(aPresentationUrls, i);
nsAutoString presentationUrl;
rv = isupportStr->GetData(presentationUrl);
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
presentationUrls.AppendElement(presentationUrl);
}
}
}
nsCOMPtr<nsIMutableArray> devices = do_CreateInstance(NS_ARRAY_CONTRACTID);
for (uint32_t i = 0; i < mDevices.Length(); ++i) {
devices->AppendElement(mDevices[i], false);
if (presentationUrls.IsEmpty()) {
devices->AppendElement(mDevices[i], false);
continue;
}
for (uint32_t j = 0; j < presentationUrls.Length(); ++j) {
bool isSupported;
if (NS_SUCCEEDED(mDevices[i]->IsRequestedUrlSupported(presentationUrls[i],
&isSupported)) &&
isSupported) {
devices->AppendElement(mDevices[i], false);
break;
}
}
}
devices.forget(aRetVal);

Просмотреть файл

@ -11,6 +11,7 @@
#include "mozIApplication.h"
#include "nsGlobalWindow.h"
#include "nsIAppsService.h"
#include "nsIMutableArray.h"
#include "nsIObserverService.h"
#include "nsIPresentationControlChannel.h"
#include "nsIPresentationDeviceManager.h"
@ -19,9 +20,11 @@
#include "nsIPresentationRequestUIGlue.h"
#include "nsIPresentationSessionRequest.h"
#include "nsIPresentationTerminateRequest.h"
#include "nsISupportsPrimitives.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCID.h"
#include "nsXULAppAPI.h"
#include "PresentationLog.h"
@ -612,8 +615,18 @@ PresentationService::StartSession(const nsAString& aUrl,
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsIMutableArray> presentationUrls
= do_CreateInstance(NS_ARRAY_CONTRACTID);
if (!presentationUrls) {
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}
nsCOMPtr<nsISupportsString> supportsStr =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
supportsStr->SetData(aUrl);
presentationUrls->AppendElement(supportsStr, false);
nsCOMPtr<nsIArray> devices;
nsresult rv = deviceManager->GetAvailableDevices(getter_AddRefs(devices));
nsresult rv = deviceManager->GetAvailableDevices(presentationUrls, getter_AddRefs(devices));
if (NS_WARN_IF(NS_FAILED(rv))) {
return aCallback->NotifyError(NS_ERROR_DOM_OPERATION_ERR);
}

Просмотреть файл

@ -31,6 +31,13 @@ interface nsIPresentationDevice : nsISupports
// Do something when presentation session is disconnected.
void disconnect();
/*
* Query if requested presentation URL is supported.
* @params requestedUrl the designated URL for a presentation request.
* @returns true if designated URL is supported.
*/
boolean isRequestedUrlSupported(in DOMString requestedUrl);
};

Просмотреть файл

@ -40,10 +40,12 @@ interface nsIPresentationDeviceManager : nsISupports
void forceDiscovery();
/*
* Retrieve all available devices, return a list of nsIPresentationDevice.
* Retrieve all available devices or all available devices that supports
* designated presentation URLs, return a list of nsIPresentationDevice.
* The returned list is a cached device list and could be out-of-date.
* Observe device change events to get following updates.
* @param presentationUrls the target presentation URLs for device filtering
*/
nsIArray getAvailableDevices();
nsIArray getAvailableDevices([optional] in nsIArray presentationUrls);
};

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DeviceProviderHelpers.h"
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
namespace mozilla {
namespace dom {
namespace presentation {
static const char* const kFxTVPresentationAppUrls[] = {
"app://fling-player.gaiamobile.org/index.html",
"app://notification-receiver.gaiamobile.org/index.html",
nullptr
};
/* static */ bool
DeviceProviderHelpers::IsCommonlySupportedScheme(const nsAString& aUrl)
{
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aUrl);
if (NS_FAILED(rv) || !uri) {
return false;
}
nsAutoCString scheme;
uri->GetScheme(scheme);
if (scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https")) {
return true;
}
return false;
}
/* static */ bool
DeviceProviderHelpers::IsFxTVSupportedAppUrl(const nsAString& aUrl)
{
// Check if matched with any presentation Apps on TV.
for (uint32_t i = 0; kFxTVPresentationAppUrls[i]; i++) {
if (aUrl.EqualsASCII(kFxTVPresentationAppUrls[i])) {
return true;
}
}
return false;
}
} // namespace presentation
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_presentation_DeviceProviderHelpers_h
#define mozilla_dom_presentation_DeviceProviderHelpers_h
#include "nsString.h"
namespace mozilla {
namespace dom {
namespace presentation {
class DeviceProviderHelpers final
{
public:
static bool IsCommonlySupportedScheme(const nsAString& aUrl);
static bool IsFxTVSupportedAppUrl(const nsAString& aUrl);
private:
DeviceProviderHelpers() = delete;
};
} // namespace presentation
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_presentation_DeviceProviderHelpers_h

Просмотреть файл

@ -5,6 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DisplayDeviceProvider.h"
#include "DeviceProviderHelpers.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
@ -117,6 +119,23 @@ DisplayDeviceProvider::HDMIDisplayDevice::Disconnect()
return NS_OK;;
}
NS_IMETHODIMP
DisplayDeviceProvider::HDMIDisplayDevice::IsRequestedUrlSupported(
const nsAString& aRequestedUrl,
bool* aRetVal)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aRetVal) {
return NS_ERROR_INVALID_POINTER;
}
// 1-UA device only supports HTTP/HTTPS hosted receiver page.
*aRetVal = DeviceProviderHelpers::IsCommonlySupportedScheme(aRequestedUrl);
return NS_OK;
}
nsresult
DisplayDeviceProvider::HDMIDisplayDevice::OpenTopLevelWindow()
{

Просмотреть файл

@ -4,6 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LegacyMDNSDeviceProvider.h"
#include "DeviceProviderHelpers.h"
#include "MainThreadUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
@ -751,6 +753,21 @@ LegacyMDNSDeviceProvider::Device::Disconnect()
return NS_OK;
}
NS_IMETHODIMP
LegacyMDNSDeviceProvider::Device::IsRequestedUrlSupported(
const nsAString& aRequestedUrl,
bool* aRetVal)
{
if (!aRetVal) {
return NS_ERROR_INVALID_POINTER;
}
// Legacy TV 2.5 device only support a fixed set of presentation Apps.
*aRetVal = DeviceProviderHelpers::IsFxTVSupportedAppUrl(aRequestedUrl);
return NS_OK;
}
} // namespace legacy
} // namespace presentation
} // namespace dom

Просмотреть файл

@ -4,6 +4,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MulticastDNSDeviceProvider.h"
#include "DeviceProviderHelpers.h"
#include "MainThreadUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
@ -1222,6 +1224,26 @@ MulticastDNSDeviceProvider::Device::Disconnect()
return NS_OK;
}
NS_IMETHODIMP
MulticastDNSDeviceProvider::Device::IsRequestedUrlSupported(
const nsAString& aRequestedUrl,
bool* aRetVal)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aRetVal) {
return NS_ERROR_INVALID_POINTER;
}
// TV 2.6 also supports presentation Apps and HTTP/HTTPS hosted receiver page.
if (DeviceProviderHelpers::IsFxTVSupportedAppUrl(aRequestedUrl) ||
DeviceProviderHelpers::IsCommonlySupportedScheme(aRequestedUrl)) {
*aRetVal = true;
}
return NS_OK;
}
} // namespace presentation
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -10,6 +10,7 @@ EXTRA_COMPONENTS += [
]
UNIFIED_SOURCES += [
'DeviceProviderHelpers.cpp',
'DisplayDeviceProvider.cpp',
'MulticastDNSDeviceProvider.cpp',
'PresentationDeviceProviderModule.cpp',

Просмотреть файл

@ -22,9 +22,13 @@ var testProvider = {
var testDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishSessionTransport: function(url, presentationId) {
establishControlChannel: function() {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
id: null,
name: null,
type: null,

Просмотреть файл

@ -185,6 +185,10 @@ const mockedDevice = {
sendAsyncMessage('control-channel-established');
return mockedControlChannel;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
const mockedDevicePrompt = {

Просмотреть файл

@ -145,6 +145,10 @@ const mockDevice = {
sendAsyncMessage('control-channel-established');
return mockControlChannelOfSender;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return true;
},
};
const mockDevicePrompt = {

Просмотреть файл

@ -426,6 +426,68 @@ function addDevice() {
run_next_test();
}
function filterDevice() {
Services.prefs.setBoolPref(PREF_DISCOVERY, true);
let mockDevice = createDevice("device.local",
12345,
"service.name",
SERVICE_TYPE);
let mockObj = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]),
startDiscovery: function(serviceType, listener) {
listener.onDiscoveryStarted(serviceType);
listener.onServiceFound(createDevice("",
0,
mockDevice.serviceName,
mockDevice.serviceType));
return {
QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
cancel: function() {}
};
},
registerService: function(serviceInfo, listener) {},
resolveService: function(serviceInfo, listener) {
Assert.equal(serviceInfo.serviceName, mockDevice.serviceName);
Assert.equal(serviceInfo.serviceType, mockDevice.serviceType);
listener.onServiceResolved(createDevice(mockDevice.host,
mockDevice.port,
mockDevice.serviceName,
mockDevice.serviceType));
}
};
let contractHook = new ContractHook(SD_CONTRACT_ID, mockObj);
let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider);
let listener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener,
Ci.nsISupportsWeakReference]),
addDevice: function(device) {
let tests = [
{ requestedUrl: "app://fling-player.gaiamobile.org/index.html", supported: true },
{ requestedUrl: "app://notification-receiver.gaiamobile.org/index.html", supported: true },
{ requestedUrl: "http://example.com", supported: true },
{ requestedUrl: "https://example.com", supported: true },
{ requestedUrl: "ftp://example.com", supported: false },
{ requestedUrl: "app://unknown-app-id", supported: false },
{ requestedUrl: "unknowSchem://example.com", supported: false },
];
for (let test of tests) {
Assert.equal(device.isRequestedUrlSupported(test.requestedUrl), test.supported);
}
provider.listener = null;
run_next_test();
},
updateDevice: function() {},
removeDevice: function() {},
onSessionRequest: function() {},
};
provider.listener = listener;
}
function handleSessionRequest() {
Services.prefs.setBoolPref(PREF_DISCOVERY, true);
Services.prefs.setBoolPref(PREF_DISCOVERABLE, false);
@ -1239,6 +1301,7 @@ function run_test() {
add_test(noRegisterService);
add_test(registerServiceDynamically);
add_test(addDevice);
add_test(filterDevice);
add_test(handleSessionRequest);
add_test(handleOnSessionRequest);
add_test(handleOnSessionRequestFromUnknownDevice);

Просмотреть файл

@ -40,6 +40,7 @@ var testProvider = {
},
};
const forbiddenRequestedUrl = 'http://example.com';
var testDevice = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
id: 'id',
@ -48,6 +49,10 @@ var testDevice = {
establishControlChannel: function(url, presentationId) {
return null;
},
disconnect: function() {},
isRequestedUrlSupported: function(requestedUrl) {
return forbiddenRequestedUrl !== requestedUrl;
},
};
function addProvider() {
@ -122,6 +127,16 @@ function updateDevice() {
manager.QueryInterface(Ci.nsIPresentationDeviceListener).updateDevice(testDevice);
}
function filterDevice() {
let presentationUrls = Cc['@mozilla.org/array;1'].createInstance(Ci.nsIMutableArray);
let url = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
url.data = forbiddenRequestedUrl;
presentationUrls.appendElement(url, false);
let devices = manager.getAvailableDevices(presentationUrls);
Assert.equal(devices.length, 0, 'expect 0 available device for example.com');
run_next_test();
}
function sessionRequest() {
let testUrl = 'http://www.example.org/';
let testPresentationId = 'test-presentation-id';
@ -217,6 +232,7 @@ add_test(addProvider);
add_test(forceDiscovery);
add_test(addDevice);
add_test(updateDevice);
add_test(filterDevice);
add_test(sessionRequest);
add_test(terminateRequest);
add_test(reconnectRequest);