Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1730)

Unified Diff: chrome/browser/permissions/permission_manager.cc

Issue 1260193009: renderer: implement multiple permission requesting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@permissions-request-multiple
Patch Set: Rebase on top of other change Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/permissions/permission_manager.cc
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index e39955ab7c364015d180c9bb05e67b771d752814..7eb0dca4ed66e093481f15b2067987b6884c37db 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -73,12 +73,11 @@ ContentSettingsType PermissionTypeToContentSetting(PermissionType permission) {
return CONTENT_SETTINGS_TYPE_DEFAULT;
}
-// Helper method that wraps a callback a void(PermissionStatus)
-// callback into a void(ContentSetting) callback.
-void PermissionStatusCallbackWrapper(
+void PermissionRequestResponseCallbackWrapper(
const base::Callback<void(PermissionStatus)>& callback,
- ContentSetting content_setting) {
- callback.Run(ContentSettingToPermissionStatus(content_setting));
+ const std::vector<PermissionStatus>& vector) {
+ DCHECK(vector.size() == 1);
+ callback.Run(vector[0]);
}
// Returns whether the permission has a constant PermissionStatus value (i.e.
@@ -116,6 +115,22 @@ PermissionStatus GetPermissionStatusForConstantPermission(PermissionType type) {
} // anonymous namespace
+struct PermissionManager::PendingResponse {
+ PermissionType type;
+ PermissionStatus status;
+
+ PendingResponse(PermissionType type, PermissionStatus status)
+ : type(type), status(status) {
+ }
+};
+
+struct PermissionManager::PendingResponses {
+ GURL requesting_origin;
+ size_t count;
+ size_t pending;
+ std::vector<PendingResponse> responses;
+};
+
struct PermissionManager::Subscription {
PermissionType permission;
GURL requesting_origin;
@@ -125,7 +140,8 @@ struct PermissionManager::Subscription {
};
PermissionManager::PermissionManager(Profile* profile)
- : profile_(profile) {
+ : profile_(profile),
+ weak_ptr_factory_(this) {
}
PermissionManager::~PermissionManager() {
@@ -139,18 +155,34 @@ void PermissionManager::RequestPermission(
int request_id,
const GURL& requesting_origin,
bool user_gesture,
- const base::Callback<void(PermissionStatus)>& callback) {
- if (IsConstantPermission(permission)) {
- callback.Run(GetPermissionStatusForConstantPermission(permission));
- return;
- }
+ const RequestCallback& callback) {
+ RequestPermissionInternal(
+ std::vector<PermissionType>(1, permission),
+ render_frame_host,
+ request_id,
+ requesting_origin,
+ user_gesture,
+ base::Bind(&PermissionRequestResponseCallbackWrapper, callback));
+}
- PermissionContextBase* context = PermissionContext::Get(profile_, permission);
- if (!context) {
- callback.Run(content::PERMISSION_STATUS_DENIED);
- return;
- }
+void PermissionManager::RequestPermission(
+ const std::vector<PermissionType>& permissions,
+ content::RenderFrameHost* render_frame_host,
+ int request_id,
+ const GURL& requesting_origin,
+ bool user_gesture,
+ const BatchRequestCallback& callback) {
+ RequestPermissionInternal(permissions, render_frame_host, request_id,
+ requesting_origin, user_gesture, callback);
+}
+void PermissionManager::RequestPermissionInternal(
+ const std::vector<PermissionType>& permissions,
+ content::RenderFrameHost* render_frame_host,
+ int request_id,
+ const GURL& requesting_origin,
+ bool user_gesture,
+ const BatchRequestCallback& callback) {
int render_process_id = render_frame_host->GetProcess()->GetID();
int render_frame_id = render_frame_host->GetRoutingID();
const PermissionRequestID request(render_process_id,
@@ -158,31 +190,104 @@ void PermissionManager::RequestPermission(
request_id,
requesting_origin);
- context->RequestPermission(
- content::WebContents::FromRenderFrameHost(render_frame_host),
- request, requesting_origin, user_gesture,
- base::Bind(&PermissionStatusCallbackWrapper,
- callback));
+ // Pass complete control of the scoped pointer to the map.
+ // Locally we will use the raw pointer and the response will be removed from
+ // the map once all the responses return.
+ scoped_ptr<PendingResponses> scoped_response(new PendingResponses());
+ PendingResponses* pending_responses = scoped_response.get();
+ pending_responses_.add(request_id, scoped_response.Pass());
+
+ pending_responses->requesting_origin = requesting_origin;
+ pending_responses->count = permissions.size();
+ pending_responses->pending = permissions.size();
+
+ for (size_t i = 0; i < permissions.size(); ++i) {
+ pending_responses->responses.emplace_back(
+ permissions[i],
+ content::PERMISSION_STATUS_DENIED);
+ }
+
+ // The pending responses should all be added to the vector before running
+ // this loop so duplicate permissions are handled properly.
+ bool seen_types[static_cast<int>(PermissionType::NUM)] = { false };
+ for (size_t i = 0; i < permissions.size(); ++i) {
+ const PermissionType current_type = permissions[i];
+ const int current_type_index = static_cast<int>(current_type);
+ if (seen_types[current_type_index])
+ continue;
+ seen_types[current_type_index] = true;
+
+ if (IsConstantPermission(current_type)) {
+ OnRequestResponse(callback, request, pending_responses, i,
+ GetContentSettingForConstantPermission(current_type));
+ continue;
+ }
+
+ PermissionContextBase* context =
+ PermissionContext::Get(profile_, current_type);
+ if (!context) {
+ OnRequestResponse(callback, request, pending_responses, i,
+ CONTENT_SETTING_BLOCK);
+ continue;
+ }
+ context->RequestPermission(
+ content::WebContents::FromRenderFrameHost(render_frame_host),
+ request, requesting_origin, user_gesture,
+ base::Bind(&PermissionManager::OnRequestResponse,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ request,
+ pending_responses,
+ i));
+ }
+}
+
+void PermissionManager::OnRequestResponse(const BatchRequestCallback& callback,
+ const PermissionRequestID request,
+ PendingResponses* pending_responses,
+ int index,
+ ContentSetting content_setting) {
+ PendingResponse& response = pending_responses->responses[index];
+ response.status = ContentSettingToPermissionStatus(content_setting);
+
+ for (size_t i = index + 1; i < pending_responses->responses.size(); ++i) {
+ if (pending_responses->responses[i].type == response.type) {
+ pending_responses->responses[i].status = response.status;
+ --pending_responses->pending;
+ }
+ }
+
+ if (pending_responses->pending == 1) {
+ std::vector<PermissionStatus> status;
+ for (auto response : pending_responses->responses)
+ status.push_back(response.status);
+ pending_responses_.erase(request.request_id());
+ callback.Run(status);
+ }
}
void PermissionManager::CancelPermissionRequest(
- PermissionType permission,
content::RenderFrameHost* render_frame_host,
- int request_id,
- const GURL& requesting_origin) {
- PermissionContextBase* context = PermissionContext::Get(profile_, permission);
- if (!context)
- return;
+ int request_id) {
+ PendingResponses* pending_responses =
+ pending_responses_.get(request_id);
int render_process_id = render_frame_host->GetProcess()->GetID();
int render_frame_id = render_frame_host->GetRoutingID();
const PermissionRequestID request(render_process_id,
render_frame_id,
request_id,
- requesting_origin);
+ pending_responses->requesting_origin);
+
+ for (size_t i = 0; i < pending_responses->count; ++i) {
+ PermissionType type = pending_responses->responses[i].type;
+ PermissionContextBase* context = PermissionContext::Get(profile_, type);
+ if (!context) continue;
- context->CancelPermissionRequest(
- content::WebContents::FromRenderFrameHost(render_frame_host), request);
+ context->CancelPermissionRequest(
+ content::WebContents::FromRenderFrameHost(render_frame_host), request);
+ }
+ pending_responses_.erase(request_id);
}
void PermissionManager::ResetPermission(PermissionType permission,
@@ -230,7 +335,7 @@ int PermissionManager::SubscribePermissionStatusChange(
PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin,
- const base::Callback<void(PermissionStatus)>& callback) {
+ const RequestCallback& callback) {
if (subscriptions_.IsEmpty())
profile_->GetHostContentSettingsMap()->AddObserver(this);

Powered by Google App Engine
This is Rietveld 408576698