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