merge b2g-inbound to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2013-11-06 13:11:03 +01:00
commit 81e43584e3
64 changed files with 847 additions and 839 deletions

View File

@ -5,7 +5,7 @@
"use strict"
function debug(str) {
//dump("-*- ContentPermissionPrompt: " + str + "\n");
//dump("-*- ContentPermissionPrompt: " + s + "\n");
}
const Ci = Components.interfaces;
@ -13,14 +13,11 @@ const Cr = Components.results;
const Cu = Components.utils;
const Cc = Components.classes;
const PROMPT_FOR_UNKNOWN = ["audio-capture",
"desktop-notification",
"geolocation",
"video-capture"];
const PROMPT_FOR_UNKNOWN = ["geolocation", "desktop-notification",
"audio-capture"];
// Due to privary issue, permission requests like GetUserMedia should prompt
// every time instead of providing session persistence.
const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
const PERMISSION_NO_SESSION = ["audio-capture"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -44,21 +41,7 @@ XPCOMUtils.defineLazyServiceGetter(this,
"@mozilla.org/telephony/audiomanager;1",
"nsIAudioManager");
/**
* aTypesInfo is an array of {permission, access, action, deny} which keeps
* the information of each permission. This arrary is initialized in
* ContentPermissionPrompt.prompt and used among functions.
*
* aTypesInfo[].permission : permission name
* aTypesInfo[].access : permission name + request.access
* aTypesInfo[].action : the default action of this permission
* aTypesInfo[].deny : true if security manager denied this app's origin
* principal.
* Note:
* aTypesInfo[].permission will be sent to prompt only when
* aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false.
*/
function rememberPermission(aTypesInfo, aPrincipal, aSession)
function rememberPermission(aPermission, aPrincipal, aSession)
{
function convertPermToAllow(aPerm, aPrincipal)
{
@ -66,13 +49,12 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession)
permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm);
if (type == Ci.nsIPermissionManager.PROMPT_ACTION ||
(type == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) {
debug("add " + aPerm + " to permission manager with ALLOW_ACTION");
PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) {
if (!aSession) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION);
} else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) {
} else if (PERMISSION_NO_SESSION.indexOf(aPermission) < 0) {
permissionManager.addFromPrincipal(aPrincipal,
aPerm,
Ci.nsIPermissionManager.ALLOW_ACTION,
@ -81,18 +63,14 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession)
}
}
for (let i in aTypesInfo) {
// Expand the permission to see if we have multiple access properties
// to convert
let perm = aTypesInfo[i].permission;
let access = PermissionsTable[perm].access;
if (access) {
for (let idx in access) {
convertPermToAllow(perm + "-" + access[idx], aPrincipal);
}
} else {
convertPermToAllow(perm, aPrincipal);
// Expand the permission to see if we have multiple access properties to convert
let access = PermissionsTable[aPermission].access;
if (access) {
for (let idx in access) {
convertPermToAllow(aPermission + "-" + access[idx], aPrincipal);
}
} else {
convertPermToAllow(aPermission, aPrincipal);
}
}
@ -100,63 +78,23 @@ function ContentPermissionPrompt() {}
ContentPermissionPrompt.prototype = {
handleExistingPermission: function handleExistingPermission(request,
typesInfo) {
typesInfo.forEach(function(type) {
type.action =
Services.perms.testExactPermissionFromPrincipal(request.principal,
type.access);
});
// If all permissions are allowed already, call allow() without prompting.
let checkAllowPermission = function(type) {
if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) {
return true;
}
return false;
}
if (typesInfo.every(checkAllowPermission)) {
debug("all permission requests are allowed");
handleExistingPermission: function handleExistingPermission(request) {
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, access);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
}
// If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel()
// without prompting.
let checkDenyPermission = function(type) {
if (type.action == Ci.nsIPermissionManager.DENY_ACTION ||
type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(type.access) < 0) {
return true;
}
return false;
}
if (typesInfo.every(checkDenyPermission)) {
debug("all permission requests are denied");
if (result == Ci.nsIPermissionManager.DENY_ACTION ||
result == Ci.nsIPermissionManager.UNKNOWN_ACTION && PROMPT_FOR_UNKNOWN.indexOf(access) < 0) {
request.cancel();
return true;
}
return false;
},
// multiple requests should be audio and video
checkMultipleRequest: function checkMultipleRequest(typesInfo) {
if (typesInfo.length == 1) {
return true;
} else if (typesInfo.length > 1) {
let checkIfAllowMultiRequest = function(type) {
return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
}
if (typesInfo.every(checkIfAllowMultiRequest)) {
debug("legal multiple requests");
return true;
}
}
return false;
},
handledByApp: function handledByApp(request, typesInfo) {
handledByApp: function handledByApp(request) {
if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID ||
request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) {
// This should not really happen
@ -168,94 +106,49 @@ ContentPermissionPrompt.prototype = {
.getService(Ci.nsIAppsService);
let app = appsService.getAppByLocalId(request.principal.appId);
// Check each permission if it's denied by permission manager with app's
// URL.
let checkIfDenyAppPrincipal = function(type) {
let url = Services.io.newURI(app.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(url,
request.principal.appId,
/*mozbrowser*/false);
let result = Services.perms.testExactPermissionFromPrincipal(principal,
type.access);
let url = Services.io.newURI(app.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(url, request.principal.appId,
/*mozbrowser*/false);
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let result = Services.perms.testExactPermissionFromPrincipal(principal, access);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
type.deny = false;
}
return type.deny;
}
if (typesInfo.every(checkIfDenyAppPrincipal)) {
request.cancel();
return true;
if (result == Ci.nsIPermissionManager.ALLOW_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) {
return false;
}
return false;
request.cancel();
return true;
},
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
for (let i in typesInfo) {
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
permissionSpecificChecker[typesInfo[i].permission](request)) {
return true;
}
}
return false;
handledByPermissionType: function handledByPermissionType(request) {
return permissionSpecificChecker.hasOwnProperty(request.type)
? permissionSpecificChecker[request.type](request)
: false;
},
_id: 0,
prompt: function(request) {
if (secMan.isSystemPrincipal(request.principal)) {
request.allow();
return;
return true;
}
// Initialize the typesInfo and set the default value.
let typesInfo = [];
let perms = request.types.QueryInterface(Ci.nsIArray);
for (let idx = 0; idx < perms.length; idx++) {
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
let tmp = {
permission: perm.type,
access: (perm.access && perm.access !== "unused") ?
perm.type + "-" + perm.access : perm.type,
deny: true,
action: Ci.nsIPermissionManager.UNKNOWN_ACTION
};
typesInfo.push(tmp);
}
if (typesInfo.length == 0) {
request.cancel();
return;
}
if(!this.checkMultipleRequest(typesInfo)) {
request.cancel();
return;
}
if (this.handledByApp(request, typesInfo) ||
this.handledByPermissionType(request, typesInfo)) {
if (this.handledByApp(request) ||
this.handledByPermissionType(request)) {
return;
}
// returns true if the request was handled
if (this.handleExistingPermission(request, typesInfo)) {
if (this.handleExistingPermission(request))
return;
}
// prompt PROMPT_ACTION request only.
typesInfo.forEach(function(aType, aIndex) {
if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) {
typesInfo.splice(aIndex);
}
});
let frame = request.element;
let requestId = this._id++;
if (!frame) {
this.delegatePrompt(request, requestId, typesInfo);
this.delegatePrompt(request, requestId);
return;
}
@ -270,7 +163,7 @@ ContentPermissionPrompt.prototype = {
if (evt.detail.visible === true)
return;
self.cancelPrompt(request, requestId, typesInfo);
self.cancelPrompt(request, requestId);
cancelRequest();
}
@ -287,7 +180,7 @@ ContentPermissionPrompt.prototype = {
// away but the request is still here.
frame.addEventListener("mozbrowservisibilitychange", onVisibilityChange);
self.delegatePrompt(request, requestId, typesInfo, function onCallback() {
self.delegatePrompt(request, requestId, function onCallback() {
frame.removeEventListener("mozbrowservisibilitychange", onVisibilityChange);
});
};
@ -298,17 +191,22 @@ ContentPermissionPrompt.prototype = {
}
},
cancelPrompt: function(request, requestId, typesInfo) {
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId,
typesInfo);
cancelPrompt: function(request, requestId) {
this.sendToBrowserWindow("cancel-permission-prompt", request, requestId);
},
delegatePrompt: function(request, requestId, typesInfo, callback) {
delegatePrompt: function(request, requestId, callback) {
let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access :
request.type;
let principal = request.principal;
this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo,
function(type, remember) {
this._permission = access;
this._uri = principal.URI.spec;
this._origin = principal.origin;
this.sendToBrowserWindow("permission-prompt", request, requestId, function(type, remember) {
if (type == "permission-allow") {
rememberPermission(typesInfo, request.principal, !remember);
rememberPermission(request.type, principal, !remember);
if (callback) {
callback();
}
@ -316,20 +214,14 @@ ContentPermissionPrompt.prototype = {
return;
}
let addDenyPermission = function(type) {
debug("add " + type.permission +
" to permission manager with DENY_ACTION");
if (remember) {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION);
} else {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION,
0);
}
if (remember) {
Services.perms.addFromPrincipal(principal, access,
Ci.nsIPermissionManager.DENY_ACTION);
} else {
Services.perms.addFromPrincipal(principal, access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION, 0);
}
typesInfo.forEach(addDenyPermission);
if (callback) {
callback();
@ -338,7 +230,7 @@ ContentPermissionPrompt.prototype = {
});
},
sendToBrowserWindow: function(type, request, requestId, typesInfo, callback) {
sendToBrowserWindow: function(type, request, requestId, callback) {
let browser = Services.wm.getMostRecentWindow("navigator:browser");
let content = browser.getContentWindow();
if (!content)
@ -361,15 +253,10 @@ ContentPermissionPrompt.prototype = {
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let permissions = [];
for (let i in typesInfo) {
debug("prompt " + typesInfo[i].permission);
permissions.push(typesInfo[i].permission);
}
let details = {
type: type,
permissions: permissions,
permission: request.type,
id: requestId,
origin: principal.origin,
isApp: isApp,
@ -402,5 +289,6 @@ ContentPermissionPrompt.prototype = {
};
})();
//module initialization
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);

View File

@ -1,12 +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/. */
#include "domstubs.idl"
[scriptable, uuid(3615a616-571d-4194-bf54-ccf546067b14)]
interface nsIB2GCameraContent : nsISupports
{
/* temporary solution, waiting for getUserMedia */
DOMString getCameraURI([optional] in jsval options);
};

View File

@ -6,10 +6,6 @@
TEST_DIRS += ['test']
XPIDL_SOURCES += [
'b2g.idl',
]
MODULE = 'B2GComponents'
EXTRA_COMPONENTS += [

View File

@ -1,4 +1,4 @@
{
"revision": "fe012cdbca542f414a72b0cba9cfb50a4aaf62ae",
"revision": "5cc807be4ece02c364c1d7f1cd2becbe1a1b441e",
"repo_path": "/integration/gaia-central"
}

View File

@ -749,8 +749,6 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@
@BINPATH@/chrome/chrome@JAREXT@
@BINPATH@/chrome/chrome.manifest
@BINPATH@/components/B2GComponents.manifest
@BINPATH@/components/B2GComponents.xpt
@BINPATH@/components/CameraContent.js
@BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@
#ifdef ENABLE_MARIONETTE
@BINPATH@/chrome/marionette@JAREXT@

View File

@ -1995,21 +1995,13 @@ ContentPermissionPrompt.prototype = {
prompt: function CPP_prompt(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
const kFeatureKeys = { "geolocation" : "geo",
"desktop-notification" : "desktop-notification",
"pointerLock" : "pointerLock",
};
// Make sure that we support the request.
if (!(perm.type in kFeatureKeys)) {
if (!(request.type in kFeatureKeys)) {
return;
}
@ -2021,7 +2013,7 @@ ContentPermissionPrompt.prototype = {
return;
var autoAllow = false;
var permissionKey = kFeatureKeys[perm.type];
var permissionKey = kFeatureKeys[request.type];
var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey);
if (result == Ci.nsIPermissionManager.DENY_ACTION) {
@ -2032,14 +2024,14 @@ ContentPermissionPrompt.prototype = {
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
autoAllow = true;
// For pointerLock, we still want to show a warning prompt.
if (perm.type != "pointerLock") {
if (request.type != "pointerLock") {
request.allow();
return;
}
}
// Show the prompt.
switch (perm.type) {
switch (request.type) {
case "geolocation":
this._promptGeo(request);
break;

View File

@ -44,8 +44,6 @@ let IndexedDB = {
}
let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt);
let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
types.appendElement({type: type, access: "unused"}, false);
// If the user waits a long time before responding, we default to UNKNOWN_ACTION.
let timeoutId = setTimeout(function() {
@ -62,7 +60,7 @@ let IndexedDB = {
}
prompt.prompt({
types: types,
type: type,
uri: Services.io.newURI(payload.location, null, null),
window: null,
element: aMessage.target,

View File

@ -56,8 +56,8 @@ ContentPermissionPrompt.prototype = {
return chromeWin.Browser.getNotificationBox(request.element);
},
handleExistingPermission: function handleExistingPermission(request, type) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
handleExistingPermission: function handleExistingPermission(request) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
@ -70,28 +70,20 @@ ContentPermissionPrompt.prototype = {
},
prompt: function(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// returns true if the request was handled
if (this.handleExistingPermission(request, perm.type))
if (this.handleExistingPermission(request))
return;
let pm = Services.perms;
let notificationBox = this.getNotificationBoxForRequest(request);
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let notification = notificationBox.getNotificationWithValue(perm.type);
let notification = notificationBox.getNotificationWithValue(request.type);
if (notification)
return;
let entityName = kEntities[perm.type];
let icon = kIcons[perm.type] || "";
let entityName = kEntities[request.type];
let icon = kIcons[request.type] || "";
let buttons = [{
label: browserBundle.GetStringFromName(entityName + ".allow"),
@ -104,7 +96,7 @@ ContentPermissionPrompt.prototype = {
label: browserBundle.GetStringFromName("contentPermissions.alwaysForSite"),
accessKey: "",
callback: function(notification) {
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
request.allow();
}
},
@ -112,7 +104,7 @@ ContentPermissionPrompt.prototype = {
label: browserBundle.GetStringFromName("contentPermissions.neverForSite"),
accessKey: "",
callback: function(notification) {
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
request.cancel();
}
}];
@ -120,12 +112,12 @@ ContentPermissionPrompt.prototype = {
let message = browserBundle.formatStringFromName(entityName + ".wantsTo",
[request.principal.URI.host], 1);
let newBar = notificationBox.appendNotification(message,
perm.type,
request.type,
icon,
notificationBox.PRIORITY_WARNING_MEDIUM,
buttons);
if (perm.type == "geolocation") {
if (request.type == "geolocation") {
// Add the "learn more" link.
let link = newBar.ownerDocument.createElement("label");
link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore"));

View File

@ -215,8 +215,6 @@
#include "mozilla/dom/XPathEvaluator.h"
#include "nsIDocumentEncoder.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -10649,11 +10647,17 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest,
nsIContentPermissionRequest)
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
nsPointerLockPermissionRequest::GetType(nsACString& aType)
{
return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
NS_LITERAL_CSTRING("unused"),
aTypes);
aType = "pointerLock";
return NS_OK;
}
NS_IMETHODIMP
nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess)
{
aAccess = "unused";
return NS_OK;
}
NS_IMETHODIMP

View File

@ -302,11 +302,6 @@ this.PermissionsTable = { geolocation: {
privileged: PROMPT_ACTION,
certified: PROMPT_ACTION
},
"video-capture": {
app: PROMPT_ACTION,
privileged: PROMPT_ACTION,
certified: PROMPT_ACTION
},
};
/**

View File

@ -2,155 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsContentPermissionHelper.h"
#include "nsIContentPermissionPrompt.h"
#include "nsCOMPtr.h"
#include "nsIDOMElement.h"
#include "nsIPrincipal.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PContentPermission.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/unused.h"
#include "nsComponentManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsIMutableArray.h"
#include "nsContentPermissionHelper.h"
using mozilla::unused; // <snicker>
using namespace mozilla::dom;
namespace mozilla {
namespace dom {
class ContentPermissionRequestParent : public PContentPermissionRequestParent
{
public:
ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal);
virtual ~ContentPermissionRequestParent();
bool IsBeingDestroyed();
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<Element> mElement;
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
nsTArray<PermissionRequest> mRequests;
private:
virtual bool Recvprompt();
virtual void ActorDestroy(ActorDestroyReason why);
};
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* aElement,
const IPC::Principal& aPrincipal)
{
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
mPrincipal = aPrincipal;
mElement = aElement;
mRequests = aRequests;
}
ContentPermissionRequestParent::~ContentPermissionRequestParent()
{
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
bool
ContentPermissionRequestParent::Recvprompt()
{
mProxy = new nsContentPermissionRequestProxy();
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
if (NS_FAILED(mProxy->Init(mRequests, this))) {
mProxy->Cancel();
}
return true;
}
void
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
{
if (mProxy) {
mProxy->OnParentDestroyed();
}
}
bool
ContentPermissionRequestParent::IsBeingDestroyed()
{
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
// to send out any message now.
TabParent* tabParent = static_cast<TabParent*>(Manager());
return tabParent->IsDestroyed();
}
NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType)
ContentPermissionType::ContentPermissionType(const nsACString& aType,
const nsACString& aAccess)
{
mType = aType;
mAccess = aAccess;
}
ContentPermissionType::~ContentPermissionType()
{
}
NS_IMETHODIMP
ContentPermissionType::GetType(nsACString& aType)
{
aType = mType;
return NS_OK;
}
NS_IMETHODIMP
ContentPermissionType::GetAccess(nsACString& aAccess)
{
aAccess = mAccess;
return NS_OK;
}
uint32_t
ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray)
{
uint32_t len = aSrcArray.Length();
for (uint32_t i = 0; i < len; i++) {
nsRefPtr<ContentPermissionType> cpt =
new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access());
aDesArray->AppendElement(cpt, false);
}
return len;
}
nsresult
CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
nsIArray** aTypesArray)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
nsRefPtr<ContentPermissionType> permType = new ContentPermissionType(aType,
aAccess);
types->AppendElement(permType, false);
types.forget(aTypesArray);
return NS_OK;
}
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal)
{
return new ContentPermissionRequestParent(aRequests, element, principal);
}
} // namespace dom
} // namespace mozilla
nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
{
MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
@ -162,12 +26,14 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
}
nsresult
nsContentPermissionRequestProxy::Init(const nsTArray<PermissionRequest>& requests,
nsContentPermissionRequestProxy::Init(const nsACString & type,
const nsACString & access,
ContentPermissionRequestParent* parent)
{
NS_ASSERTION(parent, "null parent");
mParent = parent;
mPermissionRequests = requests;
mType = type;
mAccess = access;
nsCOMPtr<nsIContentPermissionPrompt> prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
if (!prompt) {
@ -187,14 +53,17 @@ nsContentPermissionRequestProxy::OnParentDestroyed()
NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest)
NS_IMETHODIMP
nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes)
nsContentPermissionRequestProxy::GetType(nsACString & aType)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (ConvertPermissionRequestToArray(mPermissionRequests, types)) {
types.forget(aTypes);
return NS_OK;
}
return NS_ERROR_FAILURE;
aType = mType;
return NS_OK;
}
NS_IMETHODIMP
nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess)
{
aAccess = mAccess;
return NS_OK;
}
NS_IMETHODIMP
@ -265,3 +134,55 @@ nsContentPermissionRequestProxy::Allow()
mParent = nullptr;
return NS_OK;
}
namespace mozilla {
namespace dom {
ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType,
const nsACString& aAccess,
Element* aElement,
const IPC::Principal& aPrincipal)
{
MOZ_COUNT_CTOR(ContentPermissionRequestParent);
mPrincipal = aPrincipal;
mElement = aElement;
mType = aType;
mAccess = aAccess;
}
ContentPermissionRequestParent::~ContentPermissionRequestParent()
{
MOZ_COUNT_DTOR(ContentPermissionRequestParent);
}
bool
ContentPermissionRequestParent::Recvprompt()
{
mProxy = new nsContentPermissionRequestProxy();
NS_ASSERTION(mProxy, "Alloc of request proxy failed");
if (NS_FAILED(mProxy->Init(mType, mAccess, this))) {
mProxy->Cancel();
}
return true;
}
void
ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why)
{
if (mProxy) {
mProxy->OnParentDestroyed();
}
}
bool
ContentPermissionRequestParent::IsBeingDestroyed()
{
// When TabParent::Destroy() is called, we are being destroyed. It's unsafe
// to send out any message now.
TabParent* tabParent = static_cast<TabParent*>(Manager());
return tabParent->IsDestroyed();
}
} // namespace dom
} // namespace mozilla

View File

@ -6,75 +6,60 @@
#define nsContentPermissionHelper_h
#include "nsIContentPermissionPrompt.h"
#include "nsTArray.h"
#include "nsIMutableArray.h"
#include "nsString.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
class nsContentPermissionRequestProxy;
// Forward declare IPC::Principal here which is defined in
// PermissionMessageUtils.h. Include this file will transitively includes
// "windows.h" and it defines
// #define CreateEvent CreateEventW
// #define LoadImage LoadImageW
// That will mess up windows build.
namespace IPC {
class Principal;
}
namespace mozilla {
namespace dom {
class Element;
class PermissionRequest;
class ContentPermissionRequestParent;
class PContentPermissionRequestParent;
class ContentPermissionType : public nsIContentPermissionType
class ContentPermissionRequestParent : public PContentPermissionRequestParent
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONTYPE
public:
ContentPermissionRequestParent(const nsACString& type,
const nsACString& access,
Element* element,
const IPC::Principal& principal);
virtual ~ContentPermissionRequestParent();
ContentPermissionType(const nsACString& aType, const nsACString& aAccess);
virtual ~ContentPermissionType();
bool IsBeingDestroyed();
protected:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<Element> mElement;
nsCOMPtr<nsContentPermissionRequestProxy> mProxy;
nsCString mType;
nsCString mAccess;
private:
virtual bool Recvprompt();
virtual void ActorDestroy(ActorDestroyReason why);
};
uint32_t ConvertPermissionRequestToArray(nsTArray<PermissionRequest>& aSrcArray,
nsIMutableArray* aDesArray);
nsresult CreatePermissionArray(const nsACString& aType,
const nsACString& aAccess,
nsIArray** aTypesArray);
PContentPermissionRequestParent*
CreateContentPermissionRequestParent(const nsTArray<PermissionRequest>& aRequests,
Element* element,
const IPC::Principal& principal);
} // namespace dom
} // namespace mozilla
class nsContentPermissionRequestProxy : public nsIContentPermissionRequest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
nsContentPermissionRequestProxy();
virtual ~nsContentPermissionRequestProxy();
nsresult Init(const nsTArray<mozilla::dom::PermissionRequest>& requests,
mozilla::dom::ContentPermissionRequestParent* parent);
nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent);
void OnParentDestroyed();
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
private:
// Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy.
mozilla::dom::ContentPermissionRequestParent* mParent;
nsTArray<mozilla::dom::PermissionRequest> mPermissionRequests;
nsCString mType;
nsCString mAccess;
};
#endif // nsContentPermissionHelper_h

View File

@ -49,7 +49,6 @@
#include "nsIStringBundle.h"
#include "nsIDocument.h"
#include <algorithm>
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/DeviceStorageBinding.h"
@ -1696,14 +1695,17 @@ nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType)
}
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes)
nsDOMDeviceStorageCursor::GetType(nsACString & aType)
{
nsCString type;
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
NS_ENSURE_SUCCESS(rv, rv);
return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
aType);
}
return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes);
NS_IMETHODIMP
nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess)
{
aAccess = NS_LITERAL_CSTRING("read");
return NS_OK;
}
NS_IMETHODIMP
@ -2178,10 +2180,8 @@ public:
if (NS_FAILED(rv)) {
return rv;
}
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(type, access));
child->SendPContentPermissionRequestConstructor(
this, permArray, IPC::Principal(mPrincipal));
this, type, access, IPC::Principal(mPrincipal));
Sendprompt();
return NS_OK;
@ -2195,23 +2195,26 @@ public:
return NS_OK;
}
NS_IMETHODIMP GetTypes(nsIArray** aTypes)
NS_IMETHOD GetType(nsACString & aType)
{
nsCString type;
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type);
nsresult rv
= DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType,
aType);
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
nsCString access;
rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), access);
NS_IMETHOD GetAccess(nsACString & aAccess)
{
nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest(
DeviceStorageRequestType(mRequestType), aAccess);
if (NS_FAILED(rv)) {
return rv;
}
return CreatePermissionArray(type, access, aTypes);
return NS_OK;
}
NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
@ -3188,10 +3191,8 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath,
if (aRv.Failed()) {
return nullptr;
}
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read")));
child->SendPContentPermissionRequestConstructor(r,
permArray,
child->SendPContentPermissionRequestConstructor(r, type,
NS_LITERAL_CSTRING("read"),
IPC::Principal(mPrincipal));
r->Sendprompt();

View File

@ -7,13 +7,15 @@
interface nsIPrincipal;
interface nsIDOMWindow;
interface nsIDOMElement;
interface nsIArray;
/**
* Interface provides the request type and its access.
* Interface allows access to a content to request
* permission to perform a privileged operation such as
* geolocation.
*/
[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)]
interface nsIContentPermissionType : nsISupports {
[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)]
interface nsIContentPermissionRequest : nsISupports {
/**
* The type of the permission request, such as
* "geolocation".
@ -25,22 +27,8 @@ interface nsIContentPermissionType : nsISupports {
* "read".
*/
readonly attribute ACString access;
};
/**
* Interface allows access to a content to request
* permission to perform a privileged operation such as
* geolocation.
*/
[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)]
interface nsIContentPermissionRequest : nsISupports {
/**
* The array will include the request types. Elements of this array are
* nsIContentPermissionType object.
*/
readonly attribute nsIArray types;
/*
* The principal of the permission request.
*/
readonly attribute nsIPrincipal principal;

View File

@ -16,7 +16,6 @@ include protocol PIndexedDB;
include DOMTypes;
include JavaScriptTypes;
include URIParams;
include PContentPermission;
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
@ -203,8 +202,10 @@ parent:
* Initiates an asynchronous request for permission for the
* provided principal.
*
* @param aRequests
* The array of permissions to request.
* @param aType
* The type of permission to request.
* @param aAccess
* Access type. "read" for example.
* @param aPrincipal
* The principal of the request.
*
@ -212,7 +213,7 @@ parent:
* principals that can live in the content process should
* provided.
*/
PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal);
PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal);
PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures,
int32_t[] aIntParams, nsString[] aStringParams);

View File

@ -1,14 +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/. */
namespace mozilla {
namespace dom {
struct PermissionRequest {
nsCString type;
nsCString access;
};
} // namespace dom
} // namespace mozilla

View File

@ -1148,11 +1148,12 @@ TabChild::ArraysToParams(const InfallibleTArray<int>& aIntParams,
#ifdef DEBUG
PContentPermissionRequestChild*
TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
const InfallibleTArray<PermissionRequest>& aRequests,
const nsCString& aType,
const nsCString& aAccess,
const IPC::Principal& aPrincipal)
{
PCOMContentPermissionRequestChild* child = static_cast<PCOMContentPermissionRequestChild*>(aActor);
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal);
PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal);
child->mIPCOpen = true;
return request;
}
@ -2007,8 +2008,7 @@ TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog)
}
PContentPermissionRequestChild*
TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal)
TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&)
{
NS_RUNTIMEABORT("unused");
return nullptr;

View File

@ -269,11 +269,13 @@ public:
#ifdef DEBUG
virtual PContentPermissionRequestChild*
SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor,
const InfallibleTArray<PermissionRequest>& aRequests,
const nsCString& aType,
const nsCString& aAccess,
const IPC::Principal& aPrincipal);
#endif /* DEBUG */
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray<PermissionRequest>& aRequests,
virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType,
const nsCString& aAccess,
const IPC::Principal& aPrincipal);
virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor);

View File

@ -14,7 +14,6 @@
#include "mozilla/BrowserElementParent.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/layers/CompositorParent.h"
@ -571,10 +570,9 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor)
}
PContentPermissionRequestParent*
TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal)
TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal)
{
return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal);
return new ContentPermissionRequestParent(type, access, mFrameElement, principal);
}
bool

View File

@ -215,8 +215,7 @@ public:
virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor);
virtual PContentPermissionRequestParent*
AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests,
const IPC::Principal& aPrincipal);
AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal);
virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor);
virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent(

View File

@ -64,7 +64,6 @@ IPDL_SOURCES += [
'PBrowser.ipdl',
'PContent.ipdl',
'PContentDialog.ipdl',
'PContentPermission.ipdlh',
'PContentPermissionRequest.ipdl',
'PCrashReporter.ipdl',
'PDocumentRenderer.ipdl',

View File

@ -43,7 +43,7 @@
#include "MediaEngineWebRTC.h"
#endif
#ifdef MOZ_B2G
#ifdef MOZ_WIDGET_GONK
#include "MediaPermissionGonk.h"
#endif
@ -810,6 +810,7 @@ public:
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(false)
, mManager(MediaManager::GetInstance())
{}
@ -831,11 +832,15 @@ public:
, mListener(aListener)
, mPrefs(aPrefs)
, mDeviceChosen(false)
, mBackendChosen(true)
, mBackend(aBackend)
, mManager(MediaManager::GetInstance())
{}
~GetUserMediaRunnable() {
if (mBackendChosen) {
delete mBackend;
}
}
NS_IMETHOD
@ -843,7 +848,10 @@ public:
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
mBackend = mManager->GetBackend(mWindowID);
// Was a backend provided?
if (!mBackendChosen) {
mBackend = mManager->GetBackend(mWindowID);
}
// Was a device provided?
if (!mDeviceChosen) {
@ -1030,6 +1038,7 @@ private:
MediaEnginePrefs mPrefs;
bool mDeviceChosen;
bool mBackendChosen;
MediaEngine* mBackend;
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
@ -1247,10 +1256,10 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
// Force MediaManager to startup before we try to access it from other threads
// Hack: should init singleton earlier unless it's expensive (mem or CPU)
(void) MediaManager::Get();
#ifdef MOZ_B2G
#ifdef MOZ_WIDGET_GONK
// Initialize MediaPermissionManager before send out any permission request.
(void) MediaPermissionManager::GetInstance();
#endif //MOZ_B2G
#endif //MOZ_WIDGET_GONK
}
// Store the WindowID in a hash table and mark as active. The entry is removed
@ -1302,7 +1311,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
if (c.mFake) {
// Fake stream from default backend.
gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(),
onError.forget(), windowID, listener, mPrefs, GetBackend(windowID, true));
onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
} else {
// Stream from default device from WebRTC backend.
gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(),
@ -1383,26 +1392,22 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
}
MediaEngine*
MediaManager::GetBackend(uint64_t aWindowId, bool aFake)
MediaManager::GetBackend(uint64_t aWindowId)
{
// Plugin backends as appropriate. The default engine also currently
// includes picture support for Android.
// This IS called off main-thread.
MutexAutoLock lock(mMutex);
if (!mBackend) {
if (aFake) {
mBackend = new MediaEngineDefault();
} else {
#if defined(MOZ_WEBRTC)
#ifndef MOZ_B2G_CAMERA
mBackend = new MediaEngineWebRTC();
#ifndef MOZ_B2G_CAMERA
mBackend = new MediaEngineWebRTC();
#else
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
#endif
#else
mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId);
mBackend = new MediaEngineDefault();
#endif
#else
mBackend = new MediaEngineDefault();
#endif
}
}
return mBackend;
}

View File

@ -405,7 +405,7 @@ public:
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEDIAMANAGERSERVICE
MediaEngine* GetBackend(uint64_t aWindowId = 0, bool aFake = false);
MediaEngine* GetBackend(uint64_t aWindowId = 0);
StreamListeners *GetWindowListeners(uint64_t aWindowId) {
NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
@ -469,7 +469,7 @@ private:
static StaticRefPtr<MediaManager> sSingleton;
#ifdef MOZ_B2G_CAMERA
#ifdef MOZ_WIDGET_GONK
nsRefPtr<nsDOMCameraManager> mCameraManager;
#endif
};

View File

@ -20,36 +20,14 @@
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#define AUDIO_PERMISSION_NAME "audio-capture"
#define VIDEO_PERMISSION_NAME "video-capture"
using namespace mozilla::dom;
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);
aDesArray.AppendElement(PermissionRequest(type, access));
}
return len;
}
// Helper function for notifying permission granted
static nsresult
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
@ -115,7 +93,6 @@ public:
private:
bool mAudio; // Request for audio permission
bool mVideo; // Request for video permission
nsRefPtr<dom::GetUserMediaRequest> mRequest;
nsTArray<nsCOMPtr<nsIMediaDevice> > mDevices; // candiate device list
};
@ -131,7 +108,6 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
mRequest->GetConstraints(constraints);
mAudio = constraints.mAudio;
mVideo = constraints.mVideo;
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
@ -140,34 +116,10 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
if (mAudio && deviceType.EqualsLiteral("audio")) {
mDevices.AppendElement(device);
}
if (mVideo && deviceType.EqualsLiteral("video")) {
mDevices.AppendElement(device);
}
}
}
// nsIContentPermissionRequest methods
NS_IMETHODIMP
MediaPermissionRequest::GetTypes(nsIArray** aTypes)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
if (mAudio) {
nsCOMPtr<ContentPermissionType> AudioType =
new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"));
types->AppendElement(AudioType, false);
}
if (mVideo) {
nsCOMPtr<ContentPermissionType> VideoType =
new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"));
types->AppendElement(VideoType, false);
}
NS_IF_ADDREF(*aTypes = types);
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
{
@ -183,6 +135,24 @@ MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetType(nsACString &aType)
{
if (mAudio) {
aType = AUDIO_PERMISSION_NAME;
return NS_OK;
}
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetAccess(nsACString &aAccess)
{
aAccess = "unused";
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
{
@ -308,12 +278,13 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell());
NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
nsCOMPtr<nsIArray> typeArray;
rv = req->GetTypes(getter_AddRefs(typeArray));
nsAutoCString type;
rv = req->GetType(type);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<PermissionRequest> permArray;
ConvertArrayToPermissionRequest(typeArray, permArray);
nsAutoCString access;
rv = req->GetAccess(access);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrincipal> principal;
rv = req->GetPrincipal(getter_AddRefs(principal));
@ -321,7 +292,8 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr<MediaPermissionRequest> &req)
req->AddRef();
child->SendPContentPermissionRequestConstructor(req,
permArray,
type,
access,
IPC::Principal(principal));
req->Sendprompt();

View File

@ -7,9 +7,3 @@ ifdef MOZ_WEBRTC_LEAKING_TESTS
MOCHITEST_FILES += \
$(NULL)
endif
ifdef MOZ_B2G_CAMERA
MOCHITEST_FILES += \
test_getUserMedia_permission.html \
$(NULL)
endif

View File

@ -1,77 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=853356
-->
<head>
<meta charset="utf-8">
<title>mozGetUserMedia Permission Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=853356">Display camera/microphone permission acquisition prompt</a>
<script type="application/javascript">
var MockPermissionPrompt = SpecialPowers.MockPermissionPrompt;
MockPermissionPrompt.init();
var gCount = 0;
var gTests = [
{
constraints: {video: true, audio: false}
}
,
{
constraints: {video: false, audio: true}
}
,
{
constraints: {video: true, audio: true},
}
];
function gUM(data) {
var gum_success = function (stream) {
SimpleTest.info("TEST-INFO | Got succss callback for " + JSON.stringify(data.constraints));
var hasAudioTrack = stream.getAudioTracks().length > 0;
var hasVideoTrack = stream.getVideoTracks().length > 0;
is(data.constraints.audio, hasAudioTrack, "Request audio track:" +
data.constraints.audio + " contain audio track:" + hasAudioTrack);
is(data.constraints.video, hasVideoTrack, "Request video track:" +
data.constraints.video + " contain audio track:" + hasVideoTrack);
gCount++;
if (gCount < gTests.length) {
gUM(gTests[gCount]);
} else {
SimpleTest.finish();
}
}
var gum_fail = function () {
ok(false, "permission not granted for " + JSON.stringify(data.constraints));
SimpleTest.finish();
}
SimpleTest.info("TEST-INFO | Call getUserMedia for " + JSON.stringify(data.constraints));
navigator.mozGetUserMedia(data.constraints, gum_success, gum_fail);
}
SpecialPowers.pushPrefEnv({"set": [["media.navigator.permission.disabled", false]]},
function () {
SpecialPowers.addPermission('video-capture',
Ci.nsIPermissionManager.ALLOW_ACTION, document);
SpecialPowers.addPermission('audio-capture',
Ci.nsIPermissionManager.ALLOW_ACTION, document);
gUM(gTests[gCount]);
});
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -11,7 +11,7 @@ interface nsIDOMDOMCursor;
interface nsIDOMDOMRequest;
interface nsIDOMBlob;
[scriptable, builtinclass, uuid(0e4ff35e-ab84-434a-96b4-46807798cc7e)]
[scriptable, builtinclass, uuid(cfcc7067-083f-4e09-91aa-75067a721b70)]
interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget
{
nsIDOMDOMRequest getSegmentInfoForText(in DOMString text);
@ -65,6 +65,9 @@ interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget
nsIDOMDOMRequest retrieveMMS(in long id);
[optional_argc]
nsIDOMDOMRequest getSmscAddress([optional] in unsigned long serviceId);
[implicit_jscontext] attribute jsval onreceived;
[implicit_jscontext] attribute jsval onretrieving;
[implicit_jscontext] attribute jsval onsending;

View File

@ -19,9 +19,11 @@ dictionary MmsDeliveryInfo
{
DOMString? receiver;
DOMString? deliveryStatus;
jsval deliveryTimestamp; // Date object; null if not available (e.g.,
// |delivery| = "received" or not yet delivered).
};
[scriptable, builtinclass, uuid(85bfc639-0d8f-43fa-8c12-6bd2958bf219)]
[scriptable, builtinclass, uuid(3593c914-420a-11e3-a297-a3bdd768257f)]
interface nsIDOMMozMmsMessage : nsISupports
{
/**

View File

@ -14,7 +14,7 @@ dictionary SmsThreadListItem
unsigned long long unreadCount;
};
[scriptable, uuid(58780660-4080-11e3-8397-a7bb1b58cf12)]
[scriptable, uuid(0ee2ada1-fa98-40f1-adb3-0d7fd6df3f48)]
interface nsIMobileMessageCallback : nsISupports
{
/**
@ -54,4 +54,10 @@ interface nsIMobileMessageCallback : nsISupports
void notifySegmentInfoForTextGot(in nsIDOMMozSmsSegmentInfo info);
void notifyGetSegmentInfoForTextFailed(in long error);
/**
* SMSC Address get/set result
*/
void notifyGetSmscAddress(in DOMString aSmscAddress);
void notifyGetSmscAddressFailed(in long error);
};

View File

@ -13,7 +13,7 @@ interface nsIMobileMessageCallback;
#define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
%}
[scriptable, builtinclass, uuid(6ac68d50-3d60-11e3-a8ff-ab5ddef5f2ba)]
[scriptable, builtinclass, uuid(0a28f55b-95fe-4b32-994f-b08fe8edf77a)]
interface nsISmsService : nsISupports
{
readonly attribute unsigned long smsDefaultServiceId;
@ -32,4 +32,7 @@ interface nsISmsService : nsISupports
boolean isSilentNumber(in DOMString number);
void addSilentNumber(in DOMString number);
void removeSilentNumber(in DOMString number);
void getSmscAddress(in unsigned long serviceId,
in nsIMobileMessageCallback request);
};

View File

@ -15,6 +15,7 @@
#include "mozilla/dom/mobilemessage/Constants.h" // For MessageType
#include "mozilla/dom/mobilemessage/SmsTypes.h"
#include "nsDOMFile.h"
#include "nsCxPusher.h"
using namespace mozilla::idl;
using namespace mozilla::dom::mobilemessage;
@ -100,8 +101,11 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
for (uint32_t i = 0; i < len; i++) {
MmsDeliveryInfo info;
const MmsDeliveryInfoData &infoData = aData.deliveryInfo()[i];
// Prepare |info.receiver|.
info.receiver = infoData.receiver();
// Prepare |info.deliveryStatus|.
nsString statusStr;
switch (infoData.deliveryStatus()) {
case eDeliveryStatus_NotApplicable:
@ -127,6 +131,20 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData)
MOZ_CRASH("We shouldn't get any other delivery status!");
}
info.deliveryStatus = statusStr;
// Prepare |info.deliveryTimestamp|.
info.deliveryTimestamp = JSVAL_NULL;
if (infoData.deliveryTimestamp() != 0) {
AutoJSContext cx;
JS::Rooted<JSObject*>
dateObj(cx, JS_NewDateObjectMsec(cx, infoData.deliveryTimestamp()));
if (!dateObj) {
NS_WARNING("MmsMessage: Unable to create Date for deliveryTimestamp.");
} else {
info.deliveryTimestamp = OBJECT_TO_JSVAL(dateObj);
}
}
mDeliveryInfo.AppendElement(info);
}
}
@ -327,8 +345,11 @@ MmsMessage::GetData(ContentParent* aParent,
for (uint32_t i = 0; i < mDeliveryInfo.Length(); i++) {
MmsDeliveryInfoData infoData;
const MmsDeliveryInfo &info = mDeliveryInfo[i];
// Prepare |infoData.receiver|.
infoData.receiver().Assign(info.receiver);
// Prepare |infoData.deliveryStatus|.
DeliveryStatus status;
if (info.deliveryStatus.Equals(DELIVERY_STATUS_NOT_APPLICABLE)) {
status = eDeliveryStatus_NotApplicable;
@ -346,6 +367,15 @@ MmsMessage::GetData(ContentParent* aParent,
return false;
}
infoData.deliveryStatus() = status;
// Prepare |infoData.deliveryTimestamp|.
if (info.deliveryTimestamp == JSVAL_NULL) {
infoData.deliveryTimestamp() = 0;
} else {
AutoJSContext cx;
convertTimeToInt(cx, info.deliveryTimestamp, infoData.deliveryTimestamp());
}
aData.deliveryInfo().AppendElement(infoData);
}
@ -484,6 +514,13 @@ MmsMessage::GetDeliveryInfo(JSContext* aCx, JS::Value* aDeliveryInfo)
return NS_ERROR_FAILURE;
}
// Get |info.deliveryTimestamp|.
if (!JS_DefineProperty(aCx, infoJsObj,
"deliveryTimestamp", info.deliveryTimestamp,
NULL, NULL, JSPROP_ENUMERATE)) {
return NS_ERROR_FAILURE;
}
tmpJsVal = OBJECT_TO_JSVAL(infoJsObj);
if (!JS_SetElement(aCx, deliveryInfo, i, &tmpJsVal)) {
return NS_ERROR_FAILURE;

View File

@ -210,6 +210,28 @@ MobileMessageCallback::NotifyGetSegmentInfoForTextFailed(int32_t aError)
return NotifyError(aError, true);
}
NS_IMETHODIMP
MobileMessageCallback::NotifyGetSmscAddress(const nsAString& aSmscAddress)
{
AutoJSContext cx;
JSString* smsc = JS_NewUCStringCopyN(cx,
static_cast<const jschar *>(aSmscAddress.BeginReading()),
aSmscAddress.Length());
if (!smsc) {
return NotifyError(nsIMobileMessageCallback::INTERNAL_ERROR);
}
JS::Rooted<JS::Value> val(cx, STRING_TO_JSVAL(smsc));
return NotifySuccess(val);
}
NS_IMETHODIMP
MobileMessageCallback::NotifyGetSmscAddressFailed(int32_t aError)
{
return NotifyError(aError);
}
} // namesapce mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -525,5 +525,27 @@ MobileMessageManager::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
NS_IMETHODIMP
MobileMessageManager::GetSmscAddress(uint32_t aServiceId, uint8_t aArgc,
nsIDOMDOMRequest** aRequest)
{
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE);
nsresult rv;
if (aArgc != 1) {
rv = smsService->GetSmsDefaultServiceId(&aServiceId);
NS_ENSURE_SUCCESS(rv, rv);
}
nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
nsCOMPtr<nsIMobileMessageCallback> msgCallback = new MobileMessageCallback(request);
rv = smsService->GetSmscAddress(aServiceId, msgCallback);
NS_ENSURE_SUCCESS(rv, rv);
request.forget(aRequest);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -80,6 +80,14 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
SmsService::GetSmscAddress(uint32_t aServiceId,
nsIMobileMessageCallback *aRequest)
{
// TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress
return NS_OK;
}
} // namespace mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -68,6 +68,14 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber)
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
SmsService::GetSmscAddress(uint32_t aServiceId,
nsIMobileMessageCallback *aRequest)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
} // namespace mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -1544,19 +1544,19 @@ MmsService.prototype = {
// because the system message mechamism will rewrap the object
// based on the content window, which needs to know the properties.
gSystemMessenger.broadcastMessage(aName, {
type: aDomMessage.type,
id: aDomMessage.id,
threadId: aDomMessage.threadId,
delivery: aDomMessage.delivery,
deliveryInfo: aDomMessage.deliveryInfo,
sender: aDomMessage.sender,
receivers: aDomMessage.receivers,
timestamp: aDomMessage.timestamp,
read: aDomMessage.read,
subject: aDomMessage.subject,
smil: aDomMessage.smil,
attachments: aDomMessage.attachments,
expiryDate: aDomMessage.expiryDate
type: aDomMessage.type,
id: aDomMessage.id,
threadId: aDomMessage.threadId,
delivery: aDomMessage.delivery,
deliveryInfo: aDomMessage.deliveryInfo,
sender: aDomMessage.sender,
receivers: aDomMessage.receivers,
timestamp: aDomMessage.timestamp,
read: aDomMessage.read,
subject: aDomMessage.subject,
smil: aDomMessage.smil,
attachments: aDomMessage.attachments,
expiryDate: aDomMessage.expiryDate
});
},

View File

@ -1588,7 +1588,7 @@ MobileMessageDatabaseService.prototype = {
if (messageRecord.deliveryStatus != deliveryStatus) {
messageRecord.deliveryStatus = deliveryStatus;
// Update the delivery timestamp if it's successfully delivered.
// Update |deliveryTimestamp| if it's successfully delivered.
if (deliveryStatus == DELIVERY_STATUS_SUCCESS) {
messageRecord.deliveryTimestamp = Date.now();
}
@ -1601,6 +1601,12 @@ MobileMessageDatabaseService.prototype = {
for (let i = 0; i < deliveryInfo.length; i++) {
if (deliveryInfo[i].deliveryStatus != deliveryStatus) {
deliveryInfo[i].deliveryStatus = deliveryStatus;
// Update |deliveryTimestamp| if it's successfully delivered.
if (deliveryStatus == DELIVERY_STATUS_SUCCESS) {
deliveryInfo[i].deliveryTimestamp = Date.now();
}
isRecordUpdated = true;
}
}
@ -1655,6 +1661,12 @@ MobileMessageDatabaseService.prototype = {
}
if (deliveryInfo[j].deliveryStatus != deliveryStatus) {
deliveryInfo[j].deliveryStatus = deliveryStatus;
// Update |deliveryTimestamp| if it's successfully delivered.
if (deliveryStatus == DELIVERY_STATUS_SUCCESS) {
deliveryInfo[j].deliveryTimestamp = Date.now();
}
isRecordUpdated = true;
}
}
@ -1765,6 +1777,14 @@ MobileMessageDatabaseService.prototype = {
if (aMessage.type == "mms") {
aMessage.transactionIdIndex = aMessage.transactionId;
aMessage.isReadReportSent = false;
// If |deliveryTimestamp| is not specified, use 0 as default.
let deliveryInfo = aMessage.deliveryInfo;
for (let i = 0; i < deliveryInfo.length; i++) {
if (deliveryInfo[i].deliveryTimestamp == undefined) {
deliveryInfo[i].deliveryTimestamp = 0;
}
}
}
if (aMessage.type == "sms") {
@ -1818,7 +1838,9 @@ MobileMessageDatabaseService.prototype = {
aMessage.deliveryInfo = [];
for (let i = 0; i < receivers.length; i++) {
aMessage.deliveryInfo.push({
receiver: receivers[i], deliveryStatus: deliveryStatus });
receiver: receivers[i],
deliveryStatus: deliveryStatus,
deliveryTimestamp: 0 });
}
}

View File

@ -149,6 +149,19 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber)
return NS_OK;
}
NS_IMETHODIMP
SmsService::GetSmscAddress(uint32_t aServiceId,
nsIMobileMessageCallback *aRequest)
{
nsCOMPtr<nsIRadioInterface> radioInterface;
if (mRil) {
mRil->GetRadioInterface(aServiceId, getter_AddRefs(radioInterface));
}
NS_ENSURE_TRUE(radioInterface, NS_ERROR_FAILURE);
return radioInterface->GetSmscAddress(aRequest);
}
} // namespace mobilemessage
} // namespace dom
} // namespace mozilla

View File

@ -74,6 +74,11 @@ struct CreateThreadCursorRequest
{
};
struct GetSmscAddressRequest
{
uint32_t serviceId;
};
union IPCSmsRequest
{
SendMessageRequest;
@ -82,6 +87,7 @@ union IPCSmsRequest
DeleteMessageRequest;
MarkMessageReadRequest;
GetSegmentInfoForTextRequest;
GetSmscAddressRequest;
};
union IPCMobileMessageCursor

View File

@ -73,6 +73,16 @@ struct ReplyGetSegmentInfoForTextFail
int32_t error;
};
struct ReplyGetSmscAddress
{
nsString smscAddress;
};
struct ReplyGetSmscAddressFail
{
int32_t error;
};
union MessageReply
{
ReplyMessageSend;
@ -85,6 +95,8 @@ union MessageReply
ReplyMarkeMessageReadFail;
ReplyGetSegmentInfoForText;
ReplyGetSegmentInfoForTextFail;
ReplyGetSmscAddress;
ReplyGetSmscAddressFail;
};
} // namespace mobilemessage

View File

@ -216,6 +216,12 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply)
mReplyRequest->NotifyGetSegmentInfoForTextFailed(
aReply.get_ReplyGetSegmentInfoForTextFail().error());
break;
case MessageReply::TReplyGetSmscAddress:
mReplyRequest->NotifyGetSmscAddress(aReply.get_ReplyGetSmscAddress().smscAddress());
break;
case MessageReply::TReplyGetSmscAddressFail:
mReplyRequest->NotifyGetSmscAddressFailed(aReply.get_ReplyGetSmscAddressFail().error());
break;
default:
MOZ_CRASH("Received invalid response parameters!");
}

View File

@ -166,6 +166,13 @@ SmsIPCService::GetSegmentInfoForText(const nsAString& aText,
aRequest);
}
NS_IMETHODIMP
SmsIPCService::GetSmscAddress(uint32_t aServiceId,
nsIMobileMessageCallback* aRequest)
{
return SendRequest(GetSmscAddressRequest(aServiceId), aRequest);
}
NS_IMETHODIMP
SmsIPCService::Send(uint32_t aServiceId,
const nsAString& aNumber,

31
dom/mobilemessage/src/ipc/SmsParent.cpp Executable file → Normal file
View File

@ -367,6 +367,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor,
return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
case IPCSmsRequest::TGetSegmentInfoForTextRequest:
return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
case IPCSmsRequest::TGetSmscAddressRequest:
return actor->DoRequest(aRequest.get_GetSmscAddressRequest());
default:
MOZ_CRASH("Unknown type!");
}
@ -513,6 +515,23 @@ SmsRequestParent::DoRequest(const GetMessageRequest& aRequest)
return true;
}
bool
SmsRequestParent::DoRequest(const GetSmscAddressRequest& aRequest)
{
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
if (smsService) {
rv = smsService->GetSmscAddress(aRequest.serviceId(), this);
}
if (NS_FAILED(rv)) {
return NS_SUCCEEDED(NotifyGetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
}
return true;
}
bool
SmsRequestParent::DoRequest(const DeleteMessageRequest& aRequest)
{
@ -684,6 +703,18 @@ SmsRequestParent::NotifyGetSegmentInfoForTextFailed(int32_t aError)
return SendReply(ReplyGetSegmentInfoForTextFail(aError));
}
NS_IMETHODIMP
SmsRequestParent::NotifyGetSmscAddress(const nsAString& aSmscAddress)
{
return SendReply(ReplyGetSmscAddress(nsString(aSmscAddress)));
}
NS_IMETHODIMP
SmsRequestParent::NotifyGetSmscAddressFailed(int32_t aError)
{
return SendReply(ReplyGetSmscAddressFail(aError));
}
/*******************************************************************************
* MobileMessageCursorParent
******************************************************************************/

View File

@ -120,6 +120,9 @@ protected:
bool
DoRequest(const GetSegmentInfoForTextRequest& aRequest);
bool
DoRequest(const GetSmscAddressRequest& aRequest);
nsresult
SendReply(const MessageReply& aReply);
};

View File

@ -50,6 +50,7 @@ struct MmsDeliveryInfoData
{
nsString receiver;
DeliveryStatus deliveryStatus;
uint64_t deliveryTimestamp;
};
struct MmsMessageData

View File

@ -36,4 +36,5 @@ qemu = true
[test_invalid_address.js]
[test_mmsmessage_attachments.js]
[test_getthreads.js]
[test_smsc_address.js]
[test_dsds_default_service_id.js]

View File

@ -0,0 +1,78 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
SpecialPowers.addPermission("sms", true, document);
// Expected SMSC addresses of emulator
const SMSC = "\"+123456789\",145";
let manager = window.navigator.mozMobileMessage;
let tasks = {
// List of test fuctions. Each of them should call |tasks.next()| when
// completed or |tasks.finish()| to jump to the last one.
_tasks: [],
_nextTaskIndex: 0,
push: function push(func) {
this._tasks.push(func);
},
next: function next() {
let index = this._nextTaskIndex++;
let task = this._tasks[index];
try {
task();
} catch (ex) {
ok(false, "test task[" + index + "] throws: " + ex);
// Run last task as clean up if possible.
if (index != this._tasks.length - 1) {
this.finish();
}
}
},
finish: function finish() {
this._tasks[this._tasks.length - 1]();
},
run: function run() {
this.next();
}
};
tasks.push(function init() {
log("Initialize test object.");
ok(manager instanceof MozMobileMessageManager,
"manager is instance of " + manager.constructor);
tasks.next();
});
tasks.push(function readSmscAddress() {
log("read SMSC address");
let req = manager.getSmscAddress();
ok(req, "DOMRequest object for getting smsc address");
req.onsuccess = function(e) {
is(e.target.result, SMSC, "SMSC address");
tasks.next();
};
req.onerror = function(error) {
ok(false, "readSmscAddress(): Received 'onerror'");
tasks.finish();
};
});
// WARNING: All tasks should be pushed before this!!!
tasks.push(function cleanUp() {
manager.onreceived = null;
SpecialPowers.removePermission("sms", document);
finish();
});
// Start the test
tasks.run();

View File

@ -15,7 +15,6 @@
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
#include "nsCxPusher.h"
#include "nsContentPermissionHelper.h"
#include "nsIDocument.h"
#include "nsIObserverService.h"
#include "nsPIDOMWindow.h"
@ -386,11 +385,17 @@ nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
}
NS_IMETHODIMP
nsGeolocationRequest::GetTypes(nsIArray** aTypes)
nsGeolocationRequest::GetType(nsACString & aType)
{
return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused"),
aTypes);
aType = "geolocation";
return NS_OK;
}
NS_IMETHODIMP
nsGeolocationRequest::GetAccess(nsACString & aAccess)
{
aAccess = "unused";
return NS_OK;
}
NS_IMETHODIMP
@ -1447,15 +1452,12 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request)
return false;
}
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused")));
// Retain a reference so the object isn't deleted without IPDL's knowledge.
// Corresponding release occurs in DeallocPContentPermissionRequest.
request->AddRef();
child->SendPContentPermissionRequestConstructor(request,
permArray,
NS_LITERAL_CSTRING("geolocation"),
NS_LITERAL_CSTRING("unused"),
IPC::Principal(mPrincipal));
request->Sendprompt();

View File

@ -15,7 +15,6 @@
#include "PCOMContentPermissionRequestChild.h"
#include "nsIScriptSecurityManager.h"
#include "nsServiceManagerUtils.h"
#include "PermissionMessageUtils.h"
namespace mozilla {
namespace dom {
@ -178,12 +177,9 @@ DesktopNotification::Init()
// Corresponding release occurs in DeallocPContentPermissionRequest.
nsRefPtr<DesktopNotificationRequest> copy = request;
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused")));
child->SendPContentPermissionRequestConstructor(copy.forget().get(),
permArray,
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
IPC::Principal(mPrincipal));
request->Sendprompt();
@ -355,11 +351,17 @@ DesktopNotificationRequest::Allow()
}
NS_IMETHODIMP
DesktopNotificationRequest::GetTypes(nsIArray** aTypes)
DesktopNotificationRequest::GetType(nsACString & aType)
{
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
aTypes);
aType = "desktop-notification";
return NS_OK;
}
NS_IMETHODIMP
DesktopNotificationRequest::GetAccess(nsACString & aAccess)
{
aAccess = "unused";
return NS_OK;
}
} // namespace dom

View File

@ -24,7 +24,6 @@
#include "nsDOMJSUtils.h"
#include "nsIScriptSecurityManager.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "nsContentPermissionHelper.h"
#ifdef MOZ_B2G
#include "nsIDOMDesktopNotification.h"
#endif
@ -268,11 +267,9 @@ NotificationPermissionRequest::Run()
// Corresponding release occurs in DeallocPContentPermissionRequest.
AddRef();
nsTArray<PermissionRequest> permArray;
permArray.AppendElement(PermissionRequest(
NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused")));
child->SendPContentPermissionRequestConstructor(this, permArray,
NS_NAMED_LITERAL_CSTRING(type, "desktop-notification");
NS_NAMED_LITERAL_CSTRING(access, "unused");
child->SendPContentPermissionRequestConstructor(this, type, access,
IPC::Principal(mPrincipal));
Sendprompt();
@ -345,11 +342,17 @@ NotificationPermissionRequest::CallCallback()
}
NS_IMETHODIMP
NotificationPermissionRequest::GetTypes(nsIArray** aTypes)
NotificationPermissionRequest::GetAccess(nsACString& aAccess)
{
return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"),
NS_LITERAL_CSTRING("unused"),
aTypes);
aAccess.AssignLiteral("unused");
return NS_OK;
}
NS_IMETHODIMP
NotificationPermissionRequest::GetType(nsACString& aType)
{
aType.AssignLiteral("desktop-notification");
return NS_OK;
}
bool

View File

@ -271,7 +271,9 @@ MobileCellInfo.prototype = {
cdmaNetworkId: -1
};
function VoicemailStatus() {}
function VoicemailStatus(clientId) {
this.serviceId = clientId;
}
VoicemailStatus.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]),
classID: VOICEMAILSTATUS_CID,
@ -284,8 +286,9 @@ VoicemailStatus.prototype = {
// nsIDOMMozVoicemailStatus
serviceId: -1,
hasMessages: false,
messageCount: Ci.nsIDOMMozVoicemailStatus.MESSAGE_COUNT_UNKNOWN,
messageCount: -1, // Count unknown.
returnNumber: null,
returnMessage: null
};
@ -451,6 +454,8 @@ function RILContentHelper() {
debug("Number of clients: " + this.numClients);
this.rilContexts = [];
this.voicemailInfos = [];
this.voicemailStatuses = [];
for (let clientId = 0; clientId < this.numClients; clientId++) {
this.rilContexts[clientId] = {
cardState: RIL.GECKO_CARDSTATE_UNKNOWN,
@ -459,9 +464,10 @@ function RILContentHelper() {
voiceConnectionInfo: new MobileConnectionInfo(),
dataConnectionInfo: new MobileConnectionInfo()
};
this.voicemailInfos[clientId] = new VoicemailInfo();
}
this.voicemailInfo = new VoicemailInfo();
this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId();
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
@ -1361,7 +1367,8 @@ RILContentHelper.prototype = {
_voicemailListeners: null,
_iccListeners: null,
voicemailStatus: null,
voicemailInfos: null,
voicemailStatuses: null,
voicemailDefaultServiceId: 0,
getVoicemailDefaultServiceId: function getVoicemailDefaultServiceId() {
@ -1374,27 +1381,33 @@ RILContentHelper.prototype = {
return id;
},
getVoicemailInfo: function getVoicemailInfo() {
getVoicemailInfo: function getVoicemailInfo(clientId) {
// Get voicemail infomation by IPC only on first time.
this.getVoicemailInfo = function getVoicemailInfo() {
return this.voicemailInfo;
this.getVoicemailInfo = function getVoicemailInfo(clientId) {
return this.voicemailInfos[clientId];
};
let voicemailInfo =
cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: 0})[0];
if (voicemailInfo) {
this.updateInfo(voicemailInfo, this.voicemailInfo);
for (let cId = 0; cId < gNumRadioInterfaces; cId++) {
let voicemailInfo =
cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0];
if (voicemailInfo) {
this.updateInfo(voicemailInfo, this.voicemailInfos[cId]);
}
}
return this.voicemailInfo;
return this.voicemailInfos[clientId];
},
get voicemailNumber() {
return this.getVoicemailInfo().number;
getVoicemailNumber: function getVoicemailNumber(clientId) {
return this.getVoicemailInfo(clientId).number;
},
get voicemailDisplayName() {
return this.getVoicemailInfo().displayName;
getVoicemailDisplayName: function getVoicemailDisplayName(clientId) {
return this.getVoicemailInfo(clientId).displayName;
},
getVoicemailStatus: function getVoicemailStatus(clientId) {
return this.voicemailStatuses[clientId];
},
registerListener: function registerListener(listenerType, clientId, listener) {
@ -1442,13 +1455,17 @@ RILContentHelper.prototype = {
registerVoicemailMsg: function registerVoicemailMsg(listener) {
debug("Registering for voicemail-related messages");
//TODO: Bug 814634 - WebVoicemail API: support multiple sim cards.
// To follow the listener registration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.registerListener("_voicemailListeners", 0, listener);
cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg");
},
unregisterVoicemailMsg: function unregisteVoicemailMsg(listener) {
//TODO: Bug 814634 - WebVoicemail API: support multiple sim cards.
// To follow the listener unregistration scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
// See |handleVoicemailNotification|.
this.unregisterListener("_voicemailListeners", 0, listener);
},
@ -1619,7 +1636,7 @@ RILContentHelper.prototype = {
this.handleVoicemailNotification(clientId, data);
break;
case "RIL:VoicemailInfoChanged":
this.updateInfo(data, this.voicemailInfo);
this.updateInfo(data, this.voicemailInfos[clientId]);
break;
case "RIL:CardLockResult": {
let requestId = data.requestId;
@ -1835,41 +1852,44 @@ RILContentHelper.prototype = {
this.fireRequestSuccess(message.requestId, result);
},
handleVoicemailNotification: function handleVoicemailNotification(clientId, message) {
// Bug 814634 - WebVoicemail API: support multiple sim cards
handleVoicemailNotification: function handleVoicemailNotification(clientId,
message) {
let changed = false;
if (!this.voicemailStatus) {
this.voicemailStatus = new VoicemailStatus();
if (!this.voicemailStatuses[clientId]) {
this.voicemailStatuses[clientId] = new VoicemailStatus(clientId);
}
if (this.voicemailStatus.hasMessages != message.active) {
let voicemailStatus = this.voicemailStatuses[clientId];
if (voicemailStatus.hasMessages != message.active) {
changed = true;
this.voicemailStatus.hasMessages = message.active;
voicemailStatus.hasMessages = message.active;
}
if (this.voicemailStatus.messageCount != message.msgCount) {
if (voicemailStatus.messageCount != message.msgCount) {
changed = true;
this.voicemailStatus.messageCount = message.msgCount;
voicemailStatus.messageCount = message.msgCount;
} else if (message.msgCount == -1) {
// For MWI using DCS the message count is not available
changed = true;
}
if (this.voicemailStatus.returnNumber != message.returnNumber) {
if (voicemailStatus.returnNumber != message.returnNumber) {
changed = true;
this.voicemailStatus.returnNumber = message.returnNumber;
voicemailStatus.returnNumber = message.returnNumber;
}
if (this.voicemailStatus.returnMessage != message.returnMessage) {
if (voicemailStatus.returnMessage != message.returnMessage) {
changed = true;
this.voicemailStatus.returnMessage = message.returnMessage;
voicemailStatus.returnMessage = message.returnMessage;
}
if (changed) {
this._deliverEvent(clientId,
// To follow the event delivering scheme, we add a dummy clientId 0.
// All voicemail events are routed to listener for client id 0.
this._deliverEvent(0,
"_voicemailListeners",
"notifyStatusChanged",
[this.voicemailStatus]);
[voicemailStatus]);
}
},

View File

@ -2925,6 +2925,18 @@ RadioInterface.prototype = {
request.notifySegmentInfoForTextGot(result);
},
getSmscAddress: function getSmscAddress(request) {
this.workerMessenger.send("getSmscAddress",
null,
(function(response) {
if (!response.errorMsg) {
request.notifyGetSmscAddress(response.smscAddress);
} else {
request.notifyGetSmscAddressFailed(response.errorMsg);
}
}).bind(this));
},
sendSMS: function sendSMS(number, message, silent, request) {
let strict7BitEncoding;
try {

View File

@ -97,7 +97,7 @@ interface nsIRilSendWorkerMessageCallback : nsISupports
boolean handleResponse(in jsval response);
};
[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)]
[scriptable, uuid(5b14cf79-2846-4226-b07f-9b9977b525fe)]
interface nsIRadioInterface : nsISupports
{
readonly attribute nsIRilContext rilContext;
@ -128,6 +128,8 @@ interface nsIRadioInterface : nsISupports
void sendWorkerMessage(in DOMString type,
[optional] in jsval message,
[optional] in nsIRilSendWorkerMessageCallback callback);
void getSmscAddress(in nsIMobileMessageCallback request);
};
[scriptable, uuid(70d3a18c-4063-11e3-89de-0f9ec19fd803)]

View File

@ -1793,19 +1793,30 @@ let RIL = {
/**
* Get the Short Message Service Center address.
*/
getSMSCAddress: function getSMSCAddress() {
Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS);
getSmscAddress: function getSmscAddress(options) {
if (!this.SMSC) {
Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS, options);
return;
}
if (!options || options.rilMessageType !== "getSmscAddress") {
return;
}
options.smscAddress = this.SMSC;
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendChromeMessage(options);
},
/**
* Set the Short Message Service Center address.
*
* @param SMSC
* @param smscAddress
* Short Message Service Center address in PDU format.
*/
setSMSCAddress: function setSMSCAddress(options) {
Buf.newParcel(REQUEST_SET_SMSC_ADDRESS);
Buf.writeString(options.SMSC);
setSmscAddress: function setSmscAddress(options) {
Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options);
Buf.writeString(options.smscAddress);
Buf.sendParcel();
},
@ -3330,7 +3341,7 @@ let RIL = {
let rs = this.voiceRegistrationState;
let stateChanged = this._processCREG(rs, state);
if (stateChanged && rs.connected) {
RIL.getSMSCAddress();
RIL.getSmscAddress();
}
let cell = rs.cell;
@ -5914,11 +5925,15 @@ RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = function REQUEST_EXIT_EMERGENCY_CALL
this.sendChromeMessage(options);
};
RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) {
if (options.rilRequestError) {
this.SMSC = options.rilRequestError ? null : Buf.readString();
if (!options || options.rilMessageType !== "getSmscAddress") {
return;
}
this.SMSC = Buf.readString();
options.smscAddress = this.SMSC;
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendChromeMessage(options);
};
RIL[REQUEST_SET_SMSC_ADDRESS] = null;
RIL[REQUEST_REPORT_SMS_MEMORY_STATUS] = null;

View File

@ -10,12 +10,14 @@
#include "nsIDOMMozVoicemailStatus.h"
#include "nsIDOMMozVoicemailEvent.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsDOMClassInfo.h"
#include "nsServiceManagerUtils.h"
#include "GeneratedEvents.h"
#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
using namespace mozilla::dom;
@ -67,18 +69,48 @@ Voicemail::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
return MozVoicemailBinding::Wrap(aCx, aScope, this);
}
bool
Voicemail::IsValidServiceId(uint32_t aServiceId) const
{
uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1);
return aServiceId < numClients;
}
bool
Voicemail::PassedOrDefaultServiceId(const Optional<uint32_t>& aServiceId,
uint32_t& aResult) const
{
if (aServiceId.WasPassed()) {
if (!IsValidServiceId(aServiceId.Value())) {
return false;
}
aResult = aServiceId.Value();
} else {
mProvider->GetVoicemailDefaultServiceId(&aResult);
}
return true;
}
// MozVoicemail WebIDL
already_AddRefed<nsIDOMMozVoicemailStatus>
Voicemail::GetStatus(ErrorResult& aRv) const
Voicemail::GetStatus(const Optional<uint32_t>& aServiceId,
ErrorResult& aRv) const
{
if (!mProvider) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return nullptr;
}
nsCOMPtr<nsIDOMMozVoicemailStatus> status;
nsresult rv = mProvider->GetVoicemailStatus(getter_AddRefs(status));
nsresult rv = mProvider->GetVoicemailStatus(id, getter_AddRefs(status));
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return nullptr;
@ -88,7 +120,8 @@ Voicemail::GetStatus(ErrorResult& aRv) const
}
void
Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const
Voicemail::GetNumber(const Optional<uint32_t>& aServiceId, nsString& aNumber,
ErrorResult& aRv) const
{
aNumber.SetIsVoid(true);
@ -97,11 +130,18 @@ Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const
return;
}
aRv = mProvider->GetVoicemailNumber(aNumber);
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
aRv = mProvider->GetVoicemailNumber(id, aNumber);
}
void
Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const
Voicemail::GetDisplayName(const Optional<uint32_t>& aServiceId, nsString& aDisplayName,
ErrorResult& aRv) const
{
aDisplayName.SetIsVoid(true);
@ -110,7 +150,13 @@ Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const
return;
}
aRv = mProvider->GetVoicemailDisplayName(aDisplayName);
uint32_t id = 0;
if (!PassedOrDefaultServiceId(aServiceId, id)) {
aRv.Throw(NS_ERROR_INVALID_ARG);
return;
}
aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName);
}
// nsIVoicemailListener

View File

@ -52,19 +52,28 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
already_AddRefed<nsIDOMMozVoicemailStatus>
GetStatus(ErrorResult& aRv) const;
GetStatus(const Optional<uint32_t>& aServiceId, ErrorResult& aRv) const;
void
GetNumber(nsString& aNumber, ErrorResult& aRv) const;
GetNumber(const Optional<uint32_t>& aServiceId, nsString& aNumber,
ErrorResult& aRv) const;
void
GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const;
GetDisplayName(const Optional<uint32_t>& aServiceId, nsString& aDisplayName,
ErrorResult& aRv) const;
IMPL_EVENT_HANDLER(statuschanged)
private:
nsCOMPtr<nsIVoicemailProvider> mProvider;
nsRefPtr<Listener> mListener;
bool
IsValidServiceId(uint32_t aServiceId) const;
bool
PassedOrDefaultServiceId(const Optional<uint32_t>& aServiceId,
uint32_t& aResult) const;
};
} // namespace dom

View File

@ -6,13 +6,10 @@
#include "nsISupports.idl"
[scriptable, uuid(8c58859a-e006-466a-ad76-b188ba0918ab)]
[scriptable, uuid(efd352af-9eee-48dc-8e92-4d4fdbc89ecb)]
interface nsIDOMMozVoicemailStatus : nsISupports
{
/**
* There are voicemail messages waiting, but the count is unknown.
*/
const long MESSAGE_COUNT_UNKNOWN = -1;
readonly attribute unsigned long serviceId;
/**
* Whether or not there are messages waiting in the voicemail box
@ -22,7 +19,7 @@ interface nsIDOMMozVoicemailStatus : nsISupports
/**
* The total message count. Some voicemail indicators will only specify that
* messages are waiting, but not the actual number. In that case, the value
* of messageCount will be MESSAGE_COUNT_UNKNOWN (-1).
* of messageCount will be -1, indicating the unknown message count.
*
* Logic for a voicemail notification might look something like:
* if (status.hasMessages) {

View File

@ -22,7 +22,7 @@ interface nsIVoicemailListener : nsISupports
* XPCOM component (in the content process) that provides the voicemail
* information.
*/
[scriptable, uuid(38746f3c-f4e3-4804-b900-ba2463b923c8)]
[scriptable, uuid(1bbfff90-88f7-4d73-896e-9620a0000ab0)]
interface nsIVoicemailProvider : nsISupports
{
readonly attribute unsigned long voicemailDefaultServiceId;
@ -35,7 +35,7 @@ interface nsIVoicemailProvider : nsISupports
void registerVoicemailMsg(in nsIVoicemailListener listener);
void unregisterVoicemailMsg(in nsIVoicemailListener listener);
readonly attribute nsIDOMMozVoicemailStatus voicemailStatus;
readonly attribute DOMString voicemailNumber;
readonly attribute DOMString voicemailDisplayName;
nsIDOMMozVoicemailStatus getVoicemailStatus(in unsigned long clientId);
DOMString getVoicemailNumber(in unsigned long clientId);
DOMString getVoicemailDisplayName(in unsigned long clientId);
};

View File

@ -8,9 +8,14 @@ SpecialPowers.addPermission("voicemail", true, document);
let voicemail = window.navigator.mozVoicemail;
ok(voicemail instanceof MozVoicemail);
let serviceId = 0;
// These are the emulator's hard coded voicemail number and alphaId
is(voicemail.number, "+15552175049");
is(voicemail.displayName, "Voicemail");
is(voicemail.getNumber(serviceId), "+15552175049");
is(voicemail.getDisplayName(serviceId), "Voicemail");
is(voicemail.getNumber(), "+15552175049");
is(voicemail.getDisplayName(), "Voicemail");
SpecialPowers.removePermission("voicemail", document);
finish();

View File

@ -4,6 +4,8 @@
SpecialPowers.addPermission("voicemail", true, document);
let voicemail = window.navigator.mozVoicemail;
let serviceId = 0;
ok(voicemail instanceof MozVoicemail);
is(voicemail.status, null);
@ -42,10 +44,13 @@ function sendIndicatorPDU(pdu, listener, nextTest) {
// See RadioInterfaceLayer.js / Bug #768441
function isVoicemailStatus(status) {
is(voicemail.status.hasMessages, status.hasMessages);
is(voicemail.status.messageCount, status.messageCount);
is(voicemail.status.returnNumber, status.returnNumber);
is(voicemail.status.returnMessage, status.returnMessage);
is(voicemail.getStatus(), status);
is(voicemail.getStatus(serviceId), status);
is(voicemail.getStatus().hasMessages, status.hasMessages);
is(voicemail.getStatus().messageCount, status.messageCount);
is(voicemail.getStatus().returnNumber, status.returnNumber);
is(voicemail.getStatus().returnMessage, status.returnMessage);
}
const MWI_PDU_PREFIX = "0000";
@ -80,7 +85,7 @@ function testLevel1Indicator() {
// TODO: bug 905228 - MozVoicemailStatus is not defined.
//ok(status instanceof MozVoicemailStatus);
is(status.hasMessages, true);
is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN);
is(status.messageCount, -1);
is(status.returnNumber, MWI_LEVEL1_SENDER);
is(status.returnMessage, MWI_DEFAULT_BODY);
isVoicemailStatus(status);

View File

@ -11,26 +11,28 @@ interface MozVoicemailStatus;
interface MozVoicemail : EventTarget
{
/**
* The current voicemail status, or null when the status is unknown
* The current voicemail status of a specified service, or null when the
* status is unknown.
*/
[GetterThrows]
readonly attribute MozVoicemailStatus? status;
[Throws]
MozVoicemailStatus getStatus(optional unsigned long serviceId);
/**
* The voicemail box dialing number, or null if one wasn't found
* The voicemail box dialing number of a specified service, or null if one
* wasn't found.
*/
[GetterThrows]
readonly attribute DOMString? number;
[Throws]
DOMString getNumber(optional unsigned long serviceId);
/**
* The display name of the voicemail box dialing number, or null if one
* wasn't found
* The display name of the voicemail box dialing number of a specified service,
* or null if one wasn't found.
*/
[GetterThrows]
readonly attribute DOMString? displayName;
[Throws]
DOMString getDisplayName(optional unsigned long serviceId);
/**
* The current voicemail status has changed
* The current voicemail status has changed.
*/
attribute EventHandler onstatuschanged;
};

View File

@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
handleExistingPermission: function handleExistingPermission(request, type, isApp) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
handleExistingPermission: function handleExistingPermission(request, isApp) {
let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type);
if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
return true;
@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = {
return true;
}
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) {
if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) {
request.cancel();
return true;
}
@ -62,16 +62,8 @@ ContentPermissionPrompt.prototype = {
prompt: function(request) {
let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID;
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Returns true if the request was handled
if (this.handleExistingPermission(request, perm.type, isApp))
if (this.handleExistingPermission(request, isApp))
return;
let chromeWin = this.getChromeForRequest(request);
@ -80,17 +72,17 @@ ContentPermissionPrompt.prototype = {
return;
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let entityName = kEntities[perm.type];
let entityName = kEntities[request.type];
let buttons = [{
label: browserBundle.GetStringFromName(entityName + ".allow"),
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked) {
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION);
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION);
} else if (isApp || entityName == "desktopNotification") {
// Otherwise allow the permission for the current session (if the request comes from an app or if it's a desktop-notification request)
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
}
request.allow();
@ -101,7 +93,7 @@ ContentPermissionPrompt.prototype = {
callback: function(aChecked) {
// If the user checked "Don't ask again", make a permanent exception
if (aChecked)
Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION);
Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION);
request.cancel();
}

View File

@ -34,18 +34,9 @@ this.MockPermissionPrompt = {
init: function() {
this.reset();
if (!registrar.isCIDRegistered(newClassID)) {
try {
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
} catch (ex) {
oldClassID = "";
oldFactory = null;
dump("TEST-INFO | can't get permission prompt registered component, " +
"assuming there is none");
}
if (oldFactory != "" && oldFactory != null) {
registrar.unregisterFactory(oldClassID, oldFactory);
}
oldClassID = registrar.contractIDToCID(CONTRACT_ID);
oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
registrar.unregisterFactory(oldClassID, oldFactory);
registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory);
}
},
@ -70,17 +61,14 @@ MockPermissionPromptInstance.prototype = {
prompt: function(request) {
let perms = request.types.QueryInterface(Ci.nsIArray);
for (let idx = 0; idx < perms.length; idx++) {
let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType);
if (Services.perms.testExactPermissionFromPrincipal(
request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) {
request.cancel();
return;
}
this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal,
request.type);
if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) {
request.allow();
}
else {
request.cancel();
}
request.allow();
}
};

View File

@ -30,25 +30,17 @@ ContentPermission.prototype = {
},
prompt: function(request) {
// Only allow exactly one permission rquest here.
let types = request.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
request.cancel();
return;
}
let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
// Reuse any remembered permission preferences
let result =
Services.perms.testExactPermissionFromPrincipal(request.principal,
perm.type);
request.type);
// We used to use the name "geo" for the geolocation permission, now we're
// using "geolocation". We need to check both to support existing
// installations.
if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION ||
result == Ci.nsIPermissionManager.PROMPT_ACTION) &&
perm.type == "geolocation") {
request.type == "geolocation") {
let geoResult = Services.perms.testExactPermission(request.principal.URI,
"geo");
// We override the result only if the "geo" permission was allowed or
@ -64,7 +56,7 @@ ContentPermission.prototype = {
return;
} else if (result == Ci.nsIPermissionManager.DENY_ACTION ||
(result == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
UNKNOWN_FAIL.indexOf(perm.type) >= 0)) {
UNKNOWN_FAIL.indexOf(request.type) >= 0)) {
request.cancel();
return;
}
@ -79,16 +71,16 @@ ContentPermission.prototype = {
let remember = {value: false};
let choice = Services.prompt.confirmEx(
chromeWin,
bundle.formatStringFromName(perm.type + ".title", [name], 1),
bundle.GetStringFromName(perm.type + ".description"),
bundle.formatStringFromName(request.type + ".title", [name], 1),
bundle.GetStringFromName(request.type + ".description"),
// Set both buttons to strings with the cancel button being default
Ci.nsIPromptService.BUTTON_POS_1_DEFAULT |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 |
Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1,
bundle.GetStringFromName(perm.type + ".allow"),
bundle.GetStringFromName(perm.type + ".deny"),
bundle.GetStringFromName(request.type + ".allow"),
bundle.GetStringFromName(request.type + ".deny"),
null,
bundle.GetStringFromName(perm.type + ".remember"),
bundle.GetStringFromName(request.type + ".remember"),
remember);
let action = Ci.nsIPermissionManager.ALLOW_ACTION;
@ -98,10 +90,10 @@ ContentPermission.prototype = {
if (remember.value) {
// Persist the choice if the user wants to remember
Services.perms.addFromPrincipal(request.principal, perm.type, action);
Services.perms.addFromPrincipal(request.principal, request.type, action);
} else {
// Otherwise allow the permission for the current session
Services.perms.addFromPrincipal(request.principal, perm.type, action,
Services.perms.addFromPrincipal(request.principal, request.type, action,
Ci.nsIPermissionManager.EXPIRE_SESSION);
}