| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h" | 5 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" | 8 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" |
| 9 #include "chrome/common/chrome_switches.h" | 9 #include "chrome/common/chrome_switches.h" |
| 10 #include "content/public/browser/browser_thread.h" |
| 10 | 11 |
| 11 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionBubbleManager); | 12 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionBubbleManager); |
| 12 | 13 |
| 13 namespace { | |
| 14 | |
| 15 // This is how many ms to wait to see if there's another permission request | |
| 16 // we should coalesce. | |
| 17 const int kPermissionsCoalesceIntervalMs = 400; | |
| 18 | |
| 19 } | |
| 20 | |
| 21 // static | 14 // static |
| 22 bool PermissionBubbleManager::Enabled() { | 15 bool PermissionBubbleManager::Enabled() { |
| 23 return CommandLine::ForCurrentProcess()->HasSwitch( | 16 return CommandLine::ForCurrentProcess()->HasSwitch( |
| 24 switches::kEnablePermissionsBubbles); | 17 switches::kEnablePermissionsBubbles); |
| 25 } | 18 } |
| 26 | 19 |
| 27 PermissionBubbleManager::PermissionBubbleManager( | 20 PermissionBubbleManager::PermissionBubbleManager( |
| 28 content::WebContents* web_contents) | 21 content::WebContents* web_contents) |
| 29 : content::WebContentsObserver(web_contents), | 22 : content::WebContentsObserver(web_contents), |
| 30 bubble_showing_(false), | 23 bubble_showing_(false), |
| 31 view_(NULL), | 24 view_(NULL), |
| 32 customization_mode_(false) { | 25 request_url_has_loaded_(false), |
| 33 timer_.reset(new base::Timer(FROM_HERE, | 26 customization_mode_(false), |
| 34 base::TimeDelta::FromMilliseconds(kPermissionsCoalesceIntervalMs), | 27 weak_factory_(this) {} |
| 35 base::Bind(&PermissionBubbleManager::ShowBubble, base::Unretained(this)), | |
| 36 false)); | |
| 37 } | |
| 38 | 28 |
| 39 PermissionBubbleManager::~PermissionBubbleManager() { | 29 PermissionBubbleManager::~PermissionBubbleManager() { |
| 40 if (view_ != NULL) | 30 if (view_ != NULL) |
| 41 view_->SetDelegate(NULL); | 31 view_->SetDelegate(NULL); |
| 42 | 32 |
| 43 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 33 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 44 for (requests_iter = requests_.begin(); | 34 for (requests_iter = requests_.begin(); |
| 45 requests_iter != requests_.end(); | 35 requests_iter != requests_.end(); |
| 46 requests_iter++) { | 36 requests_iter++) { |
| 47 (*requests_iter)->RequestFinished(); | 37 (*requests_iter)->RequestFinished(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 | 80 |
| 91 if (bubble_showing_) { | 81 if (bubble_showing_) { |
| 92 queued_requests_.push_back(request); | 82 queued_requests_.push_back(request); |
| 93 return; | 83 return; |
| 94 } | 84 } |
| 95 | 85 |
| 96 requests_.push_back(request); | 86 requests_.push_back(request); |
| 97 // TODO(gbillock): do we need to make default state a request property? | 87 // TODO(gbillock): do we need to make default state a request property? |
| 98 accept_states_.push_back(true); | 88 accept_states_.push_back(true); |
| 99 | 89 |
| 100 // Start the timer when there is both a view and a request. | 90 if (request->HasUserGesture()) |
| 101 if (view_ && !timer_->IsRunning()) | 91 ShowBubble(); |
| 102 timer_->Reset(); | |
| 103 } | 92 } |
| 104 | 93 |
| 105 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) { | 94 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) { |
| 106 // TODO(gbillock): implement | 95 // TODO(gbillock): implement |
| 107 NOTREACHED(); | 96 NOTREACHED(); |
| 108 } | 97 } |
| 109 | 98 |
| 110 void PermissionBubbleManager::SetView(PermissionBubbleView* view) { | 99 void PermissionBubbleManager::SetView(PermissionBubbleView* view) { |
| 111 if (view == view_) | 100 if (view == view_) |
| 112 return; | 101 return; |
| 113 | 102 |
| 114 if (view_ != NULL) { | 103 if (view_ != NULL) { |
| 115 view_->SetDelegate(NULL); | 104 view_->SetDelegate(NULL); |
| 116 view_->Hide(); | 105 view_->Hide(); |
| 117 bubble_showing_ = false; | 106 bubble_showing_ = false; |
| 118 } | 107 } |
| 119 | 108 |
| 120 view_ = view; | 109 view_ = view; |
| 121 if (view_) | 110 if (view_) |
| 122 view_->SetDelegate(this); | 111 view_->SetDelegate(this); |
| 123 else | 112 else |
| 124 return; | 113 return; |
| 125 | 114 |
| 126 // Even if there are requests queued up, add a short delay before the bubble | 115 ShowBubble(); |
| 127 // appears. | |
| 128 if (!requests_.empty() && !timer_->IsRunning()) | |
| 129 timer_->Reset(); | |
| 130 else | |
| 131 view_->Hide(); | |
| 132 } | 116 } |
| 133 | 117 |
| 134 void PermissionBubbleManager::DidFinishLoad( | 118 void PermissionBubbleManager::DocumentOnLoadCompletedInMainFrame( |
| 135 int64 frame_id, | 119 int32 page_id) { |
| 136 const GURL& validated_url, | 120 request_url_has_loaded_ = true; |
| 137 bool is_main_frame, | 121 // This is scheduled because while all calls to the browser have been |
| 138 content::RenderViewHost* render_view_host) { | 122 // issued at DOMContentLoaded, they may be bouncing around in scheduled |
| 139 // Allows extra time for additional requests to coalesce. | 123 // callbacks finding the UI thread still. This makes sure we allow those |
| 140 if (timer_->IsRunning()) | 124 // scheduled calls to AddRequest to complete before we show the page-load |
| 141 timer_->Reset(); | 125 // permissions bubble. |
| 126 // TODO(gbillock): make this bind safe with a weak ptr. |
| 127 content::BrowserThread::PostTask( |
| 128 content::BrowserThread::UI, FROM_HERE, |
| 129 base::Bind(&PermissionBubbleManager::ShowBubble, |
| 130 weak_factory_.GetWeakPtr())); |
| 142 } | 131 } |
| 143 | 132 |
| 144 void PermissionBubbleManager::NavigationEntryCommitted( | 133 void PermissionBubbleManager::NavigationEntryCommitted( |
| 145 const content::LoadCommittedDetails& details) { | 134 const content::LoadCommittedDetails& details) { |
| 146 if (!request_url_.is_empty() && | 135 if (!request_url_.is_empty() && |
| 147 request_url_ != web_contents()->GetLastCommittedURL()) { | 136 request_url_ != web_contents()->GetLastCommittedURL()) { |
| 148 // Kill off existing bubble and cancel any pending requests. | 137 // Kill off existing bubble and cancel any pending requests. |
| 149 CancelPendingQueue(); | 138 CancelPendingQueue(); |
| 150 FinalizeBubble(); | 139 FinalizeBubble(); |
| 151 } | 140 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 205 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 194 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 206 for (requests_iter = requests_.begin(); | 195 for (requests_iter = requests_.begin(); |
| 207 requests_iter != requests_.end(); | 196 requests_iter != requests_.end(); |
| 208 requests_iter++) { | 197 requests_iter++) { |
| 209 (*requests_iter)->Cancelled(); | 198 (*requests_iter)->Cancelled(); |
| 210 } | 199 } |
| 211 FinalizeBubble(); | 200 FinalizeBubble(); |
| 212 } | 201 } |
| 213 | 202 |
| 214 void PermissionBubbleManager::ShowBubble() { | 203 void PermissionBubbleManager::ShowBubble() { |
| 215 if (view_ && !bubble_showing_ && requests_.size()) { | 204 if (view_ && !bubble_showing_ && request_url_has_loaded_ && |
| 205 requests_.size()) { |
| 216 // Note: this should appear above Show() for testing, since in that | 206 // Note: this should appear above Show() for testing, since in that |
| 217 // case we may do in-line calling of finalization. | 207 // case we may do in-line calling of finalization. |
| 218 bubble_showing_ = true; | 208 bubble_showing_ = true; |
| 219 view_->Show(requests_, accept_states_, customization_mode_); | 209 view_->Show(requests_, accept_states_, customization_mode_); |
| 220 } | 210 } |
| 221 } | 211 } |
| 222 | 212 |
| 223 void PermissionBubbleManager::FinalizeBubble() { | 213 void PermissionBubbleManager::FinalizeBubble() { |
| 224 if (view_) | 214 if (view_) |
| 225 view_->Hide(); | 215 view_->Hide(); |
| 226 bubble_showing_ = false; | 216 bubble_showing_ = false; |
| 227 | 217 |
| 228 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 218 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 229 for (requests_iter = requests_.begin(); | 219 for (requests_iter = requests_.begin(); |
| 230 requests_iter != requests_.end(); | 220 requests_iter != requests_.end(); |
| 231 requests_iter++) { | 221 requests_iter++) { |
| 232 (*requests_iter)->RequestFinished(); | 222 (*requests_iter)->RequestFinished(); |
| 233 } | 223 } |
| 234 requests_.clear(); | 224 requests_.clear(); |
| 235 accept_states_.clear(); | 225 accept_states_.clear(); |
| 236 if (queued_requests_.size()) { | 226 if (queued_requests_.size()) { |
| 237 requests_ = queued_requests_; | 227 requests_ = queued_requests_; |
| 238 accept_states_.resize(requests_.size(), true); | 228 accept_states_.resize(requests_.size(), true); |
| 239 queued_requests_.clear(); | 229 queued_requests_.clear(); |
| 240 // TODO(leng): Explore other options of showing the next bubble. The | 230 ShowBubble(); |
| 241 // advantage of this is that it uses the same code path as the first bubble. | |
| 242 timer_->Reset(); | |
| 243 } else { | 231 } else { |
| 244 request_url_ = GURL(); | 232 request_url_ = GURL(); |
| 245 } | 233 } |
| 246 } | 234 } |
| 247 | 235 |
| 248 void PermissionBubbleManager::CancelPendingQueue() { | 236 void PermissionBubbleManager::CancelPendingQueue() { |
| 249 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 237 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 250 for (requests_iter = queued_requests_.begin(); | 238 for (requests_iter = queued_requests_.begin(); |
| 251 requests_iter != queued_requests_.end(); | 239 requests_iter != queued_requests_.end(); |
| 252 requests_iter++) { | 240 requests_iter++) { |
| 253 (*requests_iter)->RequestFinished(); | 241 (*requests_iter)->RequestFinished(); |
| 254 } | 242 } |
| 255 } | 243 } |
| 256 | |
| 257 void PermissionBubbleManager::SetCoalesceIntervalForTesting(int interval_ms) { | |
| 258 timer_.reset(new base::Timer(FROM_HERE, | |
| 259 base::TimeDelta::FromMilliseconds(interval_ms), | |
| 260 base::Bind(&PermissionBubbleManager::ShowBubble, base::Unretained(this)), | |
| 261 false)); | |
| 262 } | |
| OLD | NEW |