Bug 1080474 - Part 3 - Presentation UI glue for Firefox OS. r=fabrice.

This commit is contained in:
Shih-Chiang Chien 2014-10-13 17:05:50 +08:00
parent 65b37e606a
commit 28515cf40c
8 changed files with 335 additions and 0 deletions

View File

@ -28,6 +28,7 @@ SignInToWebsiteController.init();
Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm');
Cu.import('resource://gre/modules/DownloadsAPI.jsm');
Cu.import('resource://gre/modules/MobileIdentityManager.jsm');
Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm');
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");

View File

@ -106,3 +106,7 @@ contract @mozilla.org/services/mobileid-ui-glue;1 {83dbe26a-81f3-4a75-9541-3d0b7
component {7211ece0-b458-4635-9afc-f8d7f376ee95} B2GAppMigrator.js
contract @mozilla.org/app-migrator;1 {7211ece0-b458-4635-9afc-f8d7f376ee95}
# B2GPresentationDevicePrompt.js
component {4a300c26-e99b-4018-ab9b-c48cf9bc4de1} B2GPresentationDevicePrompt.js
contract @mozilla.org/presentation-device/prompt;1 {4a300c26-e99b-4018-ab9b-c48cf9bc4de1}

View File

@ -0,0 +1,87 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function debug(aMsg) {
//dump("-*- B2GPresentationDevicePrompt: " + aMsg + "\n");
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1";
const kB2GPRESENTATIONDEVICEPROMPT_CID = Components.ID("{4a300c26-e99b-4018-ab9b-c48cf9bc4de1}");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
function B2GPresentationDevicePrompt() {}
B2GPresentationDevicePrompt.prototype = {
classID: kB2GPRESENTATIONDEVICEPROMPT_CID,
contractID: kB2GPRESENTATIONDEVICEPROMPT_CONTRACTID,
classDescription: "B2G Presentation Device Prompt",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]),
// nsIPresentationDevicePrompt
promptDeviceSelection: function(aRequest) {
let self = this;
let requestId = Cc["@mozilla.org/uuid-generator;1"]
.getService(Ci.nsIUUIDGenerator).generateUUID().toString();
SystemAppProxy.addEventListener("mozContentEvent", function contentEvent(aEvent) {
let detail = aEvent.detail;
if (detail.id !== requestId) {
return;
}
SystemAppProxy.removeEventListener("mozContentEvent", contentEvent);
switch (detail.type) {
case "presentation-select-result":
debug("device " + detail.deviceId + " is selected by user");
let device = self._getDeviceById(detail.deviceId);
if (!device) {
debug("cancel request because device is not found");
aRequest.cancel();
}
aRequest.select(device);
break;
case "presentation-select-deny":
debug("request canceled by user");
aRequest.cancel();
break;
}
});
let detail = {
type: "presentation-select-device",
origin: aRequest.origin,
requestURL: aRequest.requestURL,
id: requestId,
};
SystemAppProxy.dispatchEvent(detail);
},
_getDeviceById: function(aDeviceId) {
let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
let devices = deviceManager.getAvailableDevices().QueryInterface(Ci.nsIArray);
for (let i = 0; i < devices.length; i++) {
let device = devices.queryElementAt(i, Ci.nsIPresentationDevice);
if (device.id === aDeviceId) {
return device;
}
}
return null;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([B2GPresentationDevicePrompt]);

View File

@ -11,6 +11,7 @@ EXTRA_COMPONENTS += [
'AlertsService.js',
'B2GAboutRedirector.js',
'B2GAppMigrator.js',
'B2GPresentationDevicePrompt.js',
'ContentPermissionPrompt.js',
'FilePicker.js',
'FxAccountsUIGlue.js',

View File

@ -5,6 +5,7 @@ support-files =
SandboxPromptTest.html
filepicker_path_handler_chrome.js
systemapp_helper.js
presentation_prompt_handler_chrome.js
[test_filepicker_path.html]
[test_permission_deny.html]
@ -12,3 +13,4 @@ support-files =
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
[test_systemapp.html]
[test_presentation_device_prompt.html]

View File

@ -0,0 +1,94 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
function debug(str) {
dump('presentation_prompt_handler_chrome: ' + str + '\n');
}
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const { XPCOMUtils } = Cu.import('resource://gre/modules/XPCOMUtils.jsm');
const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm');
const manager = Cc["@mozilla.org/presentation-device/manager;1"]
.getService(Ci.nsIPresentationDeviceManager);
const prompt = Cc['@mozilla.org/presentation-device/prompt;1']
.getService(Ci.nsIPresentationDevicePrompt);
function TestPresentationDevice(options) {
this.id = options.id;
this.name = options.name;
this.type = options.type;
}
TestPresentationDevice.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevice]),
establishSessionTransport: function() {
return null;
},
};
function TestPresentationRequest(options) {
this.origin = options.origin;
this.requestURL = options.requestURL;
}
TestPresentationRequest.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceRequest]),
select: function(device) {
let result = {
type: 'select',
device: {
id: device.id,
name: device.name,
type: device.type,
},
};
sendAsyncMessage('presentation-select-result', result);
},
cancel: function() {
let result = {
type: 'cancel',
};
sendAsyncMessage('presentation-select-result', result);
},
};
var testDevice = null;
addMessageListener('setup', function(device_options) {
testDevice = new TestPresentationDevice(device_options);
manager.QueryInterface(Ci.nsIPresentationDeviceListener).addDevice(testDevice);
sendAsyncMessage('setup-complete');
});
let eventHandler = function(evt) {
if (!evt.detail || evt.detail.type !== 'presentation-select-device') {
return;
}
sendAsyncMessage('presentation-select-device', evt.detail);
};
SystemAppProxy.addEventListener('mozChromeEvent', eventHandler);
// need to remove ChromeEvent listener after test finished.
addMessageListener('teardown', function() {
if (testDevice) {
manager.removeDevice(testDevice);
}
SystemAppProxy.removeEventListener('mozChromeEvent', eventHandler);
});
addMessageListener('trigger-device-prompt', function(request_options) {
let request = new TestPresentationRequest(request_options);
prompt.promptDeviceSelection(request);
});
addMessageListener('presentation-select-response', function(detail) {
SystemAppProxy._sendCustomEvent('mozContentEvent', detail);
});

View File

@ -0,0 +1,145 @@
<!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 Presentation Device Selection</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=">Test for Presentation Device Selection</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
var contentEventHandler = null;
var gUrl = SimpleTest.getTestFileURL('presentation_prompt_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
function testSetup() {
info('setup for device selection');
return new Promise(function(resolve, reject) {
let device = {
id: 'test-id',
name: 'test-name',
type: 'test-type',
};
gScript.addMessageListener('setup-complete', function() {
resolve(device);
});
gScript.sendAsyncMessage('setup', device);
});
}
function testSelected(device) {
info('test device selected by user');
return new Promise(function(resolve, reject) {
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
is(detail.origin, request.origin, 'expected origin');
is(detail.requestURL, request.requestURL, 'expected requestURL');
let response = {
id: detail.id,
type: 'presentation-select-result',
deviceId: device.id,
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'select', 'expect device selected');
is(result.device.id, device.id, 'expected device id');
is(result.device.name, device.name, 'expected device name');
is(result.device.type, device.type, 'expected devcie type');
resolve();
});
});
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testSelectedNotExisted() {
info('test selected device doesn\'t exist');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
deviceId: undefined, // simulate device Id that doesn't exist
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function testDenied() {
info('test denial of device selection');
return new Promise(function(resolve, reject) {
gScript.addMessageListener('presentation-select-device', function contentEventHandler(detail) {
gScript.removeMessageListener('presentation-select-device', contentEventHandler);
ok(true, 'receive user prompt for device selection');
let response = {
id: detail.id,
type: 'presentation-select-deny',
};
gScript.sendAsyncMessage('presentation-select-response', response);
gScript.addMessageListener('presentation-select-result', function resultHandler(result) {
gScript.removeMessageListener('presentation-select-result', resultHandler);
is(result.type, 'cancel', 'expect user cancel');
resolve();
});
});
let request = {
origin: 'test-origin',
requestURL: 'test-requestURL',
};
gScript.sendAsyncMessage('trigger-device-prompt', request);
});
}
function runTests() {
testSetup()
.then(testSelected)
.then(testSelectedNotExisted)
.then(testDenied)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown');
gScript.destroy();
SimpleTest.finish();
});
}
window.addEventListener('load', runTests);
</script>
</pre>
</body>
</html>

View File

@ -867,6 +867,7 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/components/InterAppCommUIGlue.js
@BINPATH@/components/SystemMessageGlue.js
@BINPATH@/components/B2GAppMigrator.js
@BINPATH@/components/B2GPresentationDevicePrompt.js
#ifndef MOZ_WIDGET_GONK
@BINPATH@/components/SimulatorScreen.js