mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound
This commit is contained in:
commit
8543987c26
4
CLOBBER
4
CLOBBER
@ -22,4 +22,6 @@
|
||||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
bug 940506: removing idl files appears to break the build without a clobber
|
||||
Bug 1033481 - Use a .mozbuild file rather than a .mk in
|
||||
m/a/tests/background/junit3 -- doesn't clean the classes* directory
|
||||
when moving from in APK to in JAR building.
|
||||
|
@ -11,7 +11,9 @@ module.metadata = {
|
||||
const { Cu } = require("chrome");
|
||||
|
||||
// Passing an empty object as second argument to avoid scope's pollution
|
||||
const { atob, btoa } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
// (devtools loader injects these symbols as global and prevent using
|
||||
// const here)
|
||||
var { atob, btoa } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
function isUTF8(charset) {
|
||||
let type = typeof charset;
|
||||
|
@ -283,17 +283,31 @@ const load = iced(function load(loader, module) {
|
||||
}
|
||||
});
|
||||
|
||||
let sandbox = sandboxes[module.uri] = Sandbox({
|
||||
name: module.uri,
|
||||
prototype: create(globals, descriptors),
|
||||
wantXrays: false,
|
||||
wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : [],
|
||||
invisibleToDebugger: loader.invisibleToDebugger,
|
||||
metadata: {
|
||||
addonID: loader.id,
|
||||
URI: module.uri
|
||||
}
|
||||
});
|
||||
let sandbox;
|
||||
if (loader.sharedGlobalSandbox &&
|
||||
loader.sharedGlobalBlacklist.indexOf(module.id) == -1) {
|
||||
// Create a new object in this sandbox, that will be used as
|
||||
// the scope object for this particular module
|
||||
sandbox = new loader.sharedGlobalSandbox.Object();
|
||||
// Inject all expected globals in the scope object
|
||||
getOwnPropertyNames(globals).forEach(function(name) {
|
||||
descriptors[name] = getOwnPropertyDescriptor(globals, name)
|
||||
});
|
||||
define(sandbox, descriptors);
|
||||
} else {
|
||||
sandbox = Sandbox({
|
||||
name: module.uri,
|
||||
prototype: create(globals, descriptors),
|
||||
wantXrays: false,
|
||||
wantGlobalProperties: module.id == "sdk/indexed-db" ? ["indexedDB"] : [],
|
||||
invisibleToDebugger: loader.invisibleToDebugger,
|
||||
metadata: {
|
||||
addonID: loader.id,
|
||||
URI: module.uri
|
||||
}
|
||||
});
|
||||
}
|
||||
sandboxes[module.uri] = sandbox;
|
||||
|
||||
try {
|
||||
evaluate(sandbox, module.uri);
|
||||
@ -691,8 +705,8 @@ const Loader = iced(function Loader(options) {
|
||||
});
|
||||
|
||||
let {
|
||||
modules, globals, resolve, paths, rootURI,
|
||||
manifest, requireMap, isNative, metadata
|
||||
modules, globals, resolve, paths, rootURI, manifest, requireMap, isNative,
|
||||
metadata, sharedGlobal, sharedGlobalBlacklist
|
||||
} = override({
|
||||
paths: {},
|
||||
modules: {},
|
||||
@ -702,6 +716,7 @@ const Loader = iced(function Loader(options) {
|
||||
resolve: options.isNative ?
|
||||
exports.nodeResolve :
|
||||
exports.resolve,
|
||||
sharedGlobalBlacklist: ["sdk/indexed-db"]
|
||||
}, options);
|
||||
|
||||
// We create an identity object that will be dispatched on an unload
|
||||
@ -738,6 +753,24 @@ const Loader = iced(function Loader(options) {
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
let sharedGlobalSandbox;
|
||||
if (sharedGlobal) {
|
||||
// Create the unique sandbox we will be using for all modules,
|
||||
// so that we prevent creating a new comportment per module.
|
||||
// The side effect is that all modules will share the same
|
||||
// global objects.
|
||||
sharedGlobalSandbox = Sandbox({
|
||||
name: "Addon-SDK",
|
||||
wantXrays: false,
|
||||
wantGlobalProperties: [],
|
||||
invisibleToDebugger: options.invisibleToDebugger || false,
|
||||
metadata: {
|
||||
addonID: options.id,
|
||||
URI: "Addon-SDK"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Loader object is just a representation of a environment
|
||||
// state. We freeze it and mark make it's properties non-enumerable
|
||||
// as they are pure implementation detail that no one should rely upon.
|
||||
@ -748,6 +781,8 @@ const Loader = iced(function Loader(options) {
|
||||
// Map of module objects indexed by module URIs.
|
||||
modules: { enumerable: false, value: modules },
|
||||
metadata: { enumerable: false, value: metadata },
|
||||
sharedGlobalSandbox: { enumerable: false, value: sharedGlobalSandbox },
|
||||
sharedGlobalBlacklist: { enumerable: false, value: sharedGlobalBlacklist },
|
||||
// Map of module sandboxes indexed by module URIs.
|
||||
sandboxes: { enumerable: false, value: {} },
|
||||
resolve: { enumerable: false, value: resolve },
|
||||
|
@ -343,4 +343,27 @@ exports['test console global by default'] = function (assert) {
|
||||
function fakeConsole () {};
|
||||
};
|
||||
|
||||
exports['test shared globals'] = function(assert) {
|
||||
let uri = root + '/fixtures/loader/cycles/';
|
||||
let loader = Loader({ paths: { '': uri }, sharedGlobal: true,
|
||||
sharedGlobalBlacklist: ['b'] });
|
||||
|
||||
let program = main(loader, 'main');
|
||||
|
||||
// As it is hard to verify what is the global of an object
|
||||
// (due to wrappers) we check that we see the `foo` symbol
|
||||
// being manually injected into the shared global object
|
||||
loader.sharedGlobalSandbox.foo = true;
|
||||
|
||||
let m = loader.sandboxes[uri + 'main.js'];
|
||||
let a = loader.sandboxes[uri + 'a.js'];
|
||||
let b = loader.sandboxes[uri + 'b.js'];
|
||||
|
||||
assert.ok(Cu.getGlobalForObject(m).foo, "main is shared");
|
||||
assert.ok(Cu.getGlobalForObject(a).foo, "a is shared");
|
||||
assert.ok(!Cu.getGlobalForObject(b).foo, "b isn't shared");
|
||||
|
||||
unload(loader);
|
||||
}
|
||||
|
||||
require('test').run(exports);
|
||||
|
@ -9,7 +9,6 @@ Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
|
||||
Cu.import('resource://gre/modules/DataStoreChangeNotifier.jsm');
|
||||
Cu.import('resource://gre/modules/AlarmService.jsm');
|
||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
|
||||
Cu.import('resource://gre/modules/NotificationDB.jsm');
|
||||
Cu.import('resource://gre/modules/Payment.jsm');
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="bf9aaf39dd5a6491925a022db167c460f8207d34"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
@ -128,7 +128,7 @@
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
|
||||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="0e31f35a2a77301e91baa8a237aa9e9fa4076084"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="efd87a5797ca40fa2df256630c07e0dfb2f762dc"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c61e5f15fd62888f2c33d7d542b5b65c38102e8b"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="832f4acaf481a19031e479a40b03d9ce5370ddee"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="dd72bacb432efc5135a1f747d00aab91f898bddb"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -23,7 +23,7 @@
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<!-- Stock Android things -->
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
|
||||
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
|
||||
|
@ -19,13 +19,13 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="bf9aaf39dd5a6491925a022db167c460f8207d34"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "3e612bc9b3d79a3fa36d2f38af4202abb0ead68f",
|
||||
"revision": "190172ac413ab6476a6d7df3999950ec756f96a4",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -17,10 +17,10 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -17,12 +17,12 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="740faa5d0060fb218b407cf224330654ddf833a5"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="dde24450450514039bad6d8ab4fcb7e5d4d44e03"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="230f11aff069d90d20fc2dc63b48e9ae3d4bdcd1"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="dc5ca96695cab87b4c2fcd7c9f046ae3415a70a5"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="7f9ec13a30f1b2cc8bdb1a199b7da54b9ab8860f"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ee6e7320bb83409ebd4685fbd87a8ae033704182"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
@ -149,10 +149,11 @@
|
||||
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
|
||||
onsyncfrompreference="return gContentPane.updateButtons('translateButton',
|
||||
'browser.translation.detectLanguage');"/>
|
||||
<label>Übersetzungen von</label>
|
||||
<label>&translation.options.attribution.beforeLogo;</label>
|
||||
<image id="translationAttributionImage" aria-label="Microsoft Translator"
|
||||
onclick="gContentPane.openTranslationProviderAttribution()"
|
||||
src="chrome://browser/content/microsoft-translator-attribution.png"/>
|
||||
<label>&translation.options.attribution.afterLogo;</label>
|
||||
</hbox>
|
||||
<button id="translateButton" label="&translateExceptions.label;"
|
||||
oncommand="gContentPane.showTranslationExceptions();"
|
||||
|
@ -139,11 +139,13 @@
|
||||
label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
|
||||
onsyncfrompreference="return gContentPane.updateButtons('translateButton',
|
||||
'browser.translation.detectLanguage');"/>
|
||||
<label>Übersetzungen von</label>
|
||||
<label>&translation.options.attribution.beforeLogo;</label>
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<image id="translationAttributionImage" aria-label="Microsoft Translator"
|
||||
onclick="gContentPane.openTranslationProviderAttribution()"
|
||||
src="chrome://browser/content/microsoft-translator-attribution.png"/>
|
||||
<separator orient="vertical" class="thin"/>
|
||||
<label>&translation.options.attribution.afterLogo;</label>
|
||||
</hbox>
|
||||
<button id="translateButton" label="&translateExceptions.label;"
|
||||
oncommand="gContentPane.showTranslationExceptions();"
|
||||
|
@ -113,9 +113,10 @@
|
||||
accesskey="&translation.options.preferences.accesskey;"/>
|
||||
<xul:menuitem class="translation-attribution subviewbutton panel-subview-footer"
|
||||
oncommand="document.getBindingParent(this).openProviderAttribution();">
|
||||
<xul:label>Übersetzungen von</xul:label>
|
||||
<xul:label>&translation.options.attribution.beforeLogo;</xul:label>
|
||||
<xul:image src="chrome://browser/content/microsoft-translator-attribution.png"
|
||||
aria-label="Microsoft Translator"/>
|
||||
<xul:label>&translation.options.attribution.afterLogo;</xul:label>
|
||||
</xul:menuitem>
|
||||
</xul:menupopup>
|
||||
</xul:button>
|
||||
|
@ -14,14 +14,13 @@ const { indexedDB } = require("sdk/indexed-db");
|
||||
* a unique `location` object.
|
||||
*/
|
||||
|
||||
const global = this;
|
||||
const IDB = {
|
||||
_db: null,
|
||||
|
||||
open: function () {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let request = global.indexedDB.open("AppProjects", 5);
|
||||
let request = indexedDB.open("AppProjects", 5);
|
||||
request.onerror = function(event) {
|
||||
deferred.reject("Unable to open AppProjects indexedDB. " +
|
||||
"Error code: " + event.target.errorCode);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
const {Cu, Cc, Ci} = require("chrome");
|
||||
const Services = require("Services");
|
||||
const promise = require("promise");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
|
||||
|
||||
|
@ -10,6 +10,7 @@ const { EventTarget } = require("sdk/event/target");
|
||||
const { emit } = require("sdk/event/core");
|
||||
const { EditorTypeForResource } = require("projecteditor/editors");
|
||||
const NetworkHelper = require("devtools/toolkit/webconsole/network-helper");
|
||||
const promise = require("promise");
|
||||
|
||||
/**
|
||||
* The Shell is the object that manages the editor for a single resource.
|
||||
|
@ -65,6 +65,14 @@ function testGraph(graph) {
|
||||
"The mapped selection's min value is correct (5).");
|
||||
is(graph.getMappedSelection().max, max,
|
||||
"The mapped selection's max value is correct (6).");
|
||||
|
||||
graph.setSelection({ start: graph.width + 100, end: -100 });
|
||||
min = map(0, 0, graph.width, 112, 4180);
|
||||
max = map(graph.width, 0, graph.width, 112, 4180);
|
||||
is(graph.getMappedSelection().min, min,
|
||||
"The mapped selection's min value is correct (7).");
|
||||
is(graph.getMappedSelection().max, max,
|
||||
"The mapped selection's max value is correct (8).");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,9 +136,11 @@ GraphSelectionResizer.prototype = {
|
||||
this.AbstractCanvasGraph = function(parent, name, sharpness) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._ready = promise.defer();
|
||||
this._parent = parent;
|
||||
this._ready = promise.defer();
|
||||
|
||||
this._uid = "canvas-graph-" + Date.now();
|
||||
this._renderTargets = new Map();
|
||||
|
||||
AbstractCanvasGraph.createIframe(GRAPH_SRC, parent, iframe => {
|
||||
this._iframe = iframe;
|
||||
@ -231,7 +233,9 @@ AbstractCanvasGraph.prototype = {
|
||||
|
||||
this._data = null;
|
||||
this._regions = null;
|
||||
this._cachedBackgroundImage = null;
|
||||
this._cachedGraphImage = null;
|
||||
this._renderTargets.clear();
|
||||
gCachedStripePattern.clear();
|
||||
},
|
||||
|
||||
@ -254,6 +258,14 @@ AbstractCanvasGraph.prototype = {
|
||||
fixedWidth: null,
|
||||
fixedHeight: null,
|
||||
|
||||
/**
|
||||
* Optionally builds and caches a background image for this graph.
|
||||
* Inheriting classes may override this method.
|
||||
*/
|
||||
buildBackgroundImage: function() {
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds and caches a graph image, based on the data source supplied
|
||||
* in `setData`. The graph image is not rebuilt on each frame, but
|
||||
@ -278,6 +290,7 @@ AbstractCanvasGraph.prototype = {
|
||||
*/
|
||||
setData: function(data) {
|
||||
this._data = data;
|
||||
this._cachedBackgroundImage = this.buildBackgroundImage();
|
||||
this._cachedGraphImage = this.buildGraphImage();
|
||||
this._shouldRedraw = true;
|
||||
},
|
||||
@ -392,7 +405,7 @@ AbstractCanvasGraph.prototype = {
|
||||
*/
|
||||
getMappedSelection: function(unpack = e => e.delta) {
|
||||
if (!this.hasData() || !this.hasSelection()) {
|
||||
return { start: null, end: null };
|
||||
return { min: null, max: null };
|
||||
}
|
||||
let selection = this.getSelection();
|
||||
let totalTicks = this._data.length;
|
||||
@ -401,8 +414,9 @@ AbstractCanvasGraph.prototype = {
|
||||
|
||||
// The selection's start and end values are not guaranteed to be ascending.
|
||||
// This can happen, for example, when click & dragging from right to left.
|
||||
let min = Math.min(selection.start, selection.end);
|
||||
let max = Math.max(selection.start, selection.end);
|
||||
// Also make sure that the selection bounds fit inside the canvas bounds.
|
||||
let min = Math.max(Math.min(selection.start, selection.end), 0);
|
||||
let max = Math.min(Math.max(selection.start, selection.end), this._width);
|
||||
min = map(min, 0, this._width, firstTick, lastTick);
|
||||
max = map(max, 0, this._width, firstTick, lastTick);
|
||||
|
||||
@ -564,10 +578,11 @@ AbstractCanvasGraph.prototype = {
|
||||
this._width = this._canvas.width = bounds.width * this._pixelRatio;
|
||||
this._height = this._canvas.height = bounds.height * this._pixelRatio;
|
||||
|
||||
if (this._data) {
|
||||
if (this.hasData()) {
|
||||
this._cachedBackgroundImage = this.buildBackgroundImage();
|
||||
this._cachedGraphImage = this.buildGraphImage();
|
||||
}
|
||||
if (this._regions) {
|
||||
if (this.hasRegions()) {
|
||||
this._bakeRegions(this._regions, this._cachedGraphImage);
|
||||
}
|
||||
|
||||
@ -575,6 +590,38 @@ AbstractCanvasGraph.prototype = {
|
||||
this.emit("refresh");
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a canvas with the specified name, for this graph.
|
||||
*
|
||||
* If it doesn't exist yet, it will be created, otherwise the cached instance
|
||||
* will be cleared and returned.
|
||||
*
|
||||
* @param string name
|
||||
* The canvas name.
|
||||
* @param number width, height [optional]
|
||||
* A custom width and height for the canvas. Defaults to this graph's
|
||||
* container canvas width and height.
|
||||
*/
|
||||
_getNamedCanvas: function(name, width = this._width, height = this._height) {
|
||||
let cachedRenderTarget = this._renderTargets.get(name);
|
||||
if (cachedRenderTarget) {
|
||||
let { canvas, ctx } = cachedRenderTarget;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
return cachedRenderTarget;
|
||||
}
|
||||
|
||||
let canvas = this._document.createElementNS(HTML_NS, "canvas");
|
||||
let ctx = canvas.getContext("2d");
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
let renderTarget = { canvas: canvas, ctx: ctx };
|
||||
this._renderTargets.set(name, renderTarget);
|
||||
return renderTarget;
|
||||
},
|
||||
|
||||
/**
|
||||
* The contents of this graph are redrawn only when something changed,
|
||||
* like the data source, or the selection bounds etc. This flag tracks
|
||||
@ -598,14 +645,16 @@ AbstractCanvasGraph.prototype = {
|
||||
if (!this._shouldRedraw) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ctx = this._ctx;
|
||||
ctx.clearRect(0, 0, this._width, this._height);
|
||||
|
||||
// Draw the graph underneath the cursor and selection.
|
||||
if (this.hasData()) {
|
||||
if (this._cachedBackgroundImage) {
|
||||
ctx.drawImage(this._cachedBackgroundImage, 0, 0, this._width, this._height);
|
||||
}
|
||||
if (this._cachedGraphImage) {
|
||||
ctx.drawImage(this._cachedGraphImage, 0, 0, this._width, this._height);
|
||||
}
|
||||
|
||||
if (this.hasCursor()) {
|
||||
this._drawCliphead();
|
||||
}
|
||||
@ -1009,7 +1058,7 @@ AbstractCanvasGraph.prototype = {
|
||||
* Listener for the "resize" event on the graph's parent node.
|
||||
*/
|
||||
_onResize: function() {
|
||||
if (this._cachedGraphImage) {
|
||||
if (this.hasData()) {
|
||||
setNamedTimeout(this._uid, GRAPH_RESIZE_EVENTS_DRAIN, this.refresh);
|
||||
}
|
||||
}
|
||||
@ -1074,10 +1123,9 @@ LineGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
* @see AbstractCanvasGraph.prototype.buildGraphImage
|
||||
*/
|
||||
buildGraphImage: function() {
|
||||
let canvas = this._document.createElementNS(HTML_NS, "canvas");
|
||||
let ctx = canvas.getContext("2d");
|
||||
let width = canvas.width = this._width;
|
||||
let height = canvas.height = this._height;
|
||||
let { canvas, ctx } = this._getNamedCanvas("line-graph-data");
|
||||
let width = this._width;
|
||||
let height = this._height;
|
||||
|
||||
let totalTicks = this._data.length;
|
||||
let firstTick = this._data[0].delta;
|
||||
@ -1334,6 +1382,24 @@ BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
*/
|
||||
minBlocksHeight: BAR_GRAPH_MIN_BLOCKS_HEIGHT,
|
||||
|
||||
/**
|
||||
* Renders the graph's background.
|
||||
* @see AbstractCanvasGraph.prototype.buildBackgroundImage
|
||||
*/
|
||||
buildBackgroundImage: function() {
|
||||
let { canvas, ctx } = this._getNamedCanvas("bar-graph-background");
|
||||
let width = this._width;
|
||||
let height = this._height;
|
||||
|
||||
let gradient = ctx.createLinearGradient(0, 0, 0, height);
|
||||
gradient.addColorStop(0, BAR_GRAPH_BACKGROUND_GRADIENT_START);
|
||||
gradient.addColorStop(1, BAR_GRAPH_BACKGROUND_GRADIENT_END);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
return canvas;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders the graph on a canvas.
|
||||
* @see AbstractCanvasGraph.prototype.buildGraphImage
|
||||
@ -1342,11 +1408,9 @@ BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
if (!this.format || !this.format.length) {
|
||||
throw "The graph format traits are mandatory to style the data source.";
|
||||
}
|
||||
|
||||
let canvas = this._document.createElementNS(HTML_NS, "canvas");
|
||||
let ctx = canvas.getContext("2d");
|
||||
let width = canvas.width = this._width;
|
||||
let height = canvas.height = this._height;
|
||||
let { canvas, ctx } = this._getNamedCanvas("bar-graph-data");
|
||||
let width = this._width;
|
||||
let height = this._height;
|
||||
|
||||
let totalTypes = this.format.length;
|
||||
let totalTicks = this._data.length;
|
||||
@ -1364,14 +1428,6 @@ BarGraphWidget.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||
minBarsWidth: minBarsWidth
|
||||
}) * BAR_GRAPH_DAMPEN_VALUES;
|
||||
|
||||
// Draw the background.
|
||||
|
||||
let gradient = ctx.createLinearGradient(0, 0, 0, height);
|
||||
gradient.addColorStop(0, BAR_GRAPH_BACKGROUND_GRADIENT_START);
|
||||
gradient.addColorStop(1, BAR_GRAPH_BACKGROUND_GRADIENT_END);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
// Draw the graph.
|
||||
|
||||
// Iterate over the blocks, then the bars, to draw all rectangles of
|
||||
|
@ -9,6 +9,7 @@ const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
|
||||
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
|
||||
const {DebuggerServer} = require("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
const discovery = require("devtools/toolkit/discovery/discovery");
|
||||
const promise = require("promise");
|
||||
|
||||
const Strings = Services.strings.createBundle("chrome://webide/content/webide.properties");
|
||||
|
||||
|
@ -32,3 +32,13 @@
|
||||
<!ENTITY translateWebPages.accesskey "T">
|
||||
<!ENTITY translateExceptions.label "Exceptions…">
|
||||
<!ENTITY translateExceptions.accesskey "x">
|
||||
|
||||
<!-- LOCALIZATION NOTE (translation.options.attribution.beforeLogo,
|
||||
- translation.options.attribution.afterLogo):
|
||||
- These 2 strings are displayed before and after a 'Microsoft Translator'
|
||||
- logo.
|
||||
- The translations for these strings should match the translations in
|
||||
- browser/translation.dtd
|
||||
-->
|
||||
<!ENTITY translation.options.attribution.beforeLogo "Translations by">
|
||||
<!ENTITY translation.options.attribution.afterLogo "">
|
||||
|
@ -56,3 +56,11 @@
|
||||
<!ENTITY translation.options.neverForSite.accesskey "e">
|
||||
<!ENTITY translation.options.preferences.label "Translation preferences">
|
||||
<!ENTITY translation.options.preferences.accesskey "T">
|
||||
|
||||
<!-- LOCALIZATION NOTE (translation.options.attribution.beforeLogo,
|
||||
- translation.options.attribution.afterLogo):
|
||||
- These 2 strings are displayed before and after a 'Microsoft Translator'
|
||||
- logo.
|
||||
-->
|
||||
<!ENTITY translation.options.attribution.beforeLogo "Translations by">
|
||||
<!ENTITY translation.options.attribution.afterLogo "">
|
||||
|
@ -3627,6 +3627,7 @@ notification[value="translation"] {
|
||||
}
|
||||
|
||||
button.translate-infobar-element {
|
||||
background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.1)) repeat scroll 0% 0% padding-box transparent;
|
||||
color: #333333;
|
||||
border: 1px solid;
|
||||
border-color: rgba(23, 51, 78, 0.15) rgba(23, 51, 78, 0.17) rgba(23, 51, 78, 0.2);
|
||||
@ -3650,6 +3651,7 @@ label.translate-infobar-element {
|
||||
}
|
||||
|
||||
button.translate-infobar-element:hover {
|
||||
background: #f0f0f0;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.1) inset, 0 0 0 1px hsla(0,0%,100%,.05) inset, 0 1px 0 hsla(210,54%,20%,.01), 0 0 4px hsla(206,100%,20%,.1);
|
||||
}
|
||||
|
||||
@ -3660,7 +3662,7 @@ button.translate-infobar-element:active {
|
||||
|
||||
button.translate-infobar-element[anonid="translate"] {
|
||||
color: #ffffff;
|
||||
background-image: linear-gradient(#4cb1ff, #1793e5);
|
||||
background: linear-gradient(#4cb1ff, #1793e5);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset, 0 0 0 1px hsla(0,0%,100%,.1) inset, 0 1px 0 hsla(210,54%,20%,.03);
|
||||
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2);
|
||||
padding: 0 1.1em !important;;
|
||||
@ -3668,35 +3670,28 @@ button.translate-infobar-element[anonid="translate"] {
|
||||
|
||||
button.translate-infobar-element[anonid="translate"]:hover {
|
||||
background-image: linear-gradient(#66bdff, #0d9eff);
|
||||
}
|
||||
|
||||
button.translate-infobar-element[anonid="notNow"] {
|
||||
background: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.1)) repeat scroll 0% 0% padding-box transparent;
|
||||
}
|
||||
|
||||
button.translate-infobar-element[anonid="notNow"]:hover {
|
||||
background: #f0f0f0;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset, 0 0 0 1px hsla(0,0%,100%,.1) inset, 0 1px 0 hsla(210,54%,20%,.03), 0 0 4px hsla(206,100%,20%,.2);
|
||||
}
|
||||
|
||||
button.translate-infobar-element.options-menu-button {
|
||||
-moz-padding-start: 0.5em !important;
|
||||
-moz-padding-end: 0.3em !important;
|
||||
-moz-padding-end: 0em !important;
|
||||
}
|
||||
|
||||
button.translate-infobar-element.options-menu-button > .button-box > .button-menu-dropmarker {
|
||||
display: -moz-box;
|
||||
list-style-image: url("chrome://browser/skin/toolbarbutton-dropmarker.png");
|
||||
list-style-image: url("chrome://global/skin/icons/glyph-dropdown.png");
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.25dppx) {
|
||||
@media (min-resolution: 2dppx) {
|
||||
button.translate-infobar-element.options-menu-button > .button-box > .button-menu-dropmarker {
|
||||
list-style-image: url("chrome://browser/skin/toolbarbutton-dropmarker@2x.png");
|
||||
list-style-image: url("chrome://global/skin/icons/glyph-dropdown@2x.png");
|
||||
}
|
||||
|
||||
button.translate-infobar-element.options-menu-button > .button-box > .button-menu-dropmarker > .dropmarker-icon {
|
||||
width: 7px;
|
||||
width: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3709,6 +3704,7 @@ menulist.translate-infobar-element {
|
||||
background-image: linear-gradient(#FFFFFF, rgba(255,255,255,0.1));
|
||||
color: #333333;
|
||||
padding: 0;
|
||||
min-height: 22px !important;
|
||||
}
|
||||
|
||||
menulist.translate-infobar-element > .menulist-label-box {
|
||||
@ -3719,7 +3715,8 @@ menulist.translate-infobar-element > .menulist-label-box {
|
||||
}
|
||||
|
||||
menulist.translate-infobar-element:hover {
|
||||
background-image: linear-gradient(#FFFFFF, rgba(255,255,255,0.6));
|
||||
background: #f0f0f0;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.1) inset, 0 0 0 1px hsla(0,0%,100%,.05) inset, 0 1px 0 hsla(210,54%,20%,.01), 0 0 4px hsla(206,100%,20%,.1);
|
||||
}
|
||||
|
||||
menulist.translate-infobar-element[open="true"] {
|
||||
@ -3729,7 +3726,17 @@ menulist.translate-infobar-element[open="true"] {
|
||||
|
||||
menulist.translate-infobar-element > .menulist-dropmarker {
|
||||
display: -moz-box;
|
||||
list-style-image: url("chrome://global/skin/icons/menulist-dropmarker.png");
|
||||
list-style-image: url("chrome://global/skin/icons/glyph-dropdown.png");
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
menulist.translate-infobar-element > .menulist-dropmarker {
|
||||
list-style-image: url("chrome://global/skin/icons/glyph-dropdown@2x.png");
|
||||
}
|
||||
|
||||
menulist.translate-infobar-element > .menulist-dropmarker > .dropmarker-icon {
|
||||
width: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
14
configure.in
14
configure.in
@ -3895,6 +3895,7 @@ MOZ_SAFE_BROWSING=
|
||||
MOZ_HELP_VIEWER=
|
||||
MOZ_SPELLCHECK=1
|
||||
MOZ_ANDROID_OMTC=
|
||||
MOZ_NATIVE_CASTING=1
|
||||
MOZ_TOOLKIT_SEARCH=1
|
||||
MOZ_UI_LOCALE=en-US
|
||||
MOZ_UNIVERSALCHARDET=1
|
||||
@ -7673,6 +7674,19 @@ else
|
||||
OMNIJAR_NAME=omni.ja
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = --disable-native-casting
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(native-casting,
|
||||
[ --disable-native-casting Disable native casting devices],
|
||||
MOZ_NATIVE_CASTING=,
|
||||
MOZ_NATIVE_CASTING=1)
|
||||
if test "$MOZ_NATIVE_CASTING"; then
|
||||
AC_DEFINE(MOZ_NATIVE_CASTING)
|
||||
fi
|
||||
|
||||
AC_SUBST(MOZ_NATIVE_CASTING)
|
||||
AC_SUBST(OMNIJAR_NAME)
|
||||
AC_SUBST(MOZ_OMNIJAR)
|
||||
AC_SUBST(MOZ_PACKAGER_FORMAT)
|
||||
|
@ -167,7 +167,7 @@ this.PermissionsInstaller = {
|
||||
// If it's not a system update, then we should keep the prompt
|
||||
// permissions that have been granted or denied previously.
|
||||
permValue =
|
||||
PermissionSettingsModule.getPermission(permName,
|
||||
PermissionSettingsModule.getPermission(expandedPermNames[idx],
|
||||
aApp.manifestURL,
|
||||
aApp.origin,
|
||||
false);
|
||||
|
@ -163,9 +163,15 @@ this.PermissionsTable = { geolocation: {
|
||||
},
|
||||
attention: {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"moz-attention": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
substitute: ["attention"]
|
||||
},
|
||||
"webapps-manage": {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
@ -267,14 +273,26 @@ this.PermissionsTable = { geolocation: {
|
||||
},
|
||||
"audio-channel-telephony": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"moz-audio-channel-telephony": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
substitute: ["audio-channel-telephony"]
|
||||
},
|
||||
"audio-channel-ringer": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"moz-audio-channel-ringer": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
substitute: ["audio-channel-ringer"]
|
||||
},
|
||||
"audio-channel-publicnotification": {
|
||||
app: DENY_ACTION,
|
||||
privileged: DENY_ACTION,
|
||||
@ -340,6 +358,15 @@ this.PermissionsTable = { geolocation: {
|
||||
app: DENY_ACTION,
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: PROMPT_ACTION
|
||||
},
|
||||
// This permission doesn't actually grant access to
|
||||
// anything. It exists only to check the correctness
|
||||
// of web prompt composed permissions in tests.
|
||||
"test-permission": {
|
||||
app: PROMPT_ACTION,
|
||||
privileged: PROMPT_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
access: ["read", "write", "create"]
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
"geolocation": {},
|
||||
"audio-capture": {},
|
||||
"video-capture": {},
|
||||
"test-permission": {"access": "readonly"},
|
||||
"downloads": {}
|
||||
},
|
||||
"launch_path": "tests/dom/apps/tests/file_packaged_app.sjs",
|
||||
|
@ -95,11 +95,13 @@ var initialPermissionState = {
|
||||
"geolocation": "prompt",
|
||||
"audio-capture": "prompt",
|
||||
"video-capture": "prompt",
|
||||
"test-permission-read": "prompt",
|
||||
"downloads": "deny"
|
||||
}
|
||||
|
||||
var permissionsToSet = {
|
||||
"geolocation": "allow",
|
||||
"test-permission-read": "allow",
|
||||
"audio-capture": "deny"
|
||||
}
|
||||
|
||||
@ -107,6 +109,7 @@ var permissionsToCheck = {
|
||||
"geolocation": "allow",
|
||||
"audio-capture": "deny",
|
||||
"video-capture": "prompt",
|
||||
"test-permission-read": "allow",
|
||||
"downloads": "deny"
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/dom/PContentPermission.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/PContentPermissionRequestParent.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
@ -358,3 +359,129 @@ nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
|
||||
mParent = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// RemotePermissionRequest
|
||||
|
||||
// static
|
||||
uint32_t
|
||||
RemotePermissionRequest::ConvertArrayToPermissionRequest(
|
||||
nsIArray* aSrcArray,
|
||||
nsTArray<PermissionRequest>& aDesArray)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
aSrcArray->GetLength(&len);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
|
||||
nsAutoCString type;
|
||||
nsAutoCString access;
|
||||
cpt->GetType(type);
|
||||
cpt->GetAccess(access);
|
||||
|
||||
nsCOMPtr<nsIArray> optionArray;
|
||||
cpt->GetOptions(getter_AddRefs(optionArray));
|
||||
uint32_t optionsLength = 0;
|
||||
if (optionArray) {
|
||||
optionArray->GetLength(&optionsLength);
|
||||
}
|
||||
nsTArray<nsString> options;
|
||||
for (uint32_t j = 0; j < optionsLength; ++j) {
|
||||
nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j);
|
||||
if (isupportsString) {
|
||||
nsString option;
|
||||
isupportsString->GetData(option);
|
||||
options.AppendElement(option);
|
||||
}
|
||||
}
|
||||
|
||||
aDesArray.AppendElement(PermissionRequest(type, access, options));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(RemotePermissionRequest, nsIContentPermissionRequest)
|
||||
|
||||
RemotePermissionRequest::RemotePermissionRequest(
|
||||
nsIContentPermissionRequest* aRequest,
|
||||
nsPIDOMWindow* aWindow)
|
||||
: mRequest(aRequest)
|
||||
, mWindow(aWindow)
|
||||
{
|
||||
}
|
||||
|
||||
// nsIContentPermissionRequest methods
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
{
|
||||
NS_ASSERTION(mRequest, "We need a request");
|
||||
return mRequest->GetTypes(aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
|
||||
|
||||
return mRequest->GetPrincipal(aRequestingPrincipal);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingWindow);
|
||||
|
||||
return mRequest->GetWindow(aRequestingWindow);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequestingElement);
|
||||
*aRequestingElement = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::Cancel()
|
||||
{
|
||||
NS_ASSERTION(mRequest, "We need a request");
|
||||
return mRequest->Cancel();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RemotePermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
{
|
||||
NS_ASSERTION(mRequest, "We need a request");
|
||||
return mRequest->Allow(aChoices);
|
||||
}
|
||||
|
||||
// PCOMContentPermissionRequestChild
|
||||
bool
|
||||
RemotePermissionRequest::Recv__delete__(const bool& aAllow,
|
||||
const nsTArray<PermissionChoice>& aChoices)
|
||||
{
|
||||
if (aAllow && mWindow->IsCurrentInnerWindow()) {
|
||||
// Convert choices to a JS val if any.
|
||||
// {"type1": "choice1", "type2": "choiceA"}
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mWindow))) {
|
||||
return true; // This is not an IPC error.
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> obj(cx);
|
||||
obj = JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr());
|
||||
for (uint32_t i = 0; i < aChoices.Length(); ++i) {
|
||||
const nsString& choice = aChoices[i].choice();
|
||||
const nsCString& type = aChoices[i].type();
|
||||
JS::Rooted<JSString*> jChoice(cx, JS_NewUCStringCopyN(cx, choice.get(), choice.Length()));
|
||||
JS::Rooted<JS::Value> vChoice(cx, StringValue(jChoice));
|
||||
if (!JS_SetProperty(cx, obj, type.get(), vChoice)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
JS::RootedValue val(cx, JS::ObjectValue(*obj));
|
||||
(void) Allow(val);
|
||||
} else {
|
||||
(void) Cancel();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -8,7 +8,9 @@
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "PCOMContentPermissionRequestChild.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
class nsContentPermissionRequestProxy;
|
||||
|
||||
// Forward declare IPC::Principal here which is defined in
|
||||
@ -83,4 +85,32 @@ class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
|
||||
nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
|
||||
};
|
||||
|
||||
/**
|
||||
* RemotePermissionRequest will send a prompt ipdl request to b2g process.
|
||||
*/
|
||||
class RemotePermissionRequest : public nsIContentPermissionRequest
|
||||
, public PCOMContentPermissionRequestChild
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
|
||||
nsPIDOMWindow* aWindow);
|
||||
|
||||
// It will be called when prompt dismissed.
|
||||
virtual bool Recv__delete__(const bool &aAllow,
|
||||
const nsTArray<PermissionChoice>& aChoices) MOZ_OVERRIDE;
|
||||
virtual void IPDLRelease() MOZ_OVERRIDE { Release(); }
|
||||
|
||||
static uint32_t ConvertArrayToPermissionRequest(
|
||||
nsIArray* aSrcArray,
|
||||
nsTArray<PermissionRequest>& aDesArray);
|
||||
private:
|
||||
virtual ~RemotePermissionRequest() {}
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequest> mRequest;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
#endif // nsContentPermissionHelper_h
|
||||
|
@ -71,6 +71,7 @@
|
||||
#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
|
||||
#include "mozilla/dom/MutableFile.h"
|
||||
#include "mozilla/dom/MutableFileBinding.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/quota/PersistenceType.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "nsDOMBlobBuilder.h"
|
||||
@ -89,6 +90,7 @@
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIContentIterator.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#undef GetClassName
|
||||
@ -3746,6 +3748,49 @@ nsDOMWindowUtils::XpconnectArgument(nsIDOMWindowUtils* aThis)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
nsRefPtr<RemotePermissionRequest> req =
|
||||
new RemotePermissionRequest(aRequest, window->GetCurrentInnerWindow());
|
||||
|
||||
// for content process
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
MOZ_ASSERT(NS_IsMainThread()); // IPC can only be execute on main thread.
|
||||
|
||||
dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell());
|
||||
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIArray> typeArray;
|
||||
nsresult rv = req->GetTypes(getter_AddRefs(typeArray));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
RemotePermissionRequest::ConvertArrayToPermissionRequest(typeArray, permArray);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = req->GetPrincipal(getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
req->AddRef();
|
||||
child->SendPContentPermissionRequestConstructor(req,
|
||||
permArray,
|
||||
IPC::Principal(principal));
|
||||
|
||||
req->Sendprompt();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// for chrome process
|
||||
nsCOMPtr<nsIContentPermissionPrompt> prompt =
|
||||
do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
|
||||
if (prompt) {
|
||||
prompt->Prompt(req);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
|
||||
|
@ -342,7 +342,7 @@ function setBluetoothEnabled(aEnabled) {
|
||||
/**
|
||||
* Wait for one named BluetoothManager event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
@ -367,7 +367,7 @@ function waitForManagerEvent(aEventName) {
|
||||
/**
|
||||
* Wait for one named BluetoothAdapter event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
@ -391,6 +391,118 @@ function waitForAdapterEvent(aAdapter, aEventName) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for 'onattributechanged' events for state changes of BluetoothAdapter
|
||||
* with specified order.
|
||||
*
|
||||
* Resolve if those expected events occur in order. Never reject.
|
||||
*
|
||||
* Fulfill params: an array which contains every changed attributes during
|
||||
* the waiting.
|
||||
*
|
||||
* @param aAdapter
|
||||
* The BluetoothAdapter you want to use.
|
||||
* @param aStateChangesInOrder
|
||||
* An array which contains an expected order of BluetoothAdapterState.
|
||||
* Example 1: [enabling, enabled]
|
||||
* Example 2: [disabling, disabled]
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForAdapterStateChanged(aAdapter, aStateChangesInOrder) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let stateIndex = 0;
|
||||
let prevStateIndex = 0;
|
||||
let statesArray = [];
|
||||
let changedAttrs = [];
|
||||
aAdapter.onattributechanged = function(aEvent) {
|
||||
for (let i in aEvent.attrs) {
|
||||
changedAttrs.push(aEvent.attrs[i]);
|
||||
switch (aEvent.attrs[i]) {
|
||||
case "state":
|
||||
log(" 'state' changed to " + aAdapter.state);
|
||||
|
||||
// Received state change order may differ from expected one even though
|
||||
// state changes in expected order, because the value of state may change
|
||||
// again before we receive prior 'onattributechanged' event.
|
||||
//
|
||||
// For example, expected state change order [A,B,C] may result in
|
||||
// received ones:
|
||||
// - [A,C,C] if state becomes C before we receive 2nd 'onattributechanged'
|
||||
// - [B,B,C] if state becomes B before we receive 1st 'onattributechanged'
|
||||
// - [C,C,C] if state becomes C before we receive 1st 'onattributechanged'
|
||||
// - [A,B,C] if all 'onattributechanged' are received in perfect timing
|
||||
//
|
||||
// As a result, we ensure only following conditions instead of exactly
|
||||
// matching received and expected state change order.
|
||||
// - Received state change order never reverse expected one. For example,
|
||||
// [B,A,C] should never occur with expected state change order [A,B,C].
|
||||
// - The changed value of state in received state change order never
|
||||
// appears later than that in expected one. For example, [A,A,C] should
|
||||
// never occur with expected state change order [A,B,C].
|
||||
let stateIndex = aStateChangesInOrder.indexOf(aAdapter.state);
|
||||
if (stateIndex >= prevStateIndex && stateIndex + 1 > statesArray.length) {
|
||||
statesArray.push(aAdapter.state);
|
||||
prevStateIndex = stateIndex;
|
||||
|
||||
if (statesArray.length == aStateChangesInOrder.length) {
|
||||
aAdapter.onattributechanged = null;
|
||||
ok(true, "BluetoothAdapter event 'onattributechanged' got.");
|
||||
deferred.resolve(changedAttrs);
|
||||
}
|
||||
} else {
|
||||
ok(false, "The order of 'onattributechanged' events is unexpected.");
|
||||
}
|
||||
|
||||
break;
|
||||
case "name":
|
||||
log(" 'name' changed to " + aAdapter.name);
|
||||
if (aAdapter.state == "enabling") {
|
||||
isnot(aAdapter.name, "", "adapter.name");
|
||||
}
|
||||
else if (aAdapter.state == "disabling") {
|
||||
is(aAdapter.name, "", "adapter.name");
|
||||
}
|
||||
break;
|
||||
case "address":
|
||||
log(" 'address' changed to " + aAdapter.address);
|
||||
if (aAdapter.state == "enabling") {
|
||||
isnot(aAdapter.address, "", "adapter.address");
|
||||
}
|
||||
else if (aAdapter.state == "disabling") {
|
||||
is(aAdapter.address, "", "adapter.address");
|
||||
}
|
||||
break;
|
||||
case "discoverable":
|
||||
log(" 'discoverable' changed to " + aAdapter.discoverable);
|
||||
if (aAdapter.state == "enabling") {
|
||||
is(aAdapter.discoverable, true, "adapter.discoverable");
|
||||
}
|
||||
else if (aAdapter.state == "disabling") {
|
||||
is(aAdapter.discoverable, false, "adapter.discoverable");
|
||||
}
|
||||
break;
|
||||
case "discovering":
|
||||
log(" 'discovering' changed to " + aAdapter.discovering);
|
||||
if (aAdapter.state == "enabling") {
|
||||
is(aAdapter.discovering, true, "adapter.discovering");
|
||||
}
|
||||
else if (aAdapter.state == "disabling") {
|
||||
is(aAdapter.discovering, false, "adapter.discovering");
|
||||
}
|
||||
break;
|
||||
case "unknown":
|
||||
default:
|
||||
ok(false, "Unknown attribute '" + aEvent.attrs[i] + "' changed." );
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush permission settings and call |finish()|.
|
||||
*/
|
||||
@ -417,7 +529,7 @@ function startBluetoothTestBase(aPermissions, aTestCaseMain) {
|
||||
}
|
||||
|
||||
function startBluetoothTest(aReenable, aTestCaseMain) {
|
||||
startBluetoothTestBase(["settings-read", "settings-write"], function() {
|
||||
startBluetoothTestBase([], function() {
|
||||
let origEnabled, needEnable;
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
|
@ -4,3 +4,4 @@ browser = false
|
||||
qemu = false
|
||||
|
||||
[test_dom_BluetoothManager_API2.js]
|
||||
[test_dom_BluetoothAdapter_enable_API2.js]
|
||||
|
@ -0,0 +1,76 @@
|
||||
/* 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/. */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Test Purpose:
|
||||
// To verify that enable/disable process of BluetoothAdapter is correct.
|
||||
//
|
||||
// Test Procedure:
|
||||
// [0] Set Bluetooth permission and enable default adapter.
|
||||
// [1] Disable Bluetooth and check the correctness of 'onattributechanged'.
|
||||
// [2] Enable Bluetooth and check the correctness of 'onattributechanged'.
|
||||
//
|
||||
// Test Coverage:
|
||||
// - BluetoothAdapter.enable()
|
||||
// - BluetoothAdapter.disable()
|
||||
// - BluetoothAdapter.onattributechanged()
|
||||
// - BluetoothAdapter.address
|
||||
// - BluetoothAdapter.state
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
startBluetoothTest(true, function testCaseMain(aAdapter) {
|
||||
log("Checking adapter attributes ...");
|
||||
|
||||
is(aAdapter.state, "enabled", "adapter.state");
|
||||
isnot(aAdapter.address, "", "adapter.address");
|
||||
|
||||
// Since adapter has just been re-enabled, these properties should be 'false'.
|
||||
is(aAdapter.discovering, false, "adapter.discovering");
|
||||
is(aAdapter.discoverable, false, "adapter.discoverable");
|
||||
// TODO: Check the correctness of name and address if we use emulator.
|
||||
// is(aAdapter.name, EMULATOR_NAME, "adapter.name");
|
||||
// is(aAdapter.address, EMULATOR_ADDRESS, "adapter.address");
|
||||
|
||||
log(" adapter.address: " + aAdapter.address);
|
||||
log(" adapter.name: " + aAdapter.name);
|
||||
|
||||
let originalAddr = aAdapter.address;
|
||||
let originalName = aAdapter.name;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(function() {
|
||||
log("[1] Disable Bluetooth and check the correctness of 'onattributechanged'");
|
||||
let promises = [];
|
||||
promises.push(waitForAdapterStateChanged(aAdapter, ["disabling", "disabled"]));
|
||||
promises.push(aAdapter.disable());
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function(aResults) {
|
||||
isnot(aResults[0].indexOf("address"), -1, "Indicator of 'address' changed event");
|
||||
if (originalName != "") {
|
||||
isnot(aResults[0].indexOf("name"), -1, "Indicator of 'name' changed event");
|
||||
}
|
||||
is(aAdapter.address, "", "adapter.address");
|
||||
is(aAdapter.name, "", "adapter.name");
|
||||
})
|
||||
.then(function() {
|
||||
log("[2] Enable Bluetooth and check the correctness of 'onattributechanged'");
|
||||
let promises = [];
|
||||
promises.push(waitForAdapterStateChanged(aAdapter, ["enabling", "enabled"]));
|
||||
promises.push(aAdapter.enable());
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function(aResults) {
|
||||
isnot(aResults[0].indexOf("address"), -1, "Indicator of 'address' changed event");
|
||||
if (originalName != "") {
|
||||
isnot(aResults[0].indexOf("name"), -1, "Indicator of 'name' changed event");
|
||||
}
|
||||
is(aAdapter.address, originalAddr, "adapter.address");
|
||||
is(aAdapter.name, originalName, "adapter.name");
|
||||
})
|
||||
});
|
@ -5,6 +5,151 @@ const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
|
||||
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
const PDU_DCS_CODING_GROUP_BITS = 0xF0;
|
||||
const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
|
||||
const PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04;
|
||||
const PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
|
||||
|
||||
const PDU_DCS_MSG_CLASS_BITS = 0x03;
|
||||
const PDU_DCS_MSG_CLASS_NORMAL = 0xFF;
|
||||
const PDU_DCS_MSG_CLASS_0 = 0x00;
|
||||
const PDU_DCS_MSG_CLASS_ME_SPECIFIC = 0x01;
|
||||
const PDU_DCS_MSG_CLASS_SIM_SPECIFIC = 0x02;
|
||||
const PDU_DCS_MSG_CLASS_TE_SPECIFIC = 0x03;
|
||||
const PDU_DCS_MSG_CLASS_USER_1 = 0x04;
|
||||
const PDU_DCS_MSG_CLASS_USER_2 = 0x05;
|
||||
|
||||
const GECKO_SMS_MESSAGE_CLASSES = {};
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0] = "class-0";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_ME_SPECIFIC] = "class-1";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_SIM_SPECIFIC] = "class-2";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_TE_SPECIFIC] = "class-3";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1] = "user-1";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2] = "user-2";
|
||||
|
||||
const CB_MESSAGE_SIZE_GSM = 88;
|
||||
const CB_MESSAGE_SIZE_ETWS = 56;
|
||||
|
||||
const CB_GSM_MESSAGEID_ETWS_BEGIN = 0x1100;
|
||||
const CB_GSM_MESSAGEID_ETWS_END = 0x1107;
|
||||
|
||||
const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [
|
||||
"cell-immediate",
|
||||
"plmn",
|
||||
"location-area",
|
||||
"cell"
|
||||
];
|
||||
|
||||
const CB_ETWS_WARNING_TYPE_NAMES = [
|
||||
"earthquake",
|
||||
"tsunami",
|
||||
"earthquake-tsunami",
|
||||
"test",
|
||||
"other"
|
||||
];
|
||||
|
||||
const CB_DCS_LANG_GROUP_1 = [
|
||||
"de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi",
|
||||
"no", "el", "tr", "hu", "pl", null
|
||||
];
|
||||
const CB_DCS_LANG_GROUP_2 = [
|
||||
"cs", "he", "ar", "ru", "is", null, null, null, null, null,
|
||||
null, null, null, null, null, null
|
||||
];
|
||||
|
||||
/**
|
||||
* Compose input number into specified number of semi-octets.
|
||||
*
|
||||
* @param: aNum
|
||||
* The number to be converted.
|
||||
* @param: aNumSemiOctets
|
||||
* Number of semi-octects to be composed to.
|
||||
*
|
||||
* @return The composed Hex String.
|
||||
*/
|
||||
function buildHexStr(aNum, aNumSemiOctets) {
|
||||
let str = aNum.toString(16);
|
||||
ok(str.length <= aNumSemiOctets);
|
||||
while (str.length < aNumSemiOctets) {
|
||||
str = "0" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to decode the given DCS into encoding type, language,
|
||||
* language indicator and message class.
|
||||
*
|
||||
* @param: aDcs
|
||||
* The DCS to be decoded.
|
||||
*
|
||||
* @return [encoding, language, hasLanguageIndicator,
|
||||
* GECKO_SMS_MESSAGE_CLASSES[messageClass]]
|
||||
*/
|
||||
function decodeGsmDataCodingScheme(aDcs) {
|
||||
let language = null;
|
||||
let hasLanguageIndicator = false;
|
||||
let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
let messageClass = PDU_DCS_MSG_CLASS_NORMAL;
|
||||
|
||||
switch (aDcs & PDU_DCS_CODING_GROUP_BITS) {
|
||||
case 0x00: // 0000
|
||||
language = CB_DCS_LANG_GROUP_1[aDcs & 0x0F];
|
||||
break;
|
||||
|
||||
case 0x10: // 0001
|
||||
switch (aDcs & 0x0F) {
|
||||
case 0x00:
|
||||
hasLanguageIndicator = true;
|
||||
break;
|
||||
case 0x01:
|
||||
encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
|
||||
hasLanguageIndicator = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20: // 0010
|
||||
language = CB_DCS_LANG_GROUP_2[aDcs & 0x0F];
|
||||
break;
|
||||
|
||||
case 0x40: // 01xx
|
||||
case 0x50:
|
||||
//case 0x60:
|
||||
//case 0x70:
|
||||
case 0x90: // 1001
|
||||
encoding = (aDcs & 0x0C);
|
||||
if (encoding == 0x0C) {
|
||||
encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
}
|
||||
messageClass = (aDcs & PDU_DCS_MSG_CLASS_BITS);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
encoding = (aDcs & 0x04) ? PDU_DCS_MSG_CODING_8BITS_ALPHABET
|
||||
: PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
switch(aDcs & PDU_DCS_MSG_CLASS_BITS) {
|
||||
case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break;
|
||||
case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break;
|
||||
case 0x03: messageClass = PDU_DCS_MSG_CLASS_TE_SPECIFIC; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x30: // 0011 (Reserved)
|
||||
case 0x80: // 1000 (Reserved)
|
||||
case 0xA0: // 1010..1100 (Reserved)
|
||||
case 0xB0:
|
||||
case 0xC0:
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported CBS data coding scheme: " + aDcs);
|
||||
}
|
||||
|
||||
return [encoding, language, hasLanguageIndicator,
|
||||
GECKO_SMS_MESSAGE_CLASSES[messageClass]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozCellBroadcast| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
@ -148,7 +293,7 @@ function sendMultipleRawCbsToEmulatorAndWait(aPdus) {
|
||||
promises.push(sendRawCbsToEmulator(pdu));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
return Promise.all(promises).then(aResults => aResults[0].message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,268 +1,215 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
MARIONETTE_TIMEOUT = 20000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const CB_MESSAGE_SIZE_ETWS = 56;
|
||||
|
||||
const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [
|
||||
"cell-immediate",
|
||||
"plmn",
|
||||
"location-area",
|
||||
"cell"
|
||||
];
|
||||
|
||||
const CB_ETWS_WARNING_TYPE_NAMES = [
|
||||
"earthquake",
|
||||
"tsunami",
|
||||
"earthquake-tsunami",
|
||||
"test",
|
||||
"other"
|
||||
];
|
||||
|
||||
SpecialPowers.addPermission("cellbroadcast", true, document);
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
let cbs = window.navigator.mozCellBroadcast;
|
||||
ok(cbs instanceof window.MozCellBroadcast,
|
||||
"mozCellBroadcast is instanceof " + cbs.constructor);
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
function sendCellBroadcastMessage(pdu, callback) {
|
||||
pendingEmulatorCmdCount++;
|
||||
|
||||
let cmd = "cbs pdu " + pdu;
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
pendingEmulatorCmdCount--;
|
||||
|
||||
is(result[0], "OK", "Emulator response");
|
||||
|
||||
if (callback) {
|
||||
window.setTimeout(callback, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildHexStr(n, numSemiOctets) {
|
||||
let str = n.toString(16);
|
||||
ok(str.length <= numSemiOctets);
|
||||
while (str.length < numSemiOctets) {
|
||||
str = "0" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function seq(end, begin) {
|
||||
let result = [];
|
||||
for (let i = begin || 0; i < end; i++) {
|
||||
result.push(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function repeat(func, array, oncomplete) {
|
||||
(function do_call(index) {
|
||||
let next = index < (array.length - 1) ? do_call.bind(null, index + 1) : oncomplete;
|
||||
func.apply(null, [array[index], next]);
|
||||
})(0);
|
||||
}
|
||||
|
||||
function doTestHelper(pdu, nextTest, checkFunc) {
|
||||
cbs.addEventListener("received", function onreceived(event) {
|
||||
cbs.removeEventListener("received", onreceived);
|
||||
|
||||
checkFunc(event.message);
|
||||
|
||||
window.setTimeout(nextTest, 0);
|
||||
});
|
||||
|
||||
if (Array.isArray(pdu)) {
|
||||
repeat(sendCellBroadcastMessage, pdu);
|
||||
} else {
|
||||
sendCellBroadcastMessage(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests receiving Cell Broadcast messages, event instance type, all attributes
|
||||
* of CellBroadcastMessage exist.
|
||||
*/
|
||||
function testEtwsMessageAttributes() {
|
||||
log("Test ETWS Primary Notification message attributes");
|
||||
|
||||
cbs.addEventListener("received", function onreceived(event) {
|
||||
cbs.removeEventListener("received", onreceived);
|
||||
|
||||
// Bug 838542: following check throws an exception and fails this case.
|
||||
// ok(event instanceof MozCellBroadcastEvent,
|
||||
// "event is instanceof " + event.constructor)
|
||||
ok(event, "event is valid");
|
||||
|
||||
let message = event.message;
|
||||
ok(message, "event.message is valid");
|
||||
function testReceiving_ETWS_MessageAttributes() {
|
||||
log("Test receiving ETWS Primary Notification - Message Attributes");
|
||||
|
||||
let verifyCBMessage = (aMessage) => {
|
||||
// Attributes other than `language` and `body` should always be assigned.
|
||||
ok(message.gsmGeographicalScope != null, "message.gsmGeographicalScope");
|
||||
ok(message.messageCode != null, "message.messageCode");
|
||||
ok(message.messageId != null, "message.messageId");
|
||||
ok('language' in message, "message.language");
|
||||
ok(message.language == null, "message.language");
|
||||
ok('body' in message, "message.body");
|
||||
ok(message.body == null, "message.body");
|
||||
is(message.messageClass, "normal", "message.messageClass");
|
||||
ok(message.timestamp != null, "message.timestamp");
|
||||
ok(message.etws != null, "message.etws");
|
||||
ok(message.etws.warningType != null, "message.etws.warningType");
|
||||
ok(message.etws.emergencyUserAlert != null,
|
||||
"message.etws.emergencyUserAlert");
|
||||
ok(message.etws.popup != null, "message.etws.popup");
|
||||
ok(message.cdmaServiceCategory != null, "message.cdmaServiceCategory");
|
||||
|
||||
window.setTimeout(testReceiving_ETWS_GeographicalScope, 0);
|
||||
});
|
||||
ok(aMessage.gsmGeographicalScope != null, "aMessage.gsmGeographicalScope");
|
||||
ok(aMessage.messageCode != null, "aMessage.messageCode");
|
||||
ok(aMessage.messageId != null, "aMessage.messageId");
|
||||
ok('language' in aMessage, "aMessage.language");
|
||||
ok(aMessage.language == null, "aMessage.language");
|
||||
ok('body' in aMessage, "aMessage.body");
|
||||
ok(aMessage.body == null, "aMessage.body");
|
||||
is(aMessage.messageClass, "normal", "aMessage.messageClass");
|
||||
ok(aMessage.timestamp != null, "aMessage.timestamp");
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
ok(aMessage.etws.warningType != null, "aMessage.etws.warningType");
|
||||
ok(aMessage.etws.emergencyUserAlert != null,
|
||||
"aMessage.etws.emergencyUserAlert");
|
||||
ok(aMessage.etws.popup != null, "aMessage.etws.popup");
|
||||
ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
|
||||
};
|
||||
|
||||
// Here we use a simple ETWS message for test.
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_ETWS * 2); // 6 octets
|
||||
sendCellBroadcastMessage(pdu);
|
||||
|
||||
return sendMultipleRawCbsToEmulatorAndWait([pdu])
|
||||
.then((aMessage) => verifyCBMessage(aMessage));
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_GeographicalScope() {
|
||||
log("Test receiving ETWS Primary Notification - Geographical Scope");
|
||||
|
||||
function do_test(gs, nextTest) {
|
||||
// Here we use a simple ETWS message for test.
|
||||
let pdu = buildHexStr(((gs & 0x03) << 14), 4)
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let verifyCBMessage = (aMessage, aGsName) => {
|
||||
is(aMessage.gsmGeographicalScope, aGsName,
|
||||
"aMessage.gsmGeographicalScope");
|
||||
};
|
||||
|
||||
CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.forEach(function(aGsName, aIndex) {
|
||||
let pdu = buildHexStr(((aIndex & 0x03) << 14), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aGsName));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.gsmGeographicalScope, CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[gs],
|
||||
"message.gsmGeographicalScope");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, seq(CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.length),
|
||||
testReceiving_ETWS_MessageCode);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_MessageCode() {
|
||||
log("Test receiving ETWS Primary Notification - Message Code");
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here
|
||||
// we test every single bit to verify the operation doesn't go wrong.
|
||||
let messageCodesToTest = [
|
||||
let messageCodes = [
|
||||
0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040,
|
||||
0x080, 0x100, 0x200, 0x251
|
||||
];
|
||||
|
||||
function do_test(messageCode, nextTest) {
|
||||
let pdu = buildHexStr(((messageCode & 0x3FF) << 4), 4)
|
||||
let verifyCBMessage = (aMessage, aMsgCode) => {
|
||||
is(aMessage.messageCode, aMsgCode, "aMessage.messageCode");
|
||||
};
|
||||
|
||||
messageCodes.forEach(function(aMsgCode) {
|
||||
let pdu = buildHexStr(((aMsgCode & 0x3FF) << 4), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 2) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMsgCode));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageCode, messageCode, "message.messageCode");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, messageCodesToTest, testReceiving_ETWS_MessageId);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_MessageId() {
|
||||
log("Test receiving ETWS Primary Notification - Message Identifier");
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// Message Identifier has 16 bits, but no bitwise operation is needed.
|
||||
// Test some selected values only.
|
||||
let messageIdsToTest = [
|
||||
0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811
|
||||
let messageIds = [
|
||||
0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811,
|
||||
];
|
||||
|
||||
function do_test(messageId, nextTest) {
|
||||
let verifyCBMessage = (aMessage, aMessageId) => {
|
||||
is(aMessage.messageId, aMessageId, "aMessage.messageId");
|
||||
};
|
||||
|
||||
messageIds.forEach(function(aMessageId) {
|
||||
let pdu = buildHexStr(0, 4)
|
||||
+ buildHexStr((messageId & 0xFFFF), 4)
|
||||
+ buildHexStr((aMessageId & 0xFFFF), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 4) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMessageId));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageId, messageId, "message.messageId");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, messageIdsToTest, testReceiving_ETWS_Timestamp);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_Timestamp() {
|
||||
log("Test receiving ETWS Primary Notification - Timestamp");
|
||||
|
||||
// Here we use a simple ETWS message for test.
|
||||
let pdu = buildHexStr(0, 12); // 6 octets
|
||||
doTestHelper(pdu, testReceiving_ETWS_WarningType, function(message) {
|
||||
let verifyCBMessage = (aMessage) => {
|
||||
// Cell Broadcast messages do not contain a timestamp field (however, ETWS
|
||||
// does). We only check the timestamp doesn't go too far (60 seconds) here.
|
||||
let msMessage = message.timestamp;
|
||||
let msMessage = aMessage.timestamp;
|
||||
let msNow = Date.now();
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
|
||||
});
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "aMessage.timestamp");
|
||||
};
|
||||
|
||||
// Here we use a simple ETWS message for test.
|
||||
let pdu = buildHexStr(0, 12); // 6 octets
|
||||
|
||||
return sendMultipleRawCbsToEmulatorAndWait([pdu])
|
||||
.then((aMessage) => verifyCBMessage(aMessage));
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_WarningType() {
|
||||
log("Test receiving ETWS Primary Notification - Warning Type");
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// Warning Type has 7 bits, and is ORed into a 16 bits 'WarningType' field.
|
||||
// Here we test every single bit to verify the operation doesn't go wrong.
|
||||
let warningTypesToTest = [
|
||||
let warningTypes = [
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x08, 0x10, 0x20, 0x40, 0x41
|
||||
];
|
||||
|
||||
function do_test(warningType, nextTest) {
|
||||
let verifyCBMessage = (aMessage, aWarningType) => {
|
||||
ok(aMessage.etws, "aMessage.etws");
|
||||
is(aMessage.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[aWarningType],
|
||||
"aMessage.etws.warningType");
|
||||
};
|
||||
|
||||
warningTypes.forEach(function(aWarningType) {
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(((warningType & 0x7F) << 9), 4)
|
||||
+ buildHexStr(((aWarningType & 0x7F) << 9), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2);
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
ok(message.etws, "message.etws");
|
||||
is(message.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[warningType],
|
||||
"message.etws.warningType");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, warningTypesToTest, testReceiving_ETWS_EmergencyUserAlert);
|
||||
}
|
||||
|
||||
function doTestEmergencyUserAlert_or_Popup(name, mask, nextTest) {
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(mask, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2);
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
ok(message.etws != null, "message.etws");
|
||||
is(message.etws[name], mask != 0, "message.etws." + name);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aWarningType));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_EmergencyUserAlert() {
|
||||
log("Test receiving ETWS Primary Notification - Emergency User Alert");
|
||||
|
||||
repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "emergencyUserAlert"),
|
||||
[0x100, 0x000], testReceiving_ETWS_Popup);
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let emergencyUserAlertMasks = [0x100, 0x000];
|
||||
|
||||
let verifyCBMessage = (aMessage, aMask) => {
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
is(aMessage.etws.emergencyUserAlert, aMask != 0, "aMessage.etws.emergencyUserAlert");
|
||||
};
|
||||
|
||||
emergencyUserAlertMasks.forEach(function(aMask) {
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(aMask, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMask));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_ETWS_Popup() {
|
||||
log("Test receiving ETWS Primary Notification - Popup");
|
||||
|
||||
repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "popup"),
|
||||
[0x80, 0x000], cleanUp);
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let popupMasks = [0x80, 0x000];
|
||||
|
||||
let verifyCBMessage = (aMessage, aMask) => {
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
is(aMessage.etws.popup, aMask != 0, "aMessage.etws.popup");
|
||||
};
|
||||
|
||||
popupMasks.forEach(function(aMask) {
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(aMask, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_ETWS - 6) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMask));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
if (pendingEmulatorCmdCount > 0) {
|
||||
window.setTimeout(cleanUp, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
SpecialPowers.removePermission("cellbroadcast", true, document);
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
waitFor(testEtwsMessageAttributes, function() {
|
||||
return navigator.mozMobileConnections[0].voice.connected;
|
||||
startTestCommon(function testCaseMain() {
|
||||
return testReceiving_ETWS_MessageAttributes()
|
||||
.then(() => testReceiving_ETWS_GeographicalScope())
|
||||
.then(() => testReceiving_ETWS_MessageCode())
|
||||
.then(() => testReceiving_ETWS_MessageId())
|
||||
.then(() => testReceiving_ETWS_Timestamp())
|
||||
.then(() => testReceiving_ETWS_WarningType())
|
||||
.then(() => testReceiving_ETWS_EmergencyUserAlert())
|
||||
.then(() => testReceiving_ETWS_Popup());
|
||||
});
|
||||
|
||||
|
@ -1,59 +1,8 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 30000;
|
||||
|
||||
const PDU_DCS_CODING_GROUP_BITS = 0xF0;
|
||||
const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
|
||||
const PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04;
|
||||
const PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
|
||||
|
||||
const PDU_DCS_MSG_CLASS_BITS = 0x03;
|
||||
const PDU_DCS_MSG_CLASS_NORMAL = 0xFF;
|
||||
const PDU_DCS_MSG_CLASS_0 = 0x00;
|
||||
const PDU_DCS_MSG_CLASS_ME_SPECIFIC = 0x01;
|
||||
const PDU_DCS_MSG_CLASS_SIM_SPECIFIC = 0x02;
|
||||
const PDU_DCS_MSG_CLASS_TE_SPECIFIC = 0x03;
|
||||
const PDU_DCS_MSG_CLASS_USER_1 = 0x04;
|
||||
const PDU_DCS_MSG_CLASS_USER_2 = 0x05;
|
||||
|
||||
const GECKO_SMS_MESSAGE_CLASSES = {};
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0] = "class-0";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_ME_SPECIFIC] = "class-1";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_SIM_SPECIFIC] = "class-2";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_TE_SPECIFIC] = "class-3";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1] = "user-1";
|
||||
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2] = "user-2";
|
||||
|
||||
const CB_MESSAGE_SIZE_GSM = 88;
|
||||
|
||||
const CB_GSM_MESSAGEID_ETWS_BEGIN = 0x1100;
|
||||
const CB_GSM_MESSAGEID_ETWS_END = 0x1107;
|
||||
|
||||
const CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [
|
||||
"cell-immediate",
|
||||
"plmn",
|
||||
"location-area",
|
||||
"cell"
|
||||
];
|
||||
|
||||
const CB_ETWS_WARNING_TYPE_NAMES = [
|
||||
"earthquake",
|
||||
"tsunami",
|
||||
"earthquake-tsunami",
|
||||
"test",
|
||||
"other"
|
||||
];
|
||||
|
||||
const CB_DCS_LANG_GROUP_1 = [
|
||||
"de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi",
|
||||
"no", "el", "tr", "hu", "pl", null
|
||||
];
|
||||
const CB_DCS_LANG_GROUP_2 = [
|
||||
"cs", "he", "ar", "ru", "is", null, null, null, null, null,
|
||||
null, null, null, null, null, null
|
||||
];
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const CB_MAX_CONTENT_7BIT = Math.floor((CB_MESSAGE_SIZE_GSM - 6) * 8 / 7);
|
||||
const CB_MAX_CONTENT_UCS2 = Math.floor((CB_MESSAGE_SIZE_GSM - 6) / 2);
|
||||
@ -70,412 +19,327 @@ const BODY_UCS2 = "\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"
|
||||
+ "\u0000"; // 41 unicode chars.
|
||||
const BODY_UCS2_IND = BODY_UCS2.substr(1);
|
||||
|
||||
SpecialPowers.addPermission("cellbroadcast", true, document);
|
||||
SpecialPowers.addPermission("mobileconnection", true, document);
|
||||
|
||||
is(BODY_7BITS.length, CB_MAX_CONTENT_7BIT, "BODY_7BITS.length");
|
||||
is(BODY_7BITS_IND.length, CB_MAX_CONTENT_7BIT - 3, "BODY_7BITS_IND.length");
|
||||
is(BODY_UCS2.length, CB_MAX_CONTENT_UCS2, "BODY_UCS2.length");
|
||||
is(BODY_UCS2_IND.length, CB_MAX_CONTENT_UCS2 - 1, "BODY_UCS2_IND.length")
|
||||
is(BODY_UCS2_IND.length, CB_MAX_CONTENT_UCS2 - 1, "BODY_UCS2_IND.length");
|
||||
|
||||
let cbs = window.navigator.mozCellBroadcast;
|
||||
ok(cbs instanceof window.MozCellBroadcast,
|
||||
"mozCellBroadcast is instanceof " + cbs.constructor);
|
||||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
function sendCellBroadcastMessage(pdu, callback) {
|
||||
pendingEmulatorCmdCount++;
|
||||
|
||||
let cmd = "cbs pdu " + pdu;
|
||||
runEmulatorCmd(cmd, function(result) {
|
||||
pendingEmulatorCmdCount--;
|
||||
|
||||
is(result[0], "OK", "Emulator response");
|
||||
|
||||
if (callback) {
|
||||
window.setTimeout(callback, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function buildHexStr(n, numSemiOctets) {
|
||||
let str = n.toString(16);
|
||||
ok(str.length <= numSemiOctets);
|
||||
while (str.length < numSemiOctets) {
|
||||
str = "0" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function seq(end, begin) {
|
||||
let result = [];
|
||||
for (let i = begin || 0; i < end; i++) {
|
||||
result.push(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function repeat(func, array, oncomplete) {
|
||||
(function do_call(index) {
|
||||
let next = index < (array.length - 1) ? do_call.bind(null, index + 1) : oncomplete;
|
||||
func.apply(null, [array[index], next]);
|
||||
})(0);
|
||||
}
|
||||
|
||||
function doTestHelper(pdu, nextTest, checkFunc) {
|
||||
cbs.addEventListener("received", function onreceived(event) {
|
||||
cbs.removeEventListener("received", onreceived);
|
||||
|
||||
checkFunc(event.message);
|
||||
|
||||
window.setTimeout(nextTest, 0);
|
||||
});
|
||||
|
||||
if (Array.isArray(pdu)) {
|
||||
repeat(sendCellBroadcastMessage, pdu);
|
||||
} else {
|
||||
sendCellBroadcastMessage(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests receiving Cell Broadcast messages, event instance type, all attributes
|
||||
* of CellBroadcastMessage exist.
|
||||
*/
|
||||
function testGsmMessageAttributes() {
|
||||
log("Test GSM Cell Broadcast message attributes");
|
||||
|
||||
cbs.addEventListener("received", function onreceived(event) {
|
||||
cbs.removeEventListener("received", onreceived);
|
||||
|
||||
// Bug 838542: following check throws an exception and fails this case.
|
||||
// ok(event instanceof MozCellBroadcastEvent,
|
||||
// "event is instanceof " + event.constructor)
|
||||
ok(event, "event is valid");
|
||||
|
||||
let message = event.message;
|
||||
ok(message, "event.message is valid");
|
||||
function testReceiving_GSM_MessageAttributes() {
|
||||
log("Test receiving GSM Cell Broadcast - Message Attributes");
|
||||
|
||||
let verifyCBMessage = (aMessage) => {
|
||||
// Attributes other than `language` and `body` should always be assigned.
|
||||
ok(message.gsmGeographicalScope != null, "message.gsmGeographicalScope");
|
||||
ok(message.messageCode != null, "message.messageCode");
|
||||
ok(message.messageId != null, "message.messageId");
|
||||
ok(message.language != null, "message.language");
|
||||
ok(message.body != null, "message.body");
|
||||
ok(message.messageClass != null, "message.messageClass");
|
||||
ok(message.timestamp != null, "message.timestamp");
|
||||
ok('etws' in message, "message.etws");
|
||||
if (message.etws) {
|
||||
ok('warningType' in message.etws, "message.etws.warningType");
|
||||
ok(message.etws.emergencyUserAlert != null, "message.etws.emergencyUserAlert");
|
||||
ok(message.etws.popup != null, "message.etws.popup");
|
||||
ok(aMessage.gsmGeographicalScope != null, "aMessage.gsmGeographicalScope");
|
||||
ok(aMessage.messageCode != null, "aMessage.messageCode");
|
||||
ok(aMessage.messageId != null, "aMessage.messageId");
|
||||
ok(aMessage.language != null, "aMessage.language");
|
||||
ok(aMessage.body != null, "aMessage.body");
|
||||
ok(aMessage.messageClass != null, "aMessage.messageClass");
|
||||
ok(aMessage.timestamp != null, "aMessage.timestamp");
|
||||
ok('etws' in aMessage, "aMessage.etws");
|
||||
if (aMessage.etws) {
|
||||
ok('warningType' in aMessage.etws, "aMessage.etws.warningType");
|
||||
ok(aMessage.etws.emergencyUserAlert != null, "aMessage.etws.emergencyUserAlert");
|
||||
ok(aMessage.etws.popup != null, "aMessage.etws.popup");
|
||||
}
|
||||
ok(message.cdmaServiceCategory != null, "message.cdmaServiceCategory");
|
||||
|
||||
window.setTimeout(testReceiving_GSM_GeographicalScope, 0);
|
||||
});
|
||||
ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
|
||||
};
|
||||
|
||||
// Here we use a simple GSM message for test.
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
|
||||
sendCellBroadcastMessage(pdu);
|
||||
|
||||
return sendMultipleRawCbsToEmulatorAndWait([pdu])
|
||||
.then((aMessage) => verifyCBMessage(aMessage));
|
||||
}
|
||||
|
||||
function testReceiving_GSM_GeographicalScope() {
|
||||
log("Test receiving GSM Cell Broadcast - Geographical Scope");
|
||||
|
||||
function do_test(gs, nextTest) {
|
||||
let pdu = buildHexStr(((gs & 0x03) << 14), 4)
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let verifyCBMessage = (aMessage, aGsName) => {
|
||||
is(aMessage.gsmGeographicalScope, aGsName,
|
||||
"aMessage.gsmGeographicalScope");
|
||||
};
|
||||
|
||||
CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.forEach(function(aGsName, aIndex) {
|
||||
let pdu = buildHexStr(((aIndex & 0x03) << 14), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 2) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aGsName));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.gsmGeographicalScope, CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[gs],
|
||||
"message.gsmGeographicalScope");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, seq(CB_GSM_GEOGRAPHICAL_SCOPE_NAMES.length),
|
||||
testReceiving_GSM_MessageCode);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_MessageCode() {
|
||||
log("Test receiving GSM Cell Broadcast - Message Code");
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// Message Code has 10 bits, and is ORed into a 16 bits 'serial' number. Here
|
||||
// we test every single bit to verify the operation doesn't go wrong.
|
||||
let messageCodesToTest = [
|
||||
let messageCodes = [
|
||||
0x000, 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x040,
|
||||
0x080, 0x100, 0x200, 0x251
|
||||
];
|
||||
|
||||
function do_test(messageCode, nextTest) {
|
||||
let pdu = buildHexStr(((messageCode & 0x3FF) << 4), 4)
|
||||
let verifyCBMessage = (aMessage, aMsgCode) => {
|
||||
is(aMessage.messageCode, aMsgCode, "aMessage.messageCode");
|
||||
};
|
||||
|
||||
messageCodes.forEach(function(aMsgCode) {
|
||||
let pdu = buildHexStr(((aMsgCode & 0x3FF) << 4), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 2) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMsgCode));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageCode, messageCode, "message.messageCode");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, messageCodesToTest, testReceiving_GSM_MessageId);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_MessageId() {
|
||||
log("Test receiving GSM Cell Broadcast - Message Identifier");
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// Message Identifier has 16 bits, but no bitwise operation is needed.
|
||||
// Test some selected values only.
|
||||
let messageIdsToTest = [
|
||||
let messageIds = [
|
||||
0x0000, 0x0001, 0x0010, 0x0100, 0x1000, 0x1111, 0x8888, 0x8811,
|
||||
];
|
||||
|
||||
function do_test(messageId, nextTest) {
|
||||
let verifyCBMessage = (aMessage, aMessageId) => {
|
||||
is(aMessage.messageId, aMessageId, "aMessage.messageId");
|
||||
ok(aMessage.etws == null, "aMessage.etws");
|
||||
};
|
||||
|
||||
messageIds.forEach(function(aMessageId) {
|
||||
let pdu = buildHexStr(0, 4)
|
||||
+ buildHexStr((messageId & 0xFFFF), 4)
|
||||
+ buildHexStr((aMessageId & 0xFFFF), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMessageId));
|
||||
});
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageId, messageId, "message.messageId");
|
||||
ok(message.etws == null, "message.etws");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, messageIdsToTest, testReceiving_GSM_Language_and_Body);
|
||||
}
|
||||
|
||||
// Copied from GsmPDUHelper.readCbDataCodingScheme
|
||||
function decodeDataCodingScheme(dcs) {
|
||||
let language = null;
|
||||
let hasLanguageIndicator = false;
|
||||
let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
let messageClass = PDU_DCS_MSG_CLASS_NORMAL;
|
||||
|
||||
switch (dcs & PDU_DCS_CODING_GROUP_BITS) {
|
||||
case 0x00: // 0000
|
||||
language = CB_DCS_LANG_GROUP_1[dcs & 0x0F];
|
||||
break;
|
||||
|
||||
case 0x10: // 0001
|
||||
switch (dcs & 0x0F) {
|
||||
case 0x00:
|
||||
hasLanguageIndicator = true;
|
||||
break;
|
||||
case 0x01:
|
||||
encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
|
||||
hasLanguageIndicator = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20: // 0010
|
||||
language = CB_DCS_LANG_GROUP_2[dcs & 0x0F];
|
||||
break;
|
||||
|
||||
case 0x40: // 01xx
|
||||
case 0x50:
|
||||
//case 0x60:
|
||||
//case 0x70:
|
||||
case 0x90: // 1001
|
||||
encoding = (dcs & 0x0C);
|
||||
if (encoding == 0x0C) {
|
||||
encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
}
|
||||
messageClass = (dcs & PDU_DCS_MSG_CLASS_BITS);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
encoding = (dcs & 0x04) ? PDU_DCS_MSG_CODING_8BITS_ALPHABET
|
||||
: PDU_DCS_MSG_CODING_7BITS_ALPHABET;
|
||||
switch(dcs & PDU_DCS_MSG_CLASS_BITS) {
|
||||
case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break;
|
||||
case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break;
|
||||
case 0x03: messageClass = PDU_DCS_MSG_CLASS_TE_SPECIFIC; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x30: // 0011 (Reserved)
|
||||
case 0x80: // 1000 (Reserved)
|
||||
case 0xA0: // 1010..1100 (Reserved)
|
||||
case 0xB0:
|
||||
case 0xC0:
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported CBS data coding scheme: " + dcs);
|
||||
}
|
||||
|
||||
return [encoding, language, hasLanguageIndicator,
|
||||
GECKO_SMS_MESSAGE_CLASSES[messageClass]];
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_Language_and_Body() {
|
||||
log("Test receiving GSM Cell Broadcast - Language & Body");
|
||||
|
||||
function do_test(dcs) {
|
||||
let encoding, language, indicator, messageClass;
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let testDcs = [];
|
||||
dcs = 0;
|
||||
while (dcs <= 0xFF) {
|
||||
try {
|
||||
[encoding, language, indicator, messageClass] = decodeDataCodingScheme(dcs);
|
||||
let dcsInfo = { dcs: dcs };
|
||||
[ dcsInfo.encoding, dcsInfo.language,
|
||||
dcsInfo.indicator, dcsInfo.messageClass ] = decodeGsmDataCodingScheme(dcs);
|
||||
testDcs.push(dcsInfo);
|
||||
} catch (e) {
|
||||
// Unsupported coding group, skip.
|
||||
let nextGroup = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
|
||||
window.setTimeout(do_test.bind(null, nextGroup), 0);
|
||||
return;
|
||||
let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10;
|
||||
}
|
||||
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(dcs, 2)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 5) * 2);
|
||||
|
||||
let nextTest = (dcs < 0xFF) ? do_test.bind(null, dcs + 1)
|
||||
: testReceiving_GSM_Timestamp;
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
if (language) {
|
||||
is(message.language, language, "message.language");
|
||||
} else if (indicator) {
|
||||
is(message.language, "@@", "message.language");
|
||||
} else {
|
||||
ok(message.language == null, "message.language");
|
||||
}
|
||||
|
||||
switch (encoding) {
|
||||
case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
|
||||
is(message.body, indicator ? BODY_7BITS_IND : BODY_7BITS, "message.body");
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
|
||||
ok(message.body == null, "message.body");
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
|
||||
is(message.body, indicator ? BODY_UCS2_IND : BODY_UCS2, "message.body");
|
||||
break;
|
||||
}
|
||||
|
||||
is(message.messageClass, messageClass, "message.messageClass");
|
||||
});
|
||||
dcs++;
|
||||
}
|
||||
|
||||
do_test(0);
|
||||
let verifyCBMessage = (aMessage, aDcsInfo) => {
|
||||
if (aDcsInfo.language) {
|
||||
is(aMessage.language, aDcsInfo.language, "aMessage.language");
|
||||
} else if (aDcsInfo.indicator) {
|
||||
is(aMessage.language, "@@", "aMessage.language");
|
||||
} else {
|
||||
ok(aMessage.language == null, "aMessage.language");
|
||||
}
|
||||
|
||||
switch (aDcsInfo.encoding) {
|
||||
case PDU_DCS_MSG_CODING_7BITS_ALPHABET:
|
||||
is(aMessage.body, aDcsInfo.indicator ? BODY_7BITS_IND : BODY_7BITS, "aMessage.body");
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_8BITS_ALPHABET:
|
||||
ok(aMessage.body == null, "aMessage.body");
|
||||
break;
|
||||
case PDU_DCS_MSG_CODING_16BITS_ALPHABET:
|
||||
is(aMessage.body, aDcsInfo.indicator ? BODY_UCS2_IND : BODY_UCS2, "aMessage.body");
|
||||
break;
|
||||
}
|
||||
|
||||
is(aMessage.messageClass, aDcsInfo.messageClass, "aMessage.messageClass");
|
||||
};
|
||||
|
||||
testDcs.forEach(function(aDcsInfo) {
|
||||
let pdu = buildHexStr(0, 8)
|
||||
+ buildHexStr(aDcsInfo.dcs, 2)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 5) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aDcsInfo));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_Timestamp() {
|
||||
log("Test receiving GSM Cell Broadcast - Timestamp");
|
||||
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
|
||||
doTestHelper(pdu, testReceiving_GSM_WarningType, function(message) {
|
||||
let verifyCBMessage = (aMessage) => {
|
||||
// Cell Broadcast messages do not contain a timestamp field (however, ETWS
|
||||
// does). We only check the timestamp doesn't go too far (60 seconds) here.
|
||||
let msMessage = message.timestamp;
|
||||
let msMessage = aMessage.timestamp;
|
||||
let msNow = Date.now();
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
|
||||
});
|
||||
ok(Math.abs(msMessage - msNow) < (1000 * 60), "aMessage.timestamp");
|
||||
};
|
||||
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
|
||||
|
||||
return sendMultipleRawCbsToEmulatorAndWait([pdu])
|
||||
.then((aMessage) => verifyCBMessage(aMessage));
|
||||
}
|
||||
|
||||
function testReceiving_GSM_WarningType() {
|
||||
log("Test receiving GSM Cell Broadcast - Warning Type");
|
||||
|
||||
let messageIdsToTest = [];
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let messageIds = [];
|
||||
for (let i = CB_GSM_MESSAGEID_ETWS_BEGIN; i <= CB_GSM_MESSAGEID_ETWS_END; i++) {
|
||||
messageIdsToTest.push(i);
|
||||
messageIds.push(i);
|
||||
}
|
||||
|
||||
function do_test(messageId, nextTest) {
|
||||
let verifyCBMessage = (aMessage, aMessageId) => {
|
||||
is(aMessage.messageId, aMessageId, "aMessage.messageId");
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
|
||||
let offset = aMessageId - CB_GSM_MESSAGEID_ETWS_BEGIN;
|
||||
if (offset < CB_ETWS_WARNING_TYPE_NAMES.length) {
|
||||
is(aMessage.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[offset],
|
||||
"aMessage.etws.warningType");
|
||||
} else {
|
||||
ok(aMessage.etws.warningType == null, "aMessage.etws.warningType");
|
||||
}
|
||||
};
|
||||
|
||||
messageIds.forEach(function(aMessageId) {
|
||||
let pdu = buildHexStr(0, 4)
|
||||
+ buildHexStr((messageId & 0xFFFF), 4)
|
||||
+ buildHexStr((aMessageId & 0xFFFF), 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageId, messageId, "message.messageId");
|
||||
ok(message.etws != null, "message.etws");
|
||||
|
||||
let offset = messageId - CB_GSM_MESSAGEID_ETWS_BEGIN;
|
||||
if (offset < CB_ETWS_WARNING_TYPE_NAMES.length) {
|
||||
is(message.etws.warningType, CB_ETWS_WARNING_TYPE_NAMES[offset],
|
||||
"message.etws.warningType");
|
||||
} else {
|
||||
ok(message.etws.warningType == null, "message.etws.warningType");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, messageIdsToTest, testReceiving_GSM_EmergencyUserAlert);
|
||||
}
|
||||
|
||||
function doTestEmergencyUserAlert_or_Popup(name, mask, nextTest) {
|
||||
let pdu = buildHexStr(mask, 4)
|
||||
+ buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
|
||||
|
||||
doTestHelper(pdu, nextTest, function(message) {
|
||||
is(message.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "message.messageId");
|
||||
ok(message.etws != null, "message.etws");
|
||||
is(message.etws[name], mask != 0, "message.etws." + name);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMessageId));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_EmergencyUserAlert() {
|
||||
log("Test receiving GSM Cell Broadcast - Emergency User Alert");
|
||||
|
||||
repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "emergencyUserAlert"),
|
||||
[0x2000, 0x0000], testReceiving_GSM_Popup);
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let emergencyUserAlertMasks = [0x2000, 0x0000];
|
||||
|
||||
let verifyCBMessage = (aMessage, aMask) => {
|
||||
is(aMessage.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "aMessage.messageId");
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
is(aMessage.etws.emergencyUserAlert, aMask != 0, "aMessage.etws.emergencyUserAlert");
|
||||
};
|
||||
|
||||
emergencyUserAlertMasks.forEach(function(aMask) {
|
||||
let pdu = buildHexStr(aMask, 4)
|
||||
+ buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMask));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_Popup() {
|
||||
log("Test receiving GSM Cell Broadcast - Popup");
|
||||
|
||||
repeat(doTestEmergencyUserAlert_or_Popup.bind(null, "popup"),
|
||||
[0x1000, 0x0000], testReceiving_GSM_Multipart);
|
||||
let promise = Promise.resolve();
|
||||
|
||||
let popupMasks = [0x1000, 0x0000];
|
||||
|
||||
let verifyCBMessage = (aMessage, aMask) => {
|
||||
is(aMessage.messageId, CB_GSM_MESSAGEID_ETWS_BEGIN, "aMessage.messageId");
|
||||
ok(aMessage.etws != null, "aMessage.etws");
|
||||
is(aMessage.etws.popup, aMask != 0, "aMessage.etws.popup");
|
||||
};
|
||||
|
||||
popupMasks.forEach(function(aMask) {
|
||||
let pdu = buildHexStr(aMask, 4)
|
||||
+ buildHexStr(CB_GSM_MESSAGEID_ETWS_BEGIN, 4)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 4) * 2);
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aMask));
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_Multipart() {
|
||||
log("Test receiving GSM Cell Broadcast - Multipart Messages");
|
||||
|
||||
function do_test(numParts, nextTest) {
|
||||
let promise = Promise.resolve();
|
||||
|
||||
// According to 9.4.1.2.4 Page Parameter in TS 23.041, the maximal Number of
|
||||
// pages per CB message is 15.
|
||||
let numParts = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||
|
||||
let verifyCBMessage = (aMessage, aNumParts) => {
|
||||
is(aMessage.body.length, (aNumParts * CB_MAX_CONTENT_7BIT),
|
||||
"aMessage.body");
|
||||
};
|
||||
|
||||
numParts.forEach(function(aNumParts) {
|
||||
let pdus = [];
|
||||
for (let i = 1; i <= numParts; i++) {
|
||||
for (let i = 1; i <= aNumParts; i++) {
|
||||
let pdu = buildHexStr(0, 10)
|
||||
+ buildHexStr((i << 4) + numParts, 2)
|
||||
+ buildHexStr((i << 4) + aNumParts, 2)
|
||||
+ buildHexStr(0, (CB_MESSAGE_SIZE_GSM - 6) * 2);
|
||||
pdus.push(pdu);
|
||||
}
|
||||
promise = promise
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait(pdus))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, aNumParts));
|
||||
});
|
||||
|
||||
doTestHelper(pdus, nextTest, function(message) {
|
||||
is(message.body.length, (numParts * CB_MAX_CONTENT_7BIT),
|
||||
"message.body");
|
||||
});
|
||||
}
|
||||
|
||||
repeat(do_test, seq(16, 1), testReceiving_GSM_ServiceCategory);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function testReceiving_GSM_ServiceCategory() {
|
||||
log("Test receiving GSM Cell Broadcast - Service Category");
|
||||
|
||||
cbs.addEventListener("received", function onreceived(event) {
|
||||
cbs.removeEventListener("received", onreceived);
|
||||
|
||||
let message = event.message;
|
||||
|
||||
let verifyCBMessage = (aMessage) => {
|
||||
// Bug 910091
|
||||
// "Service Category" is not defined in GSM. We should always get '0' here.
|
||||
is(message.cdmaServiceCategory, 0, "message.cdmaServiceCategory");
|
||||
|
||||
window.setTimeout(cleanUp, 0);
|
||||
});
|
||||
is(aMessage.cdmaServiceCategory, 0, "aMessage.cdmaServiceCategory");
|
||||
};
|
||||
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
|
||||
sendCellBroadcastMessage(pdu);
|
||||
return sendMultipleRawCbsToEmulatorAndWait([pdu])
|
||||
.then((aMessage) => verifyCBMessage(aMessage));
|
||||
}
|
||||
|
||||
function cleanUp() {
|
||||
if (pendingEmulatorCmdCount > 0) {
|
||||
window.setTimeout(cleanUp, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
SpecialPowers.removePermission("mobileconnection", document);
|
||||
SpecialPowers.removePermission("cellbroadcast", true, document);
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
waitFor(testGsmMessageAttributes, function() {
|
||||
return navigator.mozMobileConnections[0].voice.connected;
|
||||
startTestCommon(function testCaseMain() {
|
||||
return testReceiving_GSM_MessageAttributes()
|
||||
.then(() => testReceiving_GSM_GeographicalScope())
|
||||
.then(() => testReceiving_GSM_MessageCode())
|
||||
.then(() => testReceiving_GSM_MessageId())
|
||||
.then(() => testReceiving_GSM_Language_and_Body())
|
||||
.then(() => testReceiving_GSM_Timestamp())
|
||||
.then(() => testReceiving_GSM_WarningType())
|
||||
.then(() => testReceiving_GSM_EmergencyUserAlert())
|
||||
.then(() => testReceiving_GSM_Popup())
|
||||
.then(() => testReceiving_GSM_Multipart())
|
||||
.then(() => testReceiving_GSM_ServiceCategory());
|
||||
});
|
||||
|
||||
|
@ -1,19 +1,17 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_TIMEOUT = 10000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
const BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
||||
+ "@@@@@@@@@@@@@"; // 93 ascii chars.
|
||||
const CB_PDU_SIZE = 88;
|
||||
|
||||
function testReceivingMultiSIM() {
|
||||
let CB_PDU = "";
|
||||
while (CB_PDU.length < CB_PDU_SIZE * 2) {
|
||||
CB_PDU += "00";
|
||||
}
|
||||
function testReceiving_MultiSIM() {
|
||||
log("Test receiving GSM Cell Broadcast - Multi-SIM");
|
||||
|
||||
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
|
||||
|
||||
let verifyCBMessage = (aMessage, aServiceId) => {
|
||||
log("Verify CB message received from serviceId: " + aServiceId);
|
||||
@ -22,13 +20,13 @@ function testReceivingMultiSIM() {
|
||||
};
|
||||
|
||||
return selectModem(1)
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([CB_PDU]))
|
||||
.then((results) => verifyCBMessage(results[0].message, 1))
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, 1))
|
||||
.then(() => selectModem(0))
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([CB_PDU]))
|
||||
.then((results) => verifyCBMessage(results[0].message, 0));
|
||||
.then(() => sendMultipleRawCbsToEmulatorAndWait([pdu]))
|
||||
.then((aMessage) => verifyCBMessage(aMessage, 0));
|
||||
}
|
||||
|
||||
startTestCommon(function testCaseMain() {
|
||||
return runIfMultiSIM(testReceivingMultiSIM);
|
||||
return runIfMultiSIM(testReceiving_MultiSIM);
|
||||
});
|
||||
|
@ -185,19 +185,6 @@ ContactManager.prototype = {
|
||||
Services.DOMRequest.fireError(req.cursor, msg.errorMsg);
|
||||
}
|
||||
break;
|
||||
case "PermissionPromptHelper:AskPermission:OK":
|
||||
if (DEBUG) debug("id: " + msg.requestID);
|
||||
req = this.getRequest(msg.requestID);
|
||||
if (!req) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
req.allow();
|
||||
} else {
|
||||
req.cancel();
|
||||
}
|
||||
break;
|
||||
case "Contact:Changed":
|
||||
// Fire oncontactchange event
|
||||
if (DEBUG) debug("Contacts:ContactChanged: " + msg.contactID + ", " + msg.reason);
|
||||
@ -235,6 +222,7 @@ ContactManager.prototype = {
|
||||
|
||||
askPermission: function (aAccess, aRequest, aAllowCallback, aCancelCallback) {
|
||||
if (DEBUG) debug("askPermission for contacts");
|
||||
|
||||
let access;
|
||||
switch(aAccess) {
|
||||
case "create":
|
||||
@ -255,38 +243,42 @@ ContactManager.prototype = {
|
||||
}
|
||||
|
||||
// Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
let type = "contacts-" + access;
|
||||
let permValue =
|
||||
Services.perms.testExactPermissionFromPrincipal(this._window.document.nodePrincipal, type);
|
||||
Services.perms.testExactPermissionFromPrincipal(principal, type);
|
||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
aAllowCallback();
|
||||
return;
|
||||
} else if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
|
||||
aCancelCallback();
|
||||
}
|
||||
|
||||
let requestID = this.getRequestId({
|
||||
request: aRequest,
|
||||
allow: function() {
|
||||
aAllowCallback();
|
||||
}.bind(this),
|
||||
cancel : function() {
|
||||
if (aCancelCallback) {
|
||||
aCancelCallback()
|
||||
} else if (aRequest) {
|
||||
Services.DOMRequest.fireError(aRequest, "Not Allowed");
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
let principal = this._window.document.nodePrincipal;
|
||||
cpmm.sendAsyncMessage("PermissionPromptHelper:AskPermission", {
|
||||
// Create an array with a single nsIContentPermissionType element.
|
||||
let type = {
|
||||
type: "contacts",
|
||||
access: access,
|
||||
requestID: requestID,
|
||||
origin: principal.origin,
|
||||
appID: principal.appId,
|
||||
browserFlag: principal.isInBrowserElement,
|
||||
windowID: this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID
|
||||
});
|
||||
options: null,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
|
||||
};
|
||||
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
typeArray.appendElement(type, false);
|
||||
|
||||
// create a nsIContentPermissionRequest
|
||||
let request = {
|
||||
types: typeArray,
|
||||
principal: principal,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
|
||||
allow: aAllowCallback,
|
||||
cancel: aCancelCallback,
|
||||
window: this._window
|
||||
};
|
||||
|
||||
// Using askPermission from nsIDOMWindowUtils that takes care of the
|
||||
// remoting if needed.
|
||||
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
windowUtils.askPermission(request);
|
||||
},
|
||||
|
||||
save: function save(aContact) {
|
||||
@ -464,7 +456,6 @@ ContactManager.prototype = {
|
||||
"Contact:Save:Return:OK", "Contact:Save:Return:KO",
|
||||
"Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
|
||||
"Contact:Changed",
|
||||
"PermissionPromptHelper:AskPermission:OK",
|
||||
"Contacts:GetAll:Next", "Contacts:GetAll:Return:KO",
|
||||
"Contacts:Count",
|
||||
"Contacts:Revision", "Contacts:GetRevision:Return:KO",]);
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Fix the environment to run Contacts tests
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/ContactService.jsm");
|
||||
SpecialPowers.Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
|
||||
}
|
||||
|
||||
SpecialPowers.addPermission("contacts-write", true, document);
|
||||
|
@ -3,15 +3,22 @@
|
||||
<script>
|
||||
var im = navigator.mozInputMethod;
|
||||
if (im) {
|
||||
// Automatically append location hash to current input field.
|
||||
im.oninputcontextchange = function() {
|
||||
var ctx = im.inputcontext;
|
||||
if (ctx) {
|
||||
intervalId = setTimeout(function() {
|
||||
ctx.replaceSurroundingText(location.hash);
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
im.oninputcontextchange = onIcc;
|
||||
|
||||
if (im.inputcontext) {
|
||||
onIcc();
|
||||
}
|
||||
}
|
||||
|
||||
function onIcc() {
|
||||
var ctx = im.inputcontext;
|
||||
if (ctx) {
|
||||
ctx.replaceSurroundingText(location.hash).then(function() {
|
||||
/* Happy flow */
|
||||
}, function(err) {
|
||||
dump('ReplaceSurroundingText failed ' + err + '\n');
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
[test_basic.html]
|
||||
[test_bug944397.html]
|
||||
[test_bug949059.html]
|
||||
[test_bug953044.html]
|
||||
[test_bug960946.html]
|
||||
[test_bug978918.html]
|
||||
[test_delete_focused_element.html]
|
||||
|
@ -23,85 +23,85 @@ inputmethod_setup(function() {
|
||||
function appFrameScript() {
|
||||
let input = content.document.getElementById('test-input');
|
||||
input.oninput = function() {
|
||||
dump('oninput was called in file_test_app.html.');
|
||||
sendAsyncMessage('test:InputMethod:oninput', {});
|
||||
sendAsyncMessage('test:InputMethod:oninput', {
|
||||
value: input.value
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Bug 957213. Sometimes we need to refocus the input field to avoid
|
||||
* intermittent test failure.
|
||||
*/
|
||||
content.setInterval(function() {
|
||||
input.focus();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
let timeoutId = null;
|
||||
let app, keyboard;
|
||||
|
||||
// Create an app frame to recieve keyboard inputs.
|
||||
let app = document.createElement('iframe');
|
||||
app.src = 'file_test_app.html';
|
||||
app.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(app);
|
||||
app.addEventListener('mozbrowserloadend', function() {
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(app);
|
||||
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
|
||||
mm.addMessageListener("test:InputMethod:oninput", function() {
|
||||
ok(true, 'Keyboard input was received.');
|
||||
clearTimeout(timeoutId);
|
||||
inputmethod_cleanup();
|
||||
});
|
||||
});
|
||||
|
||||
// Create a browser frame to load the input method app.
|
||||
let keyboard = document.createElement('iframe');
|
||||
keyboard.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(keyboard);
|
||||
|
||||
// Bug 953044 setInputMethodActive(false) before input method app loads should
|
||||
// always succeed.
|
||||
let req = keyboard.setInputMethodActive(false);
|
||||
req.onsuccess = function() {
|
||||
ok(true, 'setInputMethodActive before loading succeeded.');
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'setInputMethodActive before loading failed: ' + this.error.name);
|
||||
clearTimeout(timeoutId);
|
||||
inputmethod_cleanup();
|
||||
};
|
||||
/**
|
||||
* So this test does the following:
|
||||
* 1. Create a mozbrowser iframe with a text field in it, and focus the text field
|
||||
* 2. 100ms. after loading we create new keyboard iframe, that will try to execute
|
||||
* replaceSurroundingText on the current active inputcontext
|
||||
* 3. That should trigger 'input' event on the said text field
|
||||
* 4. And if that happens we know everything is OK
|
||||
*/
|
||||
|
||||
let path = location.pathname;
|
||||
let imeUrl = location.protocol + '//' + location.host +
|
||||
path.substring(0, path.lastIndexOf('/')) +
|
||||
'/file_inputmethod.html#data';
|
||||
SpecialPowers.pushPermissions([{
|
||||
type: 'input',
|
||||
allow: true,
|
||||
context: imeUrl
|
||||
}], function() {
|
||||
let req = keyboard.setInputMethodActive(true);
|
||||
let basePath = location.protocol + '//' + location.host +
|
||||
path.substring(0, path.lastIndexOf('/'));
|
||||
|
||||
req.onsuccess = function() {
|
||||
ok(true, 'setInputMethodActive succeeded.');
|
||||
};
|
||||
// STEP 1: Create an app frame to recieve keyboard inputs.
|
||||
function step1() {
|
||||
app = document.createElement('iframe');
|
||||
app.src = basePath + '/file_test_app.html';
|
||||
app.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(app);
|
||||
app.addEventListener('mozbrowserloadend', function() {
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(app);
|
||||
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
|
||||
mm.addMessageListener("test:InputMethod:oninput", function(ev) {
|
||||
step4(SpecialPowers.wrap(ev).json.value);
|
||||
});
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'setInputMethodActive failed: ' + this.error.name);
|
||||
inputmethod_cleanup();
|
||||
};
|
||||
step2();
|
||||
});
|
||||
}
|
||||
|
||||
// Loads the input method app to the browser frame after a delay.
|
||||
SpecialPowers.DOMWindowUtils.focus(app);
|
||||
setTimeout(function() {
|
||||
keyboard.src = imeUrl;
|
||||
timeoutId = setTimeout(function() {
|
||||
inputmethod_cleanup();
|
||||
ok(false, 'Failed to generate keyboard input.');
|
||||
}, 20000);
|
||||
}, 100);
|
||||
});
|
||||
function step2() {
|
||||
// STEP 2a: Create a browser frame to load the input method app.
|
||||
keyboard = document.createElement('iframe');
|
||||
keyboard.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(keyboard);
|
||||
|
||||
// STEP 2b: Grant input privileges to the keyboard iframe
|
||||
let imeUrl = basePath + '/file_inputmethod.html#data';
|
||||
|
||||
SpecialPowers.pushPermissions([{
|
||||
type: 'input',
|
||||
allow: true,
|
||||
context: imeUrl
|
||||
}], function() {
|
||||
// STEP 2c: Tell Gecko to use this iframe as its keyboard app
|
||||
let req = keyboard.setInputMethodActive(true);
|
||||
|
||||
req.onsuccess = function() {
|
||||
ok(true, 'setInputMethodActive succeeded.');
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'setInputMethodActive failed: ' + this.error.name);
|
||||
inputmethod_cleanup();
|
||||
};
|
||||
|
||||
// STEP 3: Loads the input method app to the browser frame after a delay.
|
||||
setTimeout(function() {
|
||||
keyboard.src = imeUrl;
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function step4(val) {
|
||||
ok(true, 'Keyboard input was received.');
|
||||
is(val, '#dataYuan', 'Input value');
|
||||
inputmethod_cleanup();
|
||||
}
|
||||
|
||||
step1();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
52
dom/inputmethod/mochitest/test_bug953044.html
Normal file
52
dom/inputmethod/mochitest/test_bug953044.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=953044
|
||||
-->
|
||||
<head>
|
||||
<title>Basic test for InputMethod API.</title>
|
||||
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript;version=1.7" src="inputmethod_common.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=953044">Mozilla Bug 953044</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
inputmethod_setup(function() {
|
||||
runTest();
|
||||
});
|
||||
|
||||
function runTest() {
|
||||
// Create an app frame to recieve keyboard inputs.
|
||||
let app = document.createElement('iframe');
|
||||
app.src = 'file_test_app.html';
|
||||
app.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(app);
|
||||
|
||||
// Create a browser frame to load the input method app.
|
||||
let keyboard = document.createElement('iframe');
|
||||
keyboard.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(keyboard);
|
||||
|
||||
// Bug 953044 setInputMethodActive(false) before input method app loads should
|
||||
// always succeed.
|
||||
let req = keyboard.setInputMethodActive(false);
|
||||
req.onsuccess = function() {
|
||||
ok(true, 'setInputMethodActive before loading succeeded.');
|
||||
inputmethod_cleanup();
|
||||
};
|
||||
|
||||
req.onerror = function() {
|
||||
ok(false, 'setInputMethodActive before loading failed: ' + this.error.name);
|
||||
inputmethod_cleanup();
|
||||
};
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -48,8 +48,9 @@ interface nsIRunnable;
|
||||
interface nsICompositionStringSynthesizer;
|
||||
interface nsITranslationNodeList;
|
||||
interface nsIJSRAIIHelper;
|
||||
interface nsIContentPermissionRequest;
|
||||
|
||||
[scriptable, uuid(e156a9f5-d0e3-4a2f-a4a8-19c648d5ecb9)]
|
||||
[scriptable, uuid(ca202fa7-7b8f-4814-acc3-a8545f67320b)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -1671,6 +1672,12 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
* purpose of the test for bug 503926.
|
||||
*/
|
||||
void xpconnectArgument(in nsIDOMWindowUtils aThis);
|
||||
|
||||
/**
|
||||
* Helper for JS components that need to send permission requests with
|
||||
* e10s support properly.
|
||||
*/
|
||||
void askPermission(in nsIContentPermissionRequest aRequest);
|
||||
};
|
||||
|
||||
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
|
||||
|
@ -10,6 +10,7 @@
|
||||
// XXXbz Doing this in a header is a gigantic footgun. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=932421#c3 for why.
|
||||
#undef CreateEvent
|
||||
#undef LoadImage
|
||||
|
||||
/*
|
||||
PContentPermissionRequestChild implementations also are
|
||||
|
@ -35,38 +35,6 @@ namespace mozilla {
|
||||
|
||||
static MediaPermissionManager *gMediaPermMgr = nullptr;
|
||||
|
||||
static uint32_t
|
||||
ConvertArrayToPermissionRequest(nsIArray* aSrcArray,
|
||||
nsTArray<PermissionRequest>& aDesArray)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
aSrcArray->GetLength(&len);
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
nsCOMPtr<nsIContentPermissionType> cpt = do_QueryElementAt(aSrcArray, i);
|
||||
nsAutoCString type;
|
||||
nsAutoCString access;
|
||||
cpt->GetType(type);
|
||||
cpt->GetAccess(access);
|
||||
|
||||
nsCOMPtr<nsIArray> optionArray;
|
||||
cpt->GetOptions(getter_AddRefs(optionArray));
|
||||
uint32_t optionsLength = 0;
|
||||
optionArray->GetLength(&optionsLength);
|
||||
nsTArray<nsString> options;
|
||||
for (uint32_t j = 0; j < optionsLength; ++j) {
|
||||
nsCOMPtr<nsISupportsString> isupportsString = do_QueryElementAt(optionArray, j);
|
||||
if (isupportsString) {
|
||||
nsString option;
|
||||
isupportsString->GetData(option);
|
||||
options.AppendElement(option);
|
||||
}
|
||||
}
|
||||
|
||||
aDesArray.AppendElement(PermissionRequest(type, access, options));
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
|
||||
nsTArray<nsString> &aDeviceNameList)
|
||||
@ -449,7 +417,7 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsTArray<PermissionRequest> permArray;
|
||||
ConvertArrayToPermissionRequest(typeArray, permArray);
|
||||
RemotePermissionRequest::ConvertArrayToPermissionRequest(typeArray, permArray);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = req->GetPrincipal(getter_AddRefs(principal));
|
||||
|
@ -5,3 +5,5 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
PARALLEL_DIRS += ['interfaces', 'src']
|
||||
|
||||
TEST_DIRS += ['test']
|
||||
|
5
dom/mobileid/test/mochitest.ini
Normal file
5
dom/mobileid/test/mochitest.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = (buildapp != 'b2g')
|
||||
|
||||
[test_mobileid_basics.html]
|
||||
[test_mobileid_no_permission.html]
|
@ -4,3 +4,4 @@
|
||||
# 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/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
78
dom/mobileid/test/test_mobileid_basics.html
Normal file
78
dom/mobileid/test/test_mobileid_basics.html
Normal file
@ -0,0 +1,78 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for navigator.getMobileIdAssertion</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
const MOCK_CID = SpecialPowers.wrap(SpecialPowers.Components)
|
||||
.ID("{4cb9b8b3-bc8c-46c0-a2b6-2eb0b1ffce94}");
|
||||
const MOBILE_ID_SERVICE_CONTRACT_ID = "@mozilla.org/mobileidentity-service;1";
|
||||
|
||||
function finish() {
|
||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
||||
.unregisterFactory(MOCK_CID, mockMobileIdService);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var mockMobileIdService = {
|
||||
QueryInterface: function(aIID) {
|
||||
if (SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsISupports) ||
|
||||
SpecialPowers.wrap(aIID).equals(SpecialPowers.Ci.nsIMobileIdentityService)) {
|
||||
return this;
|
||||
}
|
||||
throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter != null) {
|
||||
throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
getMobileIdAssertion: function(aWindow, aOptions) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
resolve(aOptions);
|
||||
});
|
||||
}
|
||||
};
|
||||
mockMobileIdService = SpecialPowers.wrapCallbackObject(mockMobileIdService);
|
||||
|
||||
SpecialPowers.wrap(SpecialPowers.Components).manager
|
||||
.QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar)
|
||||
.registerFactory(MOCK_CID, "mobileid service",
|
||||
MOBILE_ID_SERVICE_CONTRACT_ID,
|
||||
mockMobileIdService);
|
||||
|
||||
// Tests
|
||||
|
||||
SpecialPowers.pushPermissions([{"type": "mobileid",
|
||||
"allow": 1,
|
||||
"context": document}], function() {
|
||||
ok("getMobileIdAssertion" in navigator,
|
||||
"navigator.getMobileIdAssertion should exist");
|
||||
|
||||
var options = { forceSelection: true };
|
||||
var promise = navigator.getMobileIdAssertion(options)
|
||||
.then(function(result) {
|
||||
ok(promise instanceof Promise, "Should return a Promise");
|
||||
is(result.forceSelection, options.forceSelection,
|
||||
"MobileIdentityService should receive correct options");
|
||||
finish();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
24
dom/mobileid/test/test_mobileid_no_permission.html
Normal file
24
dom/mobileid/test/test_mobileid_no_permission.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for navigator.getMobileIdAssertion - No permission</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
ok(!("getMobileIdAssertion" in navigator),
|
||||
"navigator.getMobileIdAssertion should NOT exist");
|
||||
|
||||
SimpleTest.finish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -82,6 +82,16 @@ let emulator = (function() {
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
function clearTagData(re) {
|
||||
let deferred = Promise.defer();
|
||||
let cmd = "nfc tag clear " + re;
|
||||
|
||||
this.run(cmd, function(result) {
|
||||
is(result.pop(), "OK", "clear tag" + re);
|
||||
deferred.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function snepPutNdef(dsap, ssap, flags, tnf, type, payload, id) {
|
||||
let deferred = Promise.defer();
|
||||
let cmd = "nfc snep put " + dsap + " " + ssap + " [" + flags + "," +
|
||||
@ -103,6 +113,7 @@ let emulator = (function() {
|
||||
deactivate: deactivate,
|
||||
notifyDiscoverRE: notifyDiscoverRE,
|
||||
setTagData: setTagData,
|
||||
clearTagData: clearTagData,
|
||||
snepPutNdef: snepPutNdef
|
||||
};
|
||||
}());
|
||||
|
@ -10,6 +10,6 @@ qemu=true
|
||||
[test_nfc_manager_tech_lost.js]
|
||||
[test_nfc_peer.js]
|
||||
[test_nfc_peer_sendndef.js]
|
||||
[test_nfc_tag.js]
|
||||
[test_nfc_read_tag.js]
|
||||
[test_nfc_checkP2PRegistration.js]
|
||||
[test_nfc_error_messages.js]
|
||||
|
@ -6,11 +6,10 @@ MARIONETTE_HEAD_JS = "head.js";
|
||||
|
||||
let url = "http://www.mozilla.org";
|
||||
|
||||
// TODO : Get this from emulator console command.
|
||||
const T1T_RE_INDEX = 2;
|
||||
const T2T_RE_INDEX = 3;
|
||||
const T3T_RE_INDEX = 4;
|
||||
const T4T_RE_INDEX = 5;
|
||||
const T1T_RE_INDEX = 2;
|
||||
const T2T_RE_INDEX = 3;
|
||||
const T3T_RE_INDEX = 4;
|
||||
const T4T_RE_INDEX = 5;
|
||||
|
||||
function testUrlTagDiscover(re) {
|
||||
log("Running \'testUrlTagDiscover\'");
|
||||
@ -41,6 +40,26 @@ function testUrlTagDiscover(re) {
|
||||
.then(() => emulator.activateRE(re));
|
||||
}
|
||||
|
||||
function testEmptyTagDiscover(re) {
|
||||
log("Running \'testEmptyTagDiscover\'");
|
||||
|
||||
window.navigator.mozSetMessageHandler("nfc-manager-tech-discovered", function(msg) {
|
||||
log("Received \'nfc-manager-tech-ndiscovered\'");
|
||||
is(msg.type, "techDiscovered", "check for correct message type");
|
||||
let index = msg.techList.indexOf("NDEF");
|
||||
isnot(index, -1, "check for \'NDEF\' in tech list");
|
||||
|
||||
let records = msg.records;
|
||||
ok(records == null);
|
||||
|
||||
toggleNFC(false).then(runNextTest);
|
||||
});
|
||||
|
||||
toggleNFC(true)
|
||||
.then(() => emulator.clearTagData(re))
|
||||
.then(() => emulator.activateRE(re));
|
||||
}
|
||||
|
||||
function testUrlT1TDiscover() {
|
||||
testUrlTagDiscover(T1T_RE_INDEX);
|
||||
}
|
||||
@ -57,11 +76,31 @@ function testUrlT4TDiscover() {
|
||||
testUrlTagDiscover(T4T_RE_INDEX);
|
||||
}
|
||||
|
||||
function testEmptyT1TDiscover() {
|
||||
testEmptyTagDiscover(T1T_RE_INDEX);
|
||||
}
|
||||
|
||||
function testEmptyT2TDiscover() {
|
||||
testEmptyTagDiscover(T2T_RE_INDEX);
|
||||
}
|
||||
|
||||
function testEmptyT3TDiscover() {
|
||||
testEmptyTagDiscover(T3T_RE_INDEX);
|
||||
}
|
||||
|
||||
function testEmptyT4TDiscover() {
|
||||
testEmptyTagDiscover(T4T_RE_INDEX);
|
||||
}
|
||||
|
||||
let tests = [
|
||||
testUrlT1TDiscover,
|
||||
testUrlT2TDiscover,
|
||||
testUrlT3TDiscover,
|
||||
testUrlT4TDiscover
|
||||
testUrlT1TDiscover,
|
||||
testUrlT2TDiscover,
|
||||
testUrlT3TDiscover,
|
||||
testUrlT4TDiscover,
|
||||
testEmptyT1TDiscover,
|
||||
testEmptyT2TDiscover,
|
||||
testEmptyT3TDiscover,
|
||||
testEmptyT4TDiscover
|
||||
];
|
||||
|
||||
SpecialPowers.pushPermissions(
|
@ -1,146 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* PermissionPromptHelper checks the permissionDB for a given permission
|
||||
* name and performs prompting if needed.
|
||||
* Usage: send PermissionPromptHelper:AskPermission via the FrameMessageManager with:
|
||||
* |origin|, |appID|, |browserFlag| -> used for getting the principal and
|
||||
* |type| and |access| to call testExactPermissionFromPrincipal.
|
||||
* Note that |access| isn't currently used.
|
||||
* Other arugments are:
|
||||
* requestID: ID that gets returned with the result message.
|
||||
*
|
||||
* Once the permission is checked, it returns with the message
|
||||
* "PermissionPromptHelper:AskPermission:OK"
|
||||
* The result contains the |result| e.g.Ci.nsIPermissionManager.ALLOW_ACTION
|
||||
* and a requestID that
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let DEBUG = 0;
|
||||
let debug;
|
||||
if (DEBUG)
|
||||
debug = function (s) { dump("-*- Permission Prompt Helper component: " + s + "\n"); }
|
||||
else
|
||||
debug = function (s) {}
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PermissionPromptHelper"];
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "permissionPromptService",
|
||||
"@mozilla.org/permission-prompt-service;1",
|
||||
"nsIPermissionPromptService");
|
||||
|
||||
let appsService = Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
|
||||
|
||||
this.PermissionPromptHelper = {
|
||||
init: function init() {
|
||||
debug("Init");
|
||||
ppmm.addMessageListener("PermissionPromptHelper:AskPermission", this);
|
||||
Services.obs.addObserver(this, "profile-before-change", false);
|
||||
},
|
||||
|
||||
askPermission: function askPermission(aMessage, aCallbacks) {
|
||||
let msg = aMessage.json;
|
||||
|
||||
let access = msg.type;
|
||||
if (msg.access) {
|
||||
access = access + "-" + msg.access;
|
||||
}
|
||||
|
||||
let uri = Services.io.newURI(msg.origin, null, null);
|
||||
let principal =
|
||||
Services.scriptSecurityManager.getAppCodebasePrincipal(uri, msg.appID, msg.browserFlag);
|
||||
|
||||
let permValue =
|
||||
Services.perms.testExactPermissionFromPrincipal(principal, access);
|
||||
|
||||
if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
|
||||
permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
|
||||
aCallbacks.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (permValue == Ci.nsIPermissionManager.PROMPT_ACTION) {
|
||||
|
||||
// create the options from permission request.
|
||||
let options = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
if (msg.options) {
|
||||
for (let option of options) {
|
||||
options.appendElement(option);
|
||||
}
|
||||
}
|
||||
|
||||
// create an array with a nsIContentPermissionType element
|
||||
let type = {
|
||||
type: msg.type,
|
||||
access: msg.access ? msg.access : "unused",
|
||||
options: options,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
|
||||
};
|
||||
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
typeArray.appendElement(type, false);
|
||||
|
||||
// create a nsIContentPermissionRequest
|
||||
let request = {
|
||||
types: typeArray,
|
||||
principal: principal,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
|
||||
allow: aCallbacks.allow,
|
||||
cancel: aCallbacks.cancel,
|
||||
window: Services.wm.getOuterWindowWithId(msg.windowID)
|
||||
};
|
||||
|
||||
permissionPromptService.getPermission(request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
aCallbacks.allow();
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
ppmm.removeMessageListener("PermissionPromptHelper:AskPermission", this);
|
||||
Services.obs.removeObserver(this, "profile-before-change");
|
||||
ppmm = null;
|
||||
},
|
||||
|
||||
receiveMessage: function receiveMessage(aMessage) {
|
||||
debug("PermissionPromptHelper::receiveMessage " + aMessage.name);
|
||||
let mm = aMessage.target;
|
||||
let msg = aMessage.data;
|
||||
|
||||
let result;
|
||||
if (aMessage.name == "PermissionPromptHelper:AskPermission") {
|
||||
this.askPermission(aMessage, {
|
||||
cancel: function() {
|
||||
mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
|
||||
{ result: Ci.nsIPermissionManager.DENY_ACTION,
|
||||
requestID: msg.requestID });
|
||||
},
|
||||
allow: function(aChoice) {
|
||||
mm.sendAsyncMessage("PermissionPromptHelper:AskPermission:OK",
|
||||
{ result: Ci.nsIPermissionManager.ALLOW_ACTION,
|
||||
choice: aChoice,
|
||||
requestID: msg.requestID });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PermissionPromptHelper.init();
|
@ -14,6 +14,5 @@ EXTRA_COMPONENTS += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'PermissionPromptHelper.jsm',
|
||||
'PermissionSettings.jsm',
|
||||
]
|
||||
|
@ -92,7 +92,7 @@
|
||||
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true"/>
|
||||
|
||||
#ifdef MOZ_NATIVE_DEVICES
|
||||
#ifdef MOZ_NATIVE_CASTING
|
||||
<!-- This resources comes from Google Play Services. Required for casting support. -->
|
||||
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
|
||||
#endif
|
||||
|
@ -164,7 +164,7 @@ public class AppConstants {
|
||||
#endif
|
||||
|
||||
public static final boolean MOZ_MEDIA_PLAYER =
|
||||
#ifdef MOZ_NATIVE_DEVICES
|
||||
#ifdef MOZ_NATIVE_CASTING
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
|
@ -550,19 +550,6 @@ public class BrowserApp extends GeckoApp
|
||||
|
||||
Distribution.init(this);
|
||||
|
||||
// Shipping Native casting is optional and dependent on whether you've downloaded the support
|
||||
// and google play libraries
|
||||
if (AppConstants.MOZ_MEDIA_PLAYER) {
|
||||
try {
|
||||
Class<?> mediaManagerClass = Class.forName("org.mozilla.gecko.MediaPlayerManager");
|
||||
Method init = mediaManagerClass.getMethod("init", Context.class);
|
||||
init.invoke(null, this);
|
||||
} catch(Exception ex) {
|
||||
// Ignore failures
|
||||
Log.i(LOGTAG, "No native casting support", ex);
|
||||
}
|
||||
}
|
||||
|
||||
JavaAddonManager.getInstance().init(getApplicationContext());
|
||||
mSharedPreferencesHelper = new SharedPreferencesHelper(getApplicationContext());
|
||||
mOrderedBroadcastHelper = new OrderedBroadcastHelper(getApplicationContext());
|
||||
|
@ -19,10 +19,12 @@ import com.google.android.gms.cast.MediaMetadata;
|
||||
import com.google.android.gms.cast.MediaStatus;
|
||||
import com.google.android.gms.cast.RemoteMediaPlayer;
|
||||
import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
@ -131,6 +133,11 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
|
||||
public ChromeCast(Context context, RouteInfo route) {
|
||||
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
|
||||
if (status != ConnectionResult.SUCCESS) {
|
||||
throw new IllegalStateException("Play services are required for Chromecast support (go status code " + status + ")");
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
this.route = route;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ JAVA_BOOTCLASSPATH = \
|
||||
JAVA_BOOTCLASSPATH := $(subst $(NULL) ,:,$(strip $(JAVA_BOOTCLASSPATH)))
|
||||
|
||||
# If native devices are enabled, add Google Play Services and some of the v7 compat libraries
|
||||
ifdef MOZ_NATIVE_DEVICES
|
||||
ifdef MOZ_NATIVE_CASTING
|
||||
JAVA_CLASSPATH += \
|
||||
$(GOOGLE_PLAY_SERVICES_LIB) \
|
||||
$(ANDROID_MEDIAROUTER_LIB) \
|
||||
@ -304,7 +304,7 @@ generated/android/support/v7/appcompat/R.java: .aapt.deps ;
|
||||
generated/android/support/v7/mediarouter/R.java: .aapt.deps ;
|
||||
generated/com/google/android/gms/R.java: .aapt.deps ;
|
||||
|
||||
ifdef MOZ_NATIVE_DEVICES
|
||||
ifdef MOZ_NATIVE_CASTING
|
||||
extra_packages += android.support.v7.appcompat
|
||||
extra_res_dirs += $(ANDROID_APPCOMPAT_RES)
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.mozglue.JNITarget;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
|
||||
@ -36,7 +37,7 @@ interface GeckoMediaPlayer {
|
||||
* from Gecko to the correct caster based on the id of the display
|
||||
*/
|
||||
class MediaPlayerManager implements NativeEventListener,
|
||||
GeckoAppShell.AppStateListener {
|
||||
GeckoAppShell.AppStateListener {
|
||||
private static final String LOGTAG = "GeckoMediaPlayerManager";
|
||||
|
||||
private static final boolean SHOW_DEBUG = false;
|
||||
@ -58,6 +59,7 @@ class MediaPlayerManager implements NativeEventListener,
|
||||
private final HashMap<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
|
||||
private static MediaPlayerManager instance;
|
||||
|
||||
@JNITarget
|
||||
public static void init(Context context) {
|
||||
if (instance != null) {
|
||||
debug("MediaPlayerManager initialized twice");
|
||||
@ -84,6 +86,7 @@ class MediaPlayerManager implements NativeEventListener,
|
||||
"MediaPlayer:End");
|
||||
}
|
||||
|
||||
@JNITarget
|
||||
public static void onDestroy() {
|
||||
if (instance == null) {
|
||||
return;
|
||||
|
@ -185,9 +185,6 @@ public interface TelemetryContract {
|
||||
// Awesomescreen frecency search is active.
|
||||
FRECENCY("frecency.1"),
|
||||
|
||||
// Started when a user enters about:home.
|
||||
HOME("home.1"),
|
||||
|
||||
// Started when a user enters a given home panel.
|
||||
// Session name is dynamic, encoded as "homepanel.1:<panel_id>"
|
||||
HOME_PANEL("homepanel.1"),
|
||||
|
@ -231,7 +231,6 @@ public class HomePager extends ViewPager {
|
||||
PropertyAnimator.Property.ALPHA,
|
||||
1.0f);
|
||||
}
|
||||
Telemetry.startUISession(TelemetryContract.Session.HOME);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -244,7 +243,6 @@ public class HomePager extends ViewPager {
|
||||
|
||||
// Stop UI Telemetry sessions.
|
||||
stopCurrentPanelTelemetrySession();
|
||||
Telemetry.stopUISession(TelemetryContract.Session.HOME);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ resjar.generated_sources += [
|
||||
'org/mozilla/gecko/R.java',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_NATIVE_DEVICES']:
|
||||
if CONFIG['MOZ_NATIVE_CASTING']:
|
||||
resjar.generated_sources += ['com/google/android/gms/R.java']
|
||||
resjar.generated_sources += ['android/support/v7/appcompat/R.java']
|
||||
resjar.generated_sources += ['android/support/v7/mediarouter/R.java']
|
||||
@ -473,7 +473,7 @@ gbjar.extra_jars = [
|
||||
'websockets.jar',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_NATIVE_DEVICES']:
|
||||
if CONFIG['MOZ_NATIVE_CASTING']:
|
||||
gbjar.extra_jars += [CONFIG['ANDROID_APPCOMPAT_LIB']]
|
||||
gbjar.extra_jars += [CONFIG['ANDROID_MEDIAROUTER_LIB']]
|
||||
gbjar.extra_jars += [CONFIG['GOOGLE_PLAY_SERVICES_LIB']]
|
||||
@ -530,7 +530,7 @@ ANDROID_GENERATED_RESFILES += [
|
||||
]
|
||||
|
||||
for var in ('MOZ_ANDROID_ANR_REPORTER', 'MOZ_LINKER_EXTRACT', 'MOZILLA_OFFICIAL', 'MOZ_DEBUG',
|
||||
'MOZ_ANDROID_SEARCH_ACTIVITY', 'MOZ_NATIVE_DEVICES'):
|
||||
'MOZ_ANDROID_SEARCH_ACTIVITY', 'MOZ_NATIVE_CASTING'):
|
||||
if CONFIG[var]:
|
||||
DEFINES[var] = 1
|
||||
|
||||
@ -613,7 +613,7 @@ cpe = main.add_classpathentry('src', SRCDIR,
|
||||
'org/mozilla/gecko/resources/**'])
|
||||
if not CONFIG['MOZ_CRASHREPORTER']:
|
||||
cpe.exclude_patterns += ['org/mozilla/gecko/CrashReporter.java']
|
||||
if not CONFIG['MOZ_NATIVE_DEVICES']:
|
||||
if not CONFIG['MOZ_NATIVE_CASTING']:
|
||||
cpe.exclude_patterns += ['org/mozilla/gecko/ChromeCast.java']
|
||||
cpe.exclude_patterns += ['org/mozilla/gecko/MediaPlayerManager.java']
|
||||
main.add_classpathentry('generated', OBJDIR + '/generated',
|
||||
|
@ -9,7 +9,6 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionPromptHelper.jsm");
|
||||
Cu.import("resource://gre/modules/ContactService.jsm");
|
||||
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
||||
|
||||
|
@ -330,34 +330,37 @@ var Addons = {
|
||||
try {
|
||||
let optionsURL = aListItem.getAttribute("optionsURL");
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", optionsURL, false);
|
||||
xhr.send();
|
||||
if (xhr.responseXML) {
|
||||
// Only allow <setting> for now
|
||||
let settings = xhr.responseXML.querySelectorAll(":root > setting");
|
||||
if (settings.length > 0) {
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
var setting = settings[i];
|
||||
var desc = stripTextNodes(setting).trim();
|
||||
if (!setting.hasAttribute("desc"))
|
||||
setting.setAttribute("desc", desc);
|
||||
box.appendChild(setting);
|
||||
}
|
||||
// Send an event so add-ons can prepopulate any non-preference based
|
||||
// settings
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("AddonOptionsLoad", true, false);
|
||||
window.dispatchEvent(event);
|
||||
xhr.open("GET", optionsURL, true);
|
||||
xhr.onload = function(e) {
|
||||
if (xhr.responseXML) {
|
||||
// Only allow <setting> for now
|
||||
let settings = xhr.responseXML.querySelectorAll(":root > setting");
|
||||
if (settings.length > 0) {
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
var setting = settings[i];
|
||||
var desc = stripTextNodes(setting).trim();
|
||||
if (!setting.hasAttribute("desc")) {
|
||||
setting.setAttribute("desc", desc);
|
||||
}
|
||||
box.appendChild(setting);
|
||||
}
|
||||
// Send an event so add-ons can prepopulate any non-preference based
|
||||
// settings
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("AddonOptionsLoad", true, false);
|
||||
window.dispatchEvent(event);
|
||||
|
||||
// Also send a notification to match the behavior of desktop Firefox
|
||||
let id = aListItem.getAttribute("addonID");
|
||||
Services.obs.notifyObservers(document, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, id);
|
||||
} else {
|
||||
// No options, so hide the header and reset the list item
|
||||
detailItem.setAttribute("optionsURL", "");
|
||||
aListItem.setAttribute("optionsURL", "");
|
||||
// Also send a notification to match the behavior of desktop Firefox
|
||||
let id = aListItem.getAttribute("addonID");
|
||||
Services.obs.notifyObservers(document, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, id);
|
||||
} else {
|
||||
// No options, so hide the header and reset the list item
|
||||
detailItem.setAttribute("optionsURL", "");
|
||||
aListItem.setAttribute("optionsURL", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(null);
|
||||
} catch (e) { }
|
||||
|
||||
let list = document.querySelector("#addons-list");
|
||||
|
@ -32,6 +32,7 @@ ac_add_options --with-android-gnu-compiler-version=4.7
|
||||
ac_add_options --with-android-version=9
|
||||
ac_add_options --with-system-zlib
|
||||
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
|
||||
ac_add_options --disable-native-casting # Disable native casting support until the builders are updated
|
||||
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
@ -69,8 +69,5 @@ MOZ_LOCALE_SWITCHER=1
|
||||
# Enable second screen and casting support for external devices.
|
||||
MOZ_DEVICES=1
|
||||
|
||||
# Enable second screen using native Android libraries
|
||||
MOZ_NATIVE_DEVICES=
|
||||
|
||||
# Don't enable the Search Activity.
|
||||
# MOZ_ANDROID_SEARCH_ACTIVITY=1
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
ANDROID_APK_NAME := background-junit3-debug
|
||||
|
||||
ANDROID_EXTRA_JARS := \
|
||||
background-junit3.jar \
|
||||
$(NULL)
|
||||
|
||||
PP_TARGETS += manifest
|
||||
manifest := $(srcdir)/AndroidManifest.xml.in
|
||||
manifest_TARGET := AndroidManifest.xml
|
||||
@ -17,16 +21,11 @@ ANDROID_MANIFEST_FILE := $(CURDIR)/AndroidManifest.xml
|
||||
|
||||
GARBAGE += AndroidManifest.xml
|
||||
|
||||
include $(srcdir)/android-services-files.mk
|
||||
|
||||
# BACKGROUND_TESTS_{JAVA,RES}_FILES are defined in android-services-files.mk.
|
||||
JAVAFILES := $(BACKGROUND_TESTS_JAVA_FILES)
|
||||
|
||||
# The test APK needs to know the contents of the target APK while not
|
||||
# being linked against them. This is a best effort to avoid getting
|
||||
# out of sync with base's build config.
|
||||
JARS_DIR := $(DEPTH)/mobile/android/base
|
||||
JAVA_BOOTCLASSPATH := $(JAVA_BOOTCLASSPATH):$(subst $(NULL) ,:,$(wildcard $(JARS_DIR)/*.jar))
|
||||
JAVA_BOOTCLASSPATH := $(ANDROID_SDK)/android.jar:$(subst $(NULL) ,:,$(wildcard $(JARS_DIR)/*.jar))
|
||||
# We also want to re-compile classes.dex when the associated base
|
||||
# content changes.
|
||||
classes.dex: $(wildcard $(JARS_DIR)/*.jar)
|
||||
|
@ -1,110 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# These files are managed in the android-sync repo. Do not modify directly, or your changes will be lost.
|
||||
BACKGROUND_TESTS_JAVA_FILES := \
|
||||
src/announcements/TestAnnouncementsBroadcastService.java \
|
||||
src/common/TestAndroidLogWriters.java \
|
||||
src/common/TestBrowserContractHelpers.java \
|
||||
src/common/TestDateUtils.java \
|
||||
src/common/TestUtils.java \
|
||||
src/common/TestWaitHelper.java \
|
||||
src/db/AndroidBrowserRepositoryTestCase.java \
|
||||
src/db/TestAndroidBrowserBookmarksRepository.java \
|
||||
src/db/TestAndroidBrowserHistoryDataExtender.java \
|
||||
src/db/TestAndroidBrowserHistoryRepository.java \
|
||||
src/db/TestBookmarks.java \
|
||||
src/db/TestCachedSQLiteOpenHelper.java \
|
||||
src/db/TestClientsDatabase.java \
|
||||
src/db/TestClientsDatabaseAccessor.java \
|
||||
src/db/TestFennecTabsRepositorySession.java \
|
||||
src/db/TestFennecTabsStorage.java \
|
||||
src/db/TestFormHistoryRepositorySession.java \
|
||||
src/db/TestPasswordsRepository.java \
|
||||
src/fxa/authenticator/TestAccountPickler.java \
|
||||
src/fxa/TestBrowserIDKeyPairGeneration.java \
|
||||
src/fxa/TestFirefoxAccounts.java \
|
||||
src/healthreport/MockDatabaseEnvironment.java \
|
||||
src/healthreport/MockHealthReportDatabaseStorage.java \
|
||||
src/healthreport/MockHealthReportSQLiteOpenHelper.java \
|
||||
src/healthreport/MockProfileInformationCache.java \
|
||||
src/healthreport/prune/TestHealthReportPruneService.java \
|
||||
src/healthreport/prune/TestPrunePolicyDatabaseStorage.java \
|
||||
src/healthreport/TestEnvironmentBuilder.java \
|
||||
src/healthreport/TestEnvironmentV1HashAppender.java \
|
||||
src/healthreport/TestHealthReportBroadcastService.java \
|
||||
src/healthreport/TestHealthReportDatabaseStorage.java \
|
||||
src/healthreport/TestHealthReportGenerator.java \
|
||||
src/healthreport/TestHealthReportProvider.java \
|
||||
src/healthreport/TestHealthReportSQLiteOpenHelper.java \
|
||||
src/healthreport/TestProfileInformationCache.java \
|
||||
src/healthreport/upload/TestAndroidSubmissionClient.java \
|
||||
src/healthreport/upload/TestHealthReportUploadService.java \
|
||||
src/helpers/AndroidSyncTestCase.java \
|
||||
src/helpers/BackgroundServiceTestCase.java \
|
||||
src/helpers/DBHelpers.java \
|
||||
src/helpers/DBProviderTestCase.java \
|
||||
src/helpers/FakeProfileTestCase.java \
|
||||
src/nativecode/test/TestNativeCrypto.java \
|
||||
src/sync/AndroidSyncTestCaseWithAccounts.java \
|
||||
src/sync/helpers/BookmarkHelpers.java \
|
||||
src/sync/helpers/DefaultBeginDelegate.java \
|
||||
src/sync/helpers/DefaultCleanDelegate.java \
|
||||
src/sync/helpers/DefaultDelegate.java \
|
||||
src/sync/helpers/DefaultFetchDelegate.java \
|
||||
src/sync/helpers/DefaultFinishDelegate.java \
|
||||
src/sync/helpers/DefaultGuidsSinceDelegate.java \
|
||||
src/sync/helpers/DefaultSessionCreationDelegate.java \
|
||||
src/sync/helpers/DefaultStoreDelegate.java \
|
||||
src/sync/helpers/ExpectBeginDelegate.java \
|
||||
src/sync/helpers/ExpectBeginFailDelegate.java \
|
||||
src/sync/helpers/ExpectFetchDelegate.java \
|
||||
src/sync/helpers/ExpectFetchSinceDelegate.java \
|
||||
src/sync/helpers/ExpectFinishDelegate.java \
|
||||
src/sync/helpers/ExpectFinishFailDelegate.java \
|
||||
src/sync/helpers/ExpectGuidsSinceDelegate.java \
|
||||
src/sync/helpers/ExpectInvalidRequestFetchDelegate.java \
|
||||
src/sync/helpers/ExpectInvalidTypeStoreDelegate.java \
|
||||
src/sync/helpers/ExpectManyStoredDelegate.java \
|
||||
src/sync/helpers/ExpectNoGUIDsSinceDelegate.java \
|
||||
src/sync/helpers/ExpectStoreCompletedDelegate.java \
|
||||
src/sync/helpers/ExpectStoredDelegate.java \
|
||||
src/sync/helpers/HistoryHelpers.java \
|
||||
src/sync/helpers/PasswordHelpers.java \
|
||||
src/sync/helpers/SessionTestHelper.java \
|
||||
src/sync/helpers/SimpleSuccessBeginDelegate.java \
|
||||
src/sync/helpers/SimpleSuccessCreationDelegate.java \
|
||||
src/sync/helpers/SimpleSuccessFetchDelegate.java \
|
||||
src/sync/helpers/SimpleSuccessFinishDelegate.java \
|
||||
src/sync/helpers/SimpleSuccessStoreDelegate.java \
|
||||
src/sync/TestAccountPickler.java \
|
||||
src/sync/TestClientsStage.java \
|
||||
src/sync/TestConfigurationMigrator.java \
|
||||
src/sync/TestResetting.java \
|
||||
src/sync/TestSendTabData.java \
|
||||
src/sync/TestStoreTracking.java \
|
||||
src/sync/TestSyncAccounts.java \
|
||||
src/sync/TestSyncAuthenticatorService.java \
|
||||
src/sync/TestSyncConfiguration.java \
|
||||
src/sync/TestTabsRecord.java \
|
||||
src/sync/TestUpgradeRequired.java \
|
||||
src/sync/TestWebURLFinder.java \
|
||||
src/telemetry/TestTelemetryRecorder.java \
|
||||
src/testhelpers/BaseMockServerSyncStage.java \
|
||||
src/testhelpers/CommandHelpers.java \
|
||||
src/testhelpers/DefaultGlobalSessionCallback.java \
|
||||
src/testhelpers/JPakeNumGeneratorFixed.java \
|
||||
src/testhelpers/MockAbstractNonRepositorySyncStage.java \
|
||||
src/testhelpers/MockClientsDatabaseAccessor.java \
|
||||
src/testhelpers/MockClientsDataDelegate.java \
|
||||
src/testhelpers/MockGlobalSession.java \
|
||||
src/testhelpers/MockPrefsGlobalSession.java \
|
||||
src/testhelpers/MockRecord.java \
|
||||
src/testhelpers/MockServerSyncStage.java \
|
||||
src/testhelpers/MockSharedPreferences.java \
|
||||
src/testhelpers/StubDelegate.java \
|
||||
src/testhelpers/WaitHelper.java \
|
||||
src/testhelpers/WBORepository.java \
|
||||
$(NULL)
|
||||
|
@ -0,0 +1,110 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
background_junit3_sources = [
|
||||
'src/announcements/TestAnnouncementsBroadcastService.java',
|
||||
'src/common/TestAndroidLogWriters.java',
|
||||
'src/common/TestBrowserContractHelpers.java',
|
||||
'src/common/TestDateUtils.java',
|
||||
'src/common/TestUtils.java',
|
||||
'src/common/TestWaitHelper.java',
|
||||
'src/db/AndroidBrowserRepositoryTestCase.java',
|
||||
'src/db/TestAndroidBrowserBookmarksRepository.java',
|
||||
'src/db/TestAndroidBrowserHistoryDataExtender.java',
|
||||
'src/db/TestAndroidBrowserHistoryRepository.java',
|
||||
'src/db/TestBookmarks.java',
|
||||
'src/db/TestCachedSQLiteOpenHelper.java',
|
||||
'src/db/TestClientsDatabase.java',
|
||||
'src/db/TestClientsDatabaseAccessor.java',
|
||||
'src/db/TestFennecTabsRepositorySession.java',
|
||||
'src/db/TestFennecTabsStorage.java',
|
||||
'src/db/TestFormHistoryRepositorySession.java',
|
||||
'src/db/TestPasswordsRepository.java',
|
||||
'src/fxa/authenticator/TestAccountPickler.java',
|
||||
'src/fxa/TestBrowserIDKeyPairGeneration.java',
|
||||
'src/fxa/TestFirefoxAccounts.java',
|
||||
'src/healthreport/MockDatabaseEnvironment.java',
|
||||
'src/healthreport/MockHealthReportDatabaseStorage.java',
|
||||
'src/healthreport/MockHealthReportSQLiteOpenHelper.java',
|
||||
'src/healthreport/MockProfileInformationCache.java',
|
||||
'src/healthreport/prune/TestHealthReportPruneService.java',
|
||||
'src/healthreport/prune/TestPrunePolicyDatabaseStorage.java',
|
||||
'src/healthreport/TestEnvironmentBuilder.java',
|
||||
'src/healthreport/TestEnvironmentV1HashAppender.java',
|
||||
'src/healthreport/TestHealthReportBroadcastService.java',
|
||||
'src/healthreport/TestHealthReportDatabaseStorage.java',
|
||||
'src/healthreport/TestHealthReportGenerator.java',
|
||||
'src/healthreport/TestHealthReportProvider.java',
|
||||
'src/healthreport/TestHealthReportSQLiteOpenHelper.java',
|
||||
'src/healthreport/TestProfileInformationCache.java',
|
||||
'src/healthreport/upload/TestAndroidSubmissionClient.java',
|
||||
'src/healthreport/upload/TestHealthReportUploadService.java',
|
||||
'src/helpers/AndroidSyncTestCase.java',
|
||||
'src/helpers/BackgroundServiceTestCase.java',
|
||||
'src/helpers/DBHelpers.java',
|
||||
'src/helpers/DBProviderTestCase.java',
|
||||
'src/helpers/FakeProfileTestCase.java',
|
||||
'src/nativecode/test/TestNativeCrypto.java',
|
||||
'src/sync/AndroidSyncTestCaseWithAccounts.java',
|
||||
'src/sync/helpers/BookmarkHelpers.java',
|
||||
'src/sync/helpers/DefaultBeginDelegate.java',
|
||||
'src/sync/helpers/DefaultCleanDelegate.java',
|
||||
'src/sync/helpers/DefaultDelegate.java',
|
||||
'src/sync/helpers/DefaultFetchDelegate.java',
|
||||
'src/sync/helpers/DefaultFinishDelegate.java',
|
||||
'src/sync/helpers/DefaultGuidsSinceDelegate.java',
|
||||
'src/sync/helpers/DefaultSessionCreationDelegate.java',
|
||||
'src/sync/helpers/DefaultStoreDelegate.java',
|
||||
'src/sync/helpers/ExpectBeginDelegate.java',
|
||||
'src/sync/helpers/ExpectBeginFailDelegate.java',
|
||||
'src/sync/helpers/ExpectFetchDelegate.java',
|
||||
'src/sync/helpers/ExpectFetchSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectFinishDelegate.java',
|
||||
'src/sync/helpers/ExpectFinishFailDelegate.java',
|
||||
'src/sync/helpers/ExpectGuidsSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectInvalidRequestFetchDelegate.java',
|
||||
'src/sync/helpers/ExpectInvalidTypeStoreDelegate.java',
|
||||
'src/sync/helpers/ExpectManyStoredDelegate.java',
|
||||
'src/sync/helpers/ExpectNoGUIDsSinceDelegate.java',
|
||||
'src/sync/helpers/ExpectStoreCompletedDelegate.java',
|
||||
'src/sync/helpers/ExpectStoredDelegate.java',
|
||||
'src/sync/helpers/HistoryHelpers.java',
|
||||
'src/sync/helpers/PasswordHelpers.java',
|
||||
'src/sync/helpers/SessionTestHelper.java',
|
||||
'src/sync/helpers/SimpleSuccessBeginDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessCreationDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessFetchDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessFinishDelegate.java',
|
||||
'src/sync/helpers/SimpleSuccessStoreDelegate.java',
|
||||
'src/sync/TestAccountPickler.java',
|
||||
'src/sync/TestClientsStage.java',
|
||||
'src/sync/TestConfigurationMigrator.java',
|
||||
'src/sync/TestResetting.java',
|
||||
'src/sync/TestSendTabData.java',
|
||||
'src/sync/TestStoreTracking.java',
|
||||
'src/sync/TestSyncAccounts.java',
|
||||
'src/sync/TestSyncAuthenticatorService.java',
|
||||
'src/sync/TestSyncConfiguration.java',
|
||||
'src/sync/TestTabsRecord.java',
|
||||
'src/sync/TestUpgradeRequired.java',
|
||||
'src/sync/TestWebURLFinder.java',
|
||||
'src/telemetry/TestTelemetryRecorder.java',
|
||||
'src/testhelpers/BaseMockServerSyncStage.java',
|
||||
'src/testhelpers/CommandHelpers.java',
|
||||
'src/testhelpers/DefaultGlobalSessionCallback.java',
|
||||
'src/testhelpers/JPakeNumGeneratorFixed.java',
|
||||
'src/testhelpers/MockAbstractNonRepositorySyncStage.java',
|
||||
'src/testhelpers/MockClientsDatabaseAccessor.java',
|
||||
'src/testhelpers/MockClientsDataDelegate.java',
|
||||
'src/testhelpers/MockGlobalSession.java',
|
||||
'src/testhelpers/MockPrefsGlobalSession.java',
|
||||
'src/testhelpers/MockRecord.java',
|
||||
'src/testhelpers/MockServerSyncStage.java',
|
||||
'src/testhelpers/MockSharedPreferences.java',
|
||||
'src/testhelpers/StubDelegate.java',
|
||||
'src/testhelpers/WaitHelper.java',
|
||||
'src/testhelpers/WBORepository.java',
|
||||
]
|
@ -6,7 +6,10 @@
|
||||
|
||||
DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
|
||||
|
||||
include('android-services.mozbuild')
|
||||
include('background_junit3_sources.mozbuild')
|
||||
|
||||
jar = add_java_jar('background-junit3')
|
||||
jar.sources += background_junit3_sources
|
||||
|
||||
main = add_android_eclipse_project('BackgroundInstrumentationTests', OBJDIR + '/AndroidManifest.xml')
|
||||
main.package_name = 'org.mozilla.gecko.background.tests'
|
||||
|
@ -36,9 +36,10 @@ this.MobileIdentityCredentialsStore.prototype = {
|
||||
* We will be storing objects like:
|
||||
* {
|
||||
* msisdn: <string> (key),
|
||||
* iccId: <string> (index),
|
||||
* iccId: <string> (index, optional),
|
||||
* deviceIccIds: <array>,
|
||||
* origin: <array> (index),
|
||||
* msisdnSessionToken: <string>
|
||||
* msisdnSessionToken: <string>,
|
||||
* }
|
||||
*/
|
||||
let objectStore = aDb.createObjectStore(CREDENTIALS_STORE_NAME, {
|
||||
@ -49,9 +50,9 @@ this.MobileIdentityCredentialsStore.prototype = {
|
||||
objectStore.createIndex("origin", "origin", { unique: true, multiEntry: true });
|
||||
},
|
||||
|
||||
add: function(aIccId, aMsisdn, aOrigin, aSessionToken) {
|
||||
add: function(aIccId, aMsisdn, aOrigin, aSessionToken, aDeviceIccIds) {
|
||||
log.debug("put " + aIccId + ", " + aMsisdn + ", " + aOrigin + ", " +
|
||||
aSessionToken);
|
||||
aSessionToken + ", " + aDeviceIccIds);
|
||||
if (!aOrigin || !aSessionToken) {
|
||||
return Promise.reject(ERROR_INTERNAL_DB_ERROR);
|
||||
}
|
||||
@ -82,7 +83,8 @@ this.MobileIdentityCredentialsStore.prototype = {
|
||||
iccId: aIccId,
|
||||
msisdn: aMsisdn,
|
||||
origin: [aOrigin],
|
||||
sessionToken: aSessionToken
|
||||
sessionToken: aSessionToken,
|
||||
deviceIccIds: aDeviceIccIds
|
||||
};
|
||||
aStore.add(record);
|
||||
}
|
||||
@ -169,5 +171,87 @@ this.MobileIdentityCredentialsStore.prototype = {
|
||||
deferred.reject
|
||||
);
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
removeValue: function(aMsisdn, aKey, aValue) {
|
||||
log.debug("Removing " + aKey + " with value " + aValue);
|
||||
if (!aMsisdn || !aKey) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
let deferred = Promise.defer();
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
CREDENTIALS_STORE_NAME,
|
||||
(aTxn, aStore) => {
|
||||
let range = IDBKeyRange.only(aMsisdn);
|
||||
let cursorReq = aStore.openCursor(range);
|
||||
cursorReq.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
let record;
|
||||
if (!cursor || !cursor.value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
record = cursor.value;
|
||||
if (!record[aKey]) {
|
||||
return Promise.reject();
|
||||
}
|
||||
if (aValue) {
|
||||
let index = record[aKey].indexOf(aValue);
|
||||
if (index != -1) {
|
||||
record[aKey].splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
record[aKey] = undefined;
|
||||
}
|
||||
log.debug("Removal done ${}", record);
|
||||
cursor.update(record);
|
||||
deferred.resolve();
|
||||
};
|
||||
cursorReq.onerror = function(aEvent) {
|
||||
log.error(aEvent.target.error);
|
||||
deferred.reject(ERROR_INTERNAL_DB_ERROR);
|
||||
};
|
||||
}, null, deferred.reject);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
removeOrigin: function(aMsisdn, aOrigin) {
|
||||
log.debug("removeOrigin " + aMsisdn + " " + aOrigin);
|
||||
return this.removeValue(aMsisdn, "origin", aOrigin);
|
||||
},
|
||||
|
||||
setDeviceIccIds: function(aMsisdn, aDeviceIccIds) {
|
||||
log.debug("Setting icc ids " + aDeviceIccIds + " for " + aMsisdn);
|
||||
if (!aMsisdn) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
let deferred = Promise.defer();
|
||||
this.newTxn(
|
||||
"readwrite",
|
||||
CREDENTIALS_STORE_NAME,
|
||||
(aTxn, aStore) => {
|
||||
let range = IDBKeyRange.only(aMsisdn);
|
||||
let cursorReq = aStore.openCursor(range);
|
||||
cursorReq.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
let record;
|
||||
if (!cursor || !cursor.value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
record = cursor.value;
|
||||
record.deviceIccIds = aDeviceIccIds;
|
||||
cursor.update(record);
|
||||
deferred.resolve();
|
||||
};
|
||||
cursorReq.onerror = function(aEvent) {
|
||||
log.error(aEvent.target.error);
|
||||
deferred.reject(ERROR_INTERNAL_DB_ERROR);
|
||||
};
|
||||
}, null, deferred.reject);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [];
|
||||
this.EXPORTED_SYMBOLS = ["MobileIdentityManager"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
@ -62,14 +62,13 @@ XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
|
||||
#endif
|
||||
|
||||
|
||||
let MobileIdentityManager = {
|
||||
this.MobileIdentityManager = {
|
||||
|
||||
init: function() {
|
||||
log.debug("MobileIdentityManager init");
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
ppmm.addMessageListener(GET_ASSERTION_IPC_MSG, this);
|
||||
this.messageManagers = {};
|
||||
// TODO: Store keyPairs and certificates in disk. Bug 1021605.
|
||||
this.keyPairs = {};
|
||||
this.certificates = {};
|
||||
},
|
||||
@ -107,11 +106,10 @@ let MobileIdentityManager = {
|
||||
********************************************************/
|
||||
|
||||
get iccInfo() {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
if (this._iccInfo) {
|
||||
return this._iccInfo;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
this._iccInfo = [];
|
||||
for (let i = 0; i < gRil.numRadioInterfaces; i++) {
|
||||
let rilContext = gRil.getRadioInterface(i).rilContext;
|
||||
@ -153,6 +151,26 @@ let MobileIdentityManager = {
|
||||
return null;
|
||||
},
|
||||
|
||||
get iccIds() {
|
||||
#ifdef MOZ_B2G_RIL
|
||||
if (this._iccIds) {
|
||||
return this._iccIds;
|
||||
}
|
||||
|
||||
this._iccIds = [];
|
||||
if (!this.iccInfo) {
|
||||
return this._iccIds;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.iccInfo.length; i++) {
|
||||
this._iccIds.push(this.iccInfo[i].iccId);
|
||||
}
|
||||
|
||||
return this._iccIds;
|
||||
#endif
|
||||
return null;
|
||||
},
|
||||
|
||||
get credStore() {
|
||||
if (!this._credStore) {
|
||||
this._credStore = new MobileIdentityCredentialsStore();
|
||||
@ -239,7 +257,9 @@ let MobileIdentityManager = {
|
||||
// verification mechanisms for these SIM cards.
|
||||
// All this information will be stored in iccInfo.
|
||||
if (!this.iccInfo || !this.iccInfo.length) {
|
||||
return Promise.resolve();
|
||||
let deferred = Promise.defer();
|
||||
deferred.resolve(null);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
@ -299,6 +319,25 @@ let MobileIdentityManager = {
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/*********************************************************
|
||||
* Setters (for test only purposes)
|
||||
********************************************************/
|
||||
set ui(aUi) {
|
||||
this._ui = aUi;
|
||||
},
|
||||
|
||||
set credStore(aCredStore) {
|
||||
this._credStore = aCredStore;
|
||||
},
|
||||
|
||||
set client(aClient) {
|
||||
this._client = aClient;
|
||||
},
|
||||
|
||||
set iccInfo(aIccInfo) {
|
||||
this._iccInfo = aIccInfo;
|
||||
},
|
||||
|
||||
/*********************************************************
|
||||
* UI callbacks
|
||||
********************************************************/
|
||||
@ -527,7 +566,7 @@ let MobileIdentityManager = {
|
||||
.then(
|
||||
(result) => {
|
||||
if (!result ||
|
||||
(!result.phoneNumber && !result.serviceId)) {
|
||||
(!result.phoneNumber && (result.serviceId === undefined))) {
|
||||
return Promise.reject(ERROR_INTERNAL_INVALID_PROMPT_RESULT);
|
||||
}
|
||||
|
||||
@ -537,7 +576,7 @@ let MobileIdentityManager = {
|
||||
// If the user selected one of the existing SIM cards we have to check
|
||||
// that we either have the MSISDN for that SIM or we can do a silent
|
||||
// verification that does not require us to have the MSISDN in advance.
|
||||
if (result.serviceId) {
|
||||
if (result.serviceId !== undefined) {
|
||||
let icc = this.iccInfo[result.serviceId];
|
||||
log.debug("icc ${}", icc);
|
||||
if (!icc || !icc.msisdn && !icc.canDoSilentVerification) {
|
||||
@ -597,7 +636,7 @@ let MobileIdentityManager = {
|
||||
phoneInfo = new MobileIdentityUIGluePhoneInfo(
|
||||
aCreds.msisdn,
|
||||
null, // operator
|
||||
null, // service ID
|
||||
undefined, // service ID
|
||||
!!aCreds.iccId, // external
|
||||
true // primary
|
||||
);
|
||||
@ -623,7 +662,7 @@ let MobileIdentityManager = {
|
||||
let creds = this.iccInfo[promptResult.serviceId].credentials;
|
||||
if (creds) {
|
||||
this.credStore.add(creds.iccId, creds.msisdn, aPrincipal.origin,
|
||||
creds.sessionToken);
|
||||
creds.sessionToken, this.iccIds);
|
||||
return creds;
|
||||
}
|
||||
}
|
||||
@ -636,7 +675,7 @@ let MobileIdentityManager = {
|
||||
(creds) => {
|
||||
if (creds) {
|
||||
this.credStore.add(creds.iccId, creds.msisdn, aPrincipal.origin,
|
||||
creds.sessionToken);
|
||||
creds.sessionToken, this.iccIds);
|
||||
return creds;
|
||||
}
|
||||
// Otherwise, we need to verify the new number selected by the
|
||||
@ -648,6 +687,35 @@ let MobileIdentityManager = {
|
||||
);
|
||||
},
|
||||
|
||||
/*********************************************************
|
||||
* Credentials check
|
||||
*********************************************************/
|
||||
|
||||
checkNewCredentials: function(aOldCreds, aNewCreds, aOrigin) {
|
||||
// If there were previous credentials and the user changed her
|
||||
// choice, we need to remove the origin from the old credentials.
|
||||
if (aNewCreds.msisdn != aOldCreds.msisdn) {
|
||||
return this.credStore.removeOrigin(aOldCreds.msisdn,
|
||||
aOrigin)
|
||||
.then(
|
||||
() => {
|
||||
return aNewCreds;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Otherwise, we update the status of the SIM cards in the device
|
||||
// so we know that the user decided not to take the chance to change
|
||||
// her selection. We won't bother her again until a new SIM card
|
||||
// change is detected.
|
||||
return this.credStore.setDeviceIccIds(aOldCreds.msisdn, this.iccIds)
|
||||
.then(
|
||||
() => {
|
||||
return aOldCreds;
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/*********************************************************
|
||||
* Assertion generation
|
||||
********************************************************/
|
||||
@ -685,7 +753,8 @@ let MobileIdentityManager = {
|
||||
this.credStore.add(aCredentials.iccId,
|
||||
aCredentials.msisdn,
|
||||
aOrigin,
|
||||
aCredentials.sessionToken)
|
||||
aCredentials.sessionToken,
|
||||
this.iccIds)
|
||||
.then(
|
||||
() => {
|
||||
deferred.resolve(assertion);
|
||||
@ -711,7 +780,7 @@ let MobileIdentityManager = {
|
||||
// First of all we look if we already have credentials for this origin.
|
||||
// If we don't have credentials it means that it is the first time that
|
||||
// the caller requested an assertion.
|
||||
return this.credStore.getByOrigin(aPrincipal.origin)
|
||||
this.credStore.getByOrigin(aPrincipal.origin)
|
||||
.then(
|
||||
(creds) => {
|
||||
log.debug("creds ${creds} - ${origin}", { creds: creds,
|
||||
@ -721,31 +790,60 @@ let MobileIdentityManager = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Even if we already have credentials for this origin, the consumer of
|
||||
// the API might want to force the identity selection dialog.
|
||||
// Even if we already have credentials for this origin, the consumer
|
||||
// of the API might want to force the identity selection dialog.
|
||||
if (aOptions.forceSelection) {
|
||||
return this.promptAndVerify(principal, manifestURL, creds);
|
||||
}
|
||||
|
||||
// It is possible that the ICC associated with the stored
|
||||
// credentials is not present in the device anymore, so we ask the
|
||||
// user if she still wants to use it anyway or if she prefers to use
|
||||
// another phone number.
|
||||
// If the credentials are associated with an external SIM or there is
|
||||
// no SIM in the device, we just return the credentials.
|
||||
if (this.iccInfo && creds.iccId) {
|
||||
for (let i = 0; i < this.iccInfo.length; i++) {
|
||||
if (this.iccInfo[i].iccId == creds.iccId) {
|
||||
return creds;
|
||||
return this.promptAndVerify(principal, manifestURL, creds)
|
||||
.then(
|
||||
(newCreds) => {
|
||||
return this.checkNewCredentials(creds, newCreds,
|
||||
principal.origin);
|
||||
}
|
||||
}
|
||||
// At this point we know that the SIM associated with the credentials
|
||||
// is not present in the device any more, so we need to ask the user
|
||||
// what to do.
|
||||
return this.promptAndVerify(principal, manifestURL, creds);
|
||||
);
|
||||
}
|
||||
|
||||
return creds;
|
||||
// SIM change scenario.
|
||||
|
||||
// It is possible that the SIM cards inserted in the device at the
|
||||
// moment of the previous verification where we obtained the credentials
|
||||
// has changed. In that case, we need to let the user knowabout this
|
||||
// situation. Otherwise, we just return the credentials.
|
||||
log.debug("Looking for SIM changes. Credentials ICCS ${creds} " +
|
||||
"Device ICCS ${device}", { creds: creds.deviceIccIds,
|
||||
device: this.iccIds });
|
||||
let simChanged = (creds.deviceIccIds == null && this.iccIds != null) ||
|
||||
(creds.deviceIccIds != null && this.iccIds == null);
|
||||
|
||||
if (!simChanged &&
|
||||
creds.deviceIccIds != null &&
|
||||
this.IccIds != null) {
|
||||
simChanged = creds.deviceIccIds.length != this.iccIds.length;
|
||||
}
|
||||
|
||||
if (!simChanged &&
|
||||
creds.deviceIccIds != null &&
|
||||
this.IccIds != null) {
|
||||
let intersection = creds.deviceIccIds.filter((n) => {
|
||||
return this.iccIds.indexOf(n) != -1;
|
||||
});
|
||||
simChanged = intersection.length != creds.deviceIccIds.length ||
|
||||
intersection.length != this.iccIds.length;
|
||||
}
|
||||
|
||||
if (!simChanged) {
|
||||
return creds;
|
||||
}
|
||||
|
||||
// At this point we know that the SIM associated with the credentials
|
||||
// is not present in the device any more or a new SIM has been detected,
|
||||
// so we need to ask the user what to do.
|
||||
return this.promptAndVerify(principal, manifestURL, creds)
|
||||
.then(
|
||||
(newCreds) => {
|
||||
return this.checkNewCredentials(creds, newCreds,
|
||||
principal.origin);
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
.then(
|
||||
@ -763,7 +861,8 @@ let MobileIdentityManager = {
|
||||
);
|
||||
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
return creds;
|
||||
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
|
||||
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION ||
|
||||
permission == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
|
||||
return Promise.reject(ERROR_PERMISSION_DENIED);
|
||||
}
|
||||
return this.promptAndVerify(principal, manifestURL, creds);
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
PARALLEL_DIRS += ['interfaces']
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'MobileIdentityClient.jsm',
|
||||
'MobileIdentityCommon.jsm',
|
||||
|
7
services/mobileid/tests/moz.build
Normal file
7
services/mobileid/tests/moz.build
Normal file
@ -0,0 +1,7 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['xpcshell/xpcshell.ini']
|
16
services/mobileid/tests/xpcshell/head.js
Normal file
16
services/mobileid/tests/xpcshell/head.js
Normal file
@ -0,0 +1,16 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components;
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
(function initMobileIdTestingInfrastructure() {
|
||||
do_get_profile();
|
||||
|
||||
Services.prefs.setCharPref("services.mobileid.loglevel", "Debug");
|
||||
|
||||
}).call(this);
|
1235
services/mobileid/tests/xpcshell/test_mobileid_manager.js
Normal file
1235
services/mobileid/tests/xpcshell/test_mobileid_manager.js
Normal file
File diff suppressed because it is too large
Load Diff
5
services/mobileid/tests/xpcshell/xpcshell.ini
Normal file
5
services/mobileid/tests/xpcshell/xpcshell.ini
Normal file
@ -0,0 +1,5 @@
|
||||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
|
||||
[test_mobileid_manager.js]
|
@ -4172,14 +4172,44 @@ SearchService.prototype = {
|
||||
Services.prefs.addObserver(BROWSER_SEARCH_PREF + "defaultenginename", this, false);
|
||||
Services.prefs.addObserver(BROWSER_SEARCH_PREF + "selectedEngine", this, false);
|
||||
|
||||
AsyncShutdown.profileBeforeChange.addBlocker(
|
||||
// The current stage of shutdown. Used to help analyze crash
|
||||
// signatures in case of shutdown timeout.
|
||||
let shutdownState = {
|
||||
step: "Not started",
|
||||
latestError: {
|
||||
message: undefined,
|
||||
stack: undefined
|
||||
}
|
||||
};
|
||||
OS.File.profileBeforeChange.addBlocker(
|
||||
"Search service: shutting down",
|
||||
() => Task.spawn(function () {
|
||||
() => Task.spawn(function* () {
|
||||
if (this._batchTask) {
|
||||
yield this._batchTask.finalize().then(null, Cu.reportError);
|
||||
shutdownState.step = "Finalizing batched task";
|
||||
try {
|
||||
yield this._batchTask.finalize();
|
||||
shutdownState.step = "Batched task finalized";
|
||||
} catch (ex) {
|
||||
shutdownState.step = "Batched task failed to finalize";
|
||||
|
||||
shutdownState.latestError.message = "" + ex;
|
||||
if (ex && typeof ex == "object") {
|
||||
shutdownState.latestError.stack = ex.stack || undefined;
|
||||
}
|
||||
|
||||
// Ensure that error is reported and that it causes tests
|
||||
// to fail.
|
||||
Promise.reject(ex);
|
||||
}
|
||||
}
|
||||
|
||||
shutdownState.step = "Finalizing engine metadata service";
|
||||
yield engineMetadataService.finalize();
|
||||
}.bind(this))
|
||||
shutdownState.step = "Engine metadata service finalized";
|
||||
|
||||
}.bind(this)),
|
||||
|
||||
() => shutdownState
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
/* General utilities used throughout devtools. */
|
||||
|
||||
// hasChrome is provided as a global by the loader. It is true if we are running
|
||||
// on the main thread, and false if we are running on a worker thread.
|
||||
var { Ci, Cu } = require("chrome");
|
||||
var Services = require("Services");
|
||||
var promise = require("promise");
|
||||
var { setTimeout } = require("Timer");
|
||||
|
||||
/**
|
||||
* Turn the error |aError| into a string, without fail.
|
||||
|
@ -44,19 +44,11 @@ let Timer = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
|
||||
let loaderGlobals = {
|
||||
isWorker: false,
|
||||
Debugger: Debugger,
|
||||
promise: promise,
|
||||
reportError: Cu.reportError,
|
||||
setInterval: Timer.setInterval,
|
||||
setTimeout: Timer.setTimeout,
|
||||
clearInterval: Timer.clearInterval,
|
||||
clearTimeout: Timer.clearTimeout,
|
||||
xpcInspector: xpcInspector,
|
||||
|
||||
btoa: btoa,
|
||||
console: console,
|
||||
_Iterator: Iterator,
|
||||
ChromeWorker: ChromeWorker,
|
||||
loader: {
|
||||
lazyGetter: XPCOMUtils.defineLazyGetter.bind(XPCOMUtils),
|
||||
lazyImporter: XPCOMUtils.defineLazyModuleGetter.bind(XPCOMUtils),
|
||||
@ -64,16 +56,30 @@ let loaderGlobals = {
|
||||
},
|
||||
};
|
||||
|
||||
let loaderModules = {
|
||||
"Debugger": Debugger,
|
||||
"Services": Object.create(Services),
|
||||
"Timer": Object.create(Timer),
|
||||
"toolkit/loader": loader,
|
||||
"xpcInspector": xpcInspector,
|
||||
"promise": promise,
|
||||
};
|
||||
try {
|
||||
let { indexedDB } = Cu.Sandbox(this, {wantGlobalProperties:["indexedDB"]});
|
||||
loaderModules.indexedDB = indexedDB;
|
||||
} catch(e) {
|
||||
// On xpcshell, we can't instantiate indexedDB without crashing
|
||||
}
|
||||
|
||||
let sharedGlobalBlacklist = ["sdk/indexed-db", "devtools/toolkit/qrcode/decoder/index"];
|
||||
|
||||
// Used when the tools should be loaded from the Firefox package itself (the default)
|
||||
function BuiltinProvider() {}
|
||||
BuiltinProvider.prototype = {
|
||||
load: function() {
|
||||
this.loader = new loader.Loader({
|
||||
id: "fx-devtools",
|
||||
modules: {
|
||||
"Services": Object.create(Services),
|
||||
"toolkit/loader": loader,
|
||||
},
|
||||
modules: loaderModules,
|
||||
paths: {
|
||||
// When you add a line to this mapping, don't forget to make a
|
||||
// corresponding addition to the SrcdirProvider mapping below as well.
|
||||
@ -103,7 +109,9 @@ BuiltinProvider.prototype = {
|
||||
"xpcshell-test": "resource://test"
|
||||
},
|
||||
globals: loaderGlobals,
|
||||
invisibleToDebugger: this.invisibleToDebugger
|
||||
invisibleToDebugger: this.invisibleToDebugger,
|
||||
sharedGlobal: true,
|
||||
sharedGlobalBlacklist: sharedGlobalBlacklist
|
||||
});
|
||||
|
||||
return promise.resolve(undefined);
|
||||
@ -153,10 +161,7 @@ SrcdirProvider.prototype = {
|
||||
let sourceMapURI = this.fileURI(OS.Path.join(toolkitDir), "SourceMap.jsm");
|
||||
this.loader = new loader.Loader({
|
||||
id: "fx-devtools",
|
||||
modules: {
|
||||
"Services": Object.create(Services),
|
||||
"toolkit/loader": loader,
|
||||
},
|
||||
modules: loaderModules,
|
||||
paths: {
|
||||
"": "resource://gre/modules/commonjs/",
|
||||
"main": mainURI,
|
||||
@ -181,7 +186,9 @@ SrcdirProvider.prototype = {
|
||||
"source-map": sourceMapURI,
|
||||
},
|
||||
globals: loaderGlobals,
|
||||
invisibleToDebugger: this.invisibleToDebugger
|
||||
invisibleToDebugger: this.invisibleToDebugger,
|
||||
sharedGlobal: true,
|
||||
sharedGlobalBlacklist: sharedGlobalBlacklist
|
||||
});
|
||||
|
||||
return this._writeManifest(devtoolsDir).then(null, Cu.reportError);
|
||||
|
@ -24,6 +24,7 @@ module.exports = EventEmitter;
|
||||
|
||||
const { Cu, components } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const promise = require("promise");
|
||||
|
||||
/**
|
||||
* Decorate an object with event emitter functionality.
|
||||
|
@ -7,12 +7,16 @@
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { Cc, Ci, Cu, components } = require("chrome");
|
||||
const { Cc, Ci, Cu, components, ChromeWorker } = require("chrome");
|
||||
const { ActorPool } = require("devtools/server/actors/common");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const { dbg_assert, dumpn, update } = DevToolsUtils;
|
||||
const { SourceMapConsumer, SourceMapGenerator } = require("source-map");
|
||||
const promise = require("promise");
|
||||
const Debugger = require("Debugger");
|
||||
const xpcInspector = require("xpcInspector");
|
||||
|
||||
const { defer, resolve, reject, all } = require("devtools/toolkit/deprecated-sync-thenables");
|
||||
const { CssLogic } = require("devtools/styleinspector/css-logic");
|
||||
|
||||
|
@ -1184,7 +1184,7 @@ StorageActors.createActor({
|
||||
principal = Services.scriptSecurityManager.getCodebasePrincipal(uri);
|
||||
}
|
||||
|
||||
return indexedDB.openForPrincipal(principal, name);
|
||||
return require("indexedDB").openForPrincipal(principal, name);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -7,9 +7,7 @@
|
||||
const { Cu } = require("chrome");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
|
||||
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
addDebuggerToGlobal(this);
|
||||
const Debugger = require("Debugger");
|
||||
|
||||
// TODO bug 943125: remove this polyfill and use Debugger.Frame.prototype.depth
|
||||
// once it is implemented.
|
||||
|
@ -10,6 +10,7 @@ const { Cc, Ci, Cu } = require("chrome");
|
||||
const { DebuggerServer, ActorPool } = require("devtools/server/main");
|
||||
const { EnvironmentActor, LongStringActor, ObjectActor, ThreadActor } = require("devtools/server/actors/script");
|
||||
const { update } = require("devtools/toolkit/DevToolsUtils");
|
||||
const Debugger = require("Debugger");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
|
@ -19,6 +19,7 @@ let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
let { dumpn, dumpv, dbg_assert } = DevToolsUtils;
|
||||
let Services = require("Services");
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
let Debugger = require("Debugger");
|
||||
|
||||
// Until all Debugger server code is converted to SDK modules,
|
||||
// imports Components.* alias from chrome module.
|
||||
@ -843,6 +844,15 @@ if (this.exports) {
|
||||
// Needed on B2G (See header note)
|
||||
this.DebuggerServer = DebuggerServer;
|
||||
|
||||
// When using DebuggerServer.addActors, some symbols are expected to be in
|
||||
// the scope of the added actor even before the corresponding modules are
|
||||
// loaded, so let's explicitly bind the expected symbols here.
|
||||
let includes = ["Components", "Ci", "Cu", "require", "Services", "DebuggerServer",
|
||||
"ActorPool", "DevToolsUtils"];
|
||||
includes.forEach(name => {
|
||||
DebuggerServer[name] = this[name];
|
||||
});
|
||||
|
||||
// Export ActorPool for requirers of main.js
|
||||
if (this.exports) {
|
||||
exports.ActorPool = ActorPool;
|
||||
|
@ -5,6 +5,7 @@ const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/se
|
||||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
|
||||
var gTestGlobals = [];
|
||||
DebuggerServer.addTestGlobal = function(aGlobal) {
|
||||
|
@ -21,7 +21,7 @@ function visible_loader() {
|
||||
loader.require("devtools/css-color");
|
||||
|
||||
let dbg = new Debugger();
|
||||
let sandbox = loader._provider.loader.sandboxes[COLOR_URI];
|
||||
let sandbox = loader._provider.loader.sharedGlobalSandbox;
|
||||
|
||||
try {
|
||||
dbg.addDebuggee(sandbox);
|
||||
@ -37,7 +37,7 @@ function invisible_loader() {
|
||||
loader.require("devtools/css-color");
|
||||
|
||||
let dbg = new Debugger();
|
||||
let sandbox = loader._provider.loader.sandboxes[COLOR_URI];
|
||||
let sandbox = loader._provider.loader.sharedGlobalSandbox;
|
||||
|
||||
try {
|
||||
dbg.addDebuggee(sandbox);
|
||||
|
@ -28,7 +28,7 @@ const { Cc, Ci, Cu } = require("chrome");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const { dumpn, dumpv } = DevToolsUtils;
|
||||
const StreamUtils = require("devtools/toolkit/transport/stream-utils");
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const promise = require("promise");
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "unicodeConverter", () => {
|
||||
const unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
|
@ -9,6 +9,7 @@ const Services = require("Services");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const { dumpv } = DevToolsUtils;
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const promise = require("promise");
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "IOUtil", () => {
|
||||
return Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
|
||||
|
@ -6,6 +6,7 @@ const { ActorPool, appendExtraActors, createExtraActors } =
|
||||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
|
||||
var gTestGlobals = [];
|
||||
DebuggerServer.addTestGlobal = function(aGlobal) {
|
||||
|
@ -29,6 +29,7 @@ const { dumpn, dumpv } = DevToolsUtils;
|
||||
const StreamUtils = require("devtools/toolkit/transport/stream-utils");
|
||||
const { Packet, JSONPacket, BulkPacket } =
|
||||
require("devtools/toolkit/transport/packets");
|
||||
const promise = require("promise");
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "Pipe", () => {
|
||||
return CC("@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user