Merge b2g-inbound to m-c a=merge

This commit is contained in:
Wes Kocher 2014-07-08 16:34:48 -07:00
Родитель 58cdda12a0 91ff15476e
Коммит b822ae8366
52 изменённых файлов: 2804 добавлений и 937 удалений

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

@ -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"/>

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

@ -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

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

@ -70,6 +70,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"
@ -88,6 +89,7 @@
#include "GeckoProfiler.h"
#include "mozilla/Preferences.h"
#include "nsIContentIterator.h"
#include "nsContentPermissionHelper.h"
#ifdef XP_WIN
#undef GetClassName
@ -3677,6 +3679,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>

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

@ -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>

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

@ -47,8 +47,9 @@ interface nsIDOMEventTarget;
interface nsIRunnable;
interface nsICompositionStringSynthesizer;
interface nsITranslationNodeList;
interface nsIContentPermissionRequest;
[scriptable, uuid(46e3f206-9a8f-4d66-8248-7ec6a37de45a)]
[scriptable, uuid(ca202fa7-7b8f-4814-acc3-a8545f67320b)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -1663,6 +1664,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']

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

@ -0,0 +1,5 @@
[DEFAULT]
skip-if = (buildapp != 'b2g')
[test_mobileid_basics.html]
[test_mobileid_no_permission.html]

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

@ -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/.
MOCHITEST_MANIFESTS += ['mochitest.ini']

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

@ -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>

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

@ -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',
]

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

@ -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");

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

@ -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',

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

@ -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']

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

@ -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);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -0,0 +1,5 @@
[DEFAULT]
head = head.js
tail =
[test_mobileid_manager.js]