Bug 978660 - no need to prompt if gUM is already granted. r=fabrice.

This commit is contained in:
Shih-Chiang Chien 2014-05-13 13:58:04 +08:00
Родитель 289ee87838
Коммит 8cf6c4014d
3 изменённых файлов: 224 добавлений и 20 удалений

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

@ -42,6 +42,39 @@ XPCOMUtils.defineLazyServiceGetter(this,
XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
"resource://gre/modules/SystemAppProxy.jsm");
/**
* Determine if a permission should be prompt to user or not.
*
* @param aPerm requested permission
* @param aAction the action according to principal
* @return true if prompt is required
*/
function shouldPrompt(aPerm, aAction) {
return ((aAction == Ci.nsIPermissionManager.PROMPT_ACTION) ||
(aAction == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0));
}
/**
* Create the default choices for the requested permissions
*
* @param aTypesInfo requested permissions
* @return the default choices for permissions with options, return
* undefined if no option in all requested permissions.
*/
function buildDefaultChoices(aTypesInfo) {
let choices;
for (let type of aTypesInfo) {
if (type.options.length > 0) {
if (!choices) {
choices = {};
}
choices[type.access] = type.options[0];
}
}
return choices;
}
/**
* aTypesInfo is an array of {permission, access, action, deny} which keeps
* the information of each permission. This arrary is initialized in
@ -62,9 +95,7 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession)
{
let type =
permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm);
if (type == Ci.nsIPermissionManager.PROMPT_ACTION ||
(type == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) {
if (shouldPrompt(aPerm, type)) {
debug("add " + aPerm + " to permission manager with ALLOW_ACTION");
if (!aSession) {
permissionManager.addFromPrincipal(aPrincipal,
@ -104,22 +135,23 @@ ContentPermissionPrompt.prototype = {
type.action =
Services.perms.testExactPermissionFromPrincipal(request.principal,
type.access);
if (type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION &&
PROMPT_FOR_UNKNOWN.indexOf(type.access) >= 0) {
if (shouldPrompt(type.access, type.action)) {
type.action = Ci.nsIPermissionManager.PROMPT_ACTION;
}
});
// If all permissions are allowed already, call allow() without prompting.
// If all permissions are allowed already and no more than one option,
// call allow() without prompting.
let checkAllowPermission = function(type) {
if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) {
if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION &&
type.options.length <= 1) {
return true;
}
return false;
}
if (typesInfo.every(checkAllowPermission)) {
debug("all permission requests are allowed");
request.allow();
request.allow(buildDefaultChoices(typesInfo));
return true;
}
@ -185,7 +217,8 @@ ContentPermissionPrompt.prototype = {
}
return !type.deny;
}
if (typesInfo.filter(notDenyAppPrincipal).length === 0) {
// Cancel the entire request if one of the requested permissions is denied
if (!typesInfo.every(notDenyAppPrincipal)) {
request.cancel();
return true;
}
@ -206,11 +239,6 @@ ContentPermissionPrompt.prototype = {
_id: 0,
prompt: function(request) {
if (secMan.isSystemPrincipal(request.principal)) {
request.allow();
return;
}
// Initialize the typesInfo and set the default value.
let typesInfo = [];
let perms = request.types.QueryInterface(Ci.nsIArray);
@ -234,6 +262,12 @@ ContentPermissionPrompt.prototype = {
typesInfo.push(tmp);
}
if (secMan.isSystemPrincipal(request.principal)) {
request.allow(buildDefaultChoices(typesInfo));
return;
}
if (typesInfo.length == 0) {
request.cancel();
return;
@ -254,11 +288,9 @@ ContentPermissionPrompt.prototype = {
return;
}
// prompt PROMPT_ACTION request only.
typesInfo.forEach(function(aType, aIndex) {
if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) {
typesInfo.splice(aIndex);
}
// prompt PROMPT_ACTION request or request with options.
typesInfo = typesInfo.filter(function(type) {
return !type.deny && (type.action == Ci.nsIPermissionManager.PROMPT_ACTION || type.options.length > 0) ;
});
let frame = request.element;
@ -366,6 +398,9 @@ ContentPermissionPrompt.prototype = {
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let isGranted = typesInfo.every(function(type) {
return type.action == Ci.nsIPermissionManager.ALLOW_ACTION;
});
let permissions = {};
for (let i in typesInfo) {
debug("prompt " + typesInfo[i].permission);
@ -378,7 +413,8 @@ ContentPermissionPrompt.prototype = {
id: requestId,
origin: principal.origin,
isApp: isApp,
remember: remember
remember: remember,
isGranted: isGranted,
};
if (isApp) {

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

@ -11,4 +11,6 @@ run-if = toolkit == "gonk"
run-if = toolkit == "gonk"
[test_permission_deny.html]
run-if = toolkit == "gonk"
[test_permission_gum_remember.html]
run-if = toolkit == "gonk"
[test_systemapp.html]

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

@ -0,0 +1,166 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=978660
-->
<head>
<meta charset="utf-8">
<title>gUM Remember Permission Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978660">Test remembering gUM Permission</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
gScript.addMessageListener('permission-request', function(detail) {
ok(false, 'unexpected mozChromeEvent for permission prompt');
let response = {
id: detail.id,
type: 'permission-deny',
remember: false,
};
gScript.sendAsyncMessage('permission-response', response);
});
var gTests = [
{
'audio': true,
'video': {facingMode: 'environment', required: ['facingMode']},
},
{
'video': {facingMode: 'environment', required: ['facingMode']},
},
{
'audio': true,
},
];
function testGranted() {
info('test remember permission granted');
return new Promise(function(resolve, reject) {
let steps = [].concat(gTests);
function nextStep() {
if (steps.length > 0) {
let requestedType = steps.shift();
info('getUserMedia for ' + JSON.stringify(requestedType));
navigator.mozGetUserMedia(requestedType, function success() {
ok(true, 'expected gUM success');
nextStep();
}, function failure(err) {
ok(false, 'unexpected gUM fail: ' + err);
nextStep();
});
} else {
resolve();
}
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: true, context: document},
{type: 'audio-capture', allow: true, context: document},
], nextStep);
});
}
function testDenied() {
info('test remember permission denied');
return new Promise(function(resolve, reject) {
let steps = [].concat(gTests);
function nextStep() {
if (steps.length > 0) {
let requestedType = steps.shift();
info('getUserMedia for ' + JSON.stringify(requestedType));
navigator.mozGetUserMedia(requestedType, function success() {
ok(false, 'unexpected gUM success');
nextStep();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
nextStep();
});
} else {
resolve();
}
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: false, context: document},
{type: 'audio-capture', allow: false, context: document},
], nextStep);
});
}
function testPartialDeniedAudio() {
info('test remember permission partial denied: audio');
return new Promise(function(resolve, reject) {
info('getUserMedia for video and audio');
function nextStep() {
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
audio: true}, function success() {
ok(false, 'unexpected gUM success');
resolve();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
resolve();
});
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: true, context: document},
{type: 'audio-capture', allow: false, context: document},
], nextStep);
});
}
function testPartialDeniedVideo() {
info('test remember permission partial denied: video');
return new Promise(function(resolve, reject) {
info('getUserMedia for video and audio');
function nextStep() {
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
audio: true}, function success() {
ok(false, 'unexpected gUM success');
resolve();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
resolve();
});
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: false, context: document},
{type: 'audio-capture', allow: true, context: document},
], nextStep);
});
}
function runTests() {
testGranted()
.then(testDenied)
.then(testPartialDeniedAudio)
.then(testPartialDeniedVideo)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown', '');
gScript.destroy();
SimpleTest.finish();
});
}
SpecialPowers.pushPrefEnv({
'set': [
['media.navigator.permission.disabled', false],
]
}, runTests);
</script>
</pre>
</body>
</html>