Index: chrome/browser/ui/website_settings/permission_bubble_manager.cc |
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager.cc b/chrome/browser/ui/website_settings/permission_bubble_manager.cc |
index cb3df39d6b39ba73206ca70d492a2a430354a009..990d124df440414409cc28736b54a2edc59db926 100644 |
--- a/chrome/browser/ui/website_settings/permission_bubble_manager.cc |
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager.cc |
@@ -10,6 +10,14 @@ |
DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionBubbleManager); |
+namespace { |
+ |
+// This is how many ms to wait to see if there's another permission request |
+// we should coalesce. |
+const int kPermissionsCoalesceIntervalMs = 400; |
+ |
+} |
+ |
// static |
bool PermissionBubbleManager::Enabled() { |
return CommandLine::ForCurrentProcess()->HasSwitch( |
@@ -18,24 +26,32 @@ bool PermissionBubbleManager::Enabled() { |
void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) { |
// Don't re-add an existing request. |
- std::vector<PermissionBubbleRequest*>::iterator di; |
- for (di = requests_.begin(); di != requests_.end(); di++) { |
- if (*di == request) |
+ std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
+ for (requests_iter = requests_.begin(); |
+ requests_iter != requests_.end(); |
+ requests_iter++) { |
+ if (*requests_iter == request) |
return; |
} |
+ if (bubble_showing_) { |
+ for (requests_iter = queued_requests_.begin(); |
+ requests_iter != queued_requests_.end(); |
+ requests_iter++) { |
+ if (*requests_iter == request) |
+ return; |
+ } |
+ queued_requests_.push_back(request); |
+ return; |
+ } |
+ |
requests_.push_back(request); |
// TODO(gbillock): do we need to make default state a request property? |
- accept_state_.push_back(true); |
+ accept_states_.push_back(true); |
- // TODO(gbillock): need significantly more complex logic here to deal |
- // with various states of the manager. |
- |
- if (view_ && !bubble_showing_) { |
- view_->SetDelegate(this); |
- view_->Show(requests_, accept_state_, customization_mode_); |
- bubble_showing_ = true; |
- } |
+ // Start the timer when there is both a view and a request. |
+ if (view_ && !timer_->IsRunning()) |
+ timer_->Reset(); |
} |
void PermissionBubbleManager::SetView(PermissionBubbleView* view) { |
@@ -45,6 +61,7 @@ void PermissionBubbleManager::SetView(PermissionBubbleView* view) { |
if (view_ != NULL) { |
view_->SetDelegate(NULL); |
view_->Hide(); |
+ bubble_showing_ = false; |
} |
view_ = view; |
@@ -53,11 +70,10 @@ void PermissionBubbleManager::SetView(PermissionBubbleView* view) { |
else |
return; |
- if (!requests_.empty()) |
- bubble_showing_ = true; |
- |
- if (bubble_showing_) |
- view_->Show(requests_, accept_state_, customization_mode_); |
+ // Even if there are requests queued up, add a short delay before the bubble |
+ // appears. |
+ if (!requests_.empty() && !timer_->IsRunning()) |
+ timer_->Reset(); |
else |
view_->Hide(); |
} |
@@ -68,10 +84,24 @@ PermissionBubbleManager::PermissionBubbleManager( |
bubble_showing_(false), |
view_(NULL), |
customization_mode_(false) { |
+ timer_.reset(new base::Timer(FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(kPermissionsCoalesceIntervalMs), |
+ base::Bind(&PermissionBubbleManager::ShowBubble, base::Unretained(this)), |
+ false)); |
} |
PermissionBubbleManager::~PermissionBubbleManager() {} |
+void PermissionBubbleManager::DidFinishLoad( |
+ int64 frame_id, |
+ const GURL& validated_url, |
+ bool is_main_frame, |
+ content::RenderViewHost* render_view_host) { |
+ // Allows extra time for additional requests to coalesce. |
+ if (timer_->IsRunning()) |
+ timer_->Reset(); |
+} |
+ |
void PermissionBubbleManager::WebContentsDestroyed( |
content::WebContents* web_contents) { |
// Synthetic cancel event if the user closes the WebContents. |
@@ -86,53 +116,86 @@ void PermissionBubbleManager::WebContentsDestroyed( |
} |
void PermissionBubbleManager::ToggleAccept(int request_index, bool new_value) { |
- DCHECK(request_index < static_cast<int>(accept_state_.size())); |
- accept_state_[request_index] = new_value; |
+ DCHECK(request_index < static_cast<int>(accept_states_.size())); |
+ accept_states_[request_index] = new_value; |
} |
void PermissionBubbleManager::SetCustomizationMode() { |
customization_mode_ = true; |
if (view_) |
- view_->Show(requests_, accept_state_, customization_mode_); |
+ view_->Show(requests_, accept_states_, customization_mode_); |
} |
void PermissionBubbleManager::Accept() { |
- std::vector<PermissionBubbleRequest*>::iterator di; |
- std::vector<bool>::iterator ai; |
- for (di = requests_.begin(), ai = accept_state_.begin(); |
- di != requests_.end(); di++, ai++) { |
- if (*ai) |
- (*di)->PermissionGranted(); |
+ std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
+ std::vector<bool>::iterator accepts_iter = accept_states_.begin(); |
+ for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin(); |
+ requests_iter != requests_.end(); |
+ requests_iter++, accepts_iter++) { |
+ if (*accepts_iter) |
+ (*requests_iter)->PermissionGranted(); |
else |
- (*di)->PermissionDenied(); |
+ (*requests_iter)->PermissionDenied(); |
} |
FinalizeBubble(); |
} |
void PermissionBubbleManager::Deny() { |
- std::vector<PermissionBubbleRequest*>::iterator di; |
- for (di = requests_.begin(); di != requests_.end(); di++) |
- (*di)->PermissionDenied(); |
+ std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
+ for (requests_iter = requests_.begin(); |
+ requests_iter != requests_.end(); |
+ requests_iter++) { |
+ (*requests_iter)->PermissionDenied(); |
+ } |
FinalizeBubble(); |
} |
void PermissionBubbleManager::Closing() { |
- std::vector<PermissionBubbleRequest*>::iterator di; |
- for (di = requests_.begin(); di != requests_.end(); di++) |
- (*di)->Cancelled(); |
+ std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
+ for (requests_iter = requests_.begin(); |
+ requests_iter != requests_.end(); |
+ requests_iter++) { |
+ (*requests_iter)->Cancelled(); |
+ } |
FinalizeBubble(); |
} |
+void PermissionBubbleManager::ShowBubble() { |
+ if (view_ && !bubble_showing_ && requests_.size()) { |
+ view_->SetDelegate(this); |
+ view_->Show(requests_, accept_states_, customization_mode_); |
+ bubble_showing_ = true; |
+ } |
+} |
+ |
void PermissionBubbleManager::FinalizeBubble() { |
if (view_) { |
view_->SetDelegate(NULL); |
view_->Hide(); |
} |
- std::vector<PermissionBubbleRequest*>::iterator di; |
- for (di = requests_.begin(); di != requests_.end(); di++) |
- (*di)->RequestFinished(); |
+ std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
+ for (requests_iter = requests_.begin(); |
+ requests_iter != requests_.end(); |
+ requests_iter++) { |
+ (*requests_iter)->RequestFinished(); |
+ } |
requests_.clear(); |
- accept_state_.clear(); |
+ accept_states_.clear(); |
+ bubble_showing_ = false; |
+ if (queued_requests_.size()) { |
+ requests_ = queued_requests_; |
+ accept_states_.resize(requests_.size(), true); |
+ queued_requests_.clear(); |
+ // TODO(leng): Explore other options of showing the next bubble. The |
+ // advantage of this is that it uses the same code path as the first bubble. |
+ timer_->Reset(); |
+ } |
} |
+void PermissionBubbleManager::SetCoalesceIntervalForTesting(int interval_ms) { |
+ timer_.reset(new base::Timer(FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(interval_ms), |
+ base::Bind(&PermissionBubbleManager::ShowBubble, base::Unretained(this)), |
+ false)); |
+} |