| 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 "base/metrics/user_metrics_action.h" | 8 #include "base/metrics/user_metrics_action.h" |
| 9 #include "chrome/browser/ui/browser.h" |
| 10 #include "chrome/browser/ui/website_settings/permission_bubble_delegate.h" |
| 9 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" | 11 #include "chrome/browser/ui/website_settings/permission_bubble_request.h" |
| 10 #include "chrome/common/chrome_switches.h" | 12 #include "chrome/common/chrome_switches.h" |
| 11 #include "content/public/browser/browser_thread.h" | 13 #include "content/public/browser/browser_thread.h" |
| 12 #include "content/public/browser/navigation_details.h" | 14 #include "content/public/browser/navigation_details.h" |
| 13 #include "content/public/browser/user_metrics.h" | 15 #include "content/public/browser/user_metrics.h" |
| 14 | 16 |
| 15 namespace { | 17 namespace { |
| 16 | 18 |
| 17 class CancelledRequest : public PermissionBubbleRequest { | 19 class CancelledRequest : public PermissionBubbleRequest { |
| 18 public: | 20 public: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 return true; | 74 return true; |
| 73 } | 75 } |
| 74 | 76 |
| 75 PermissionBubbleManager::PermissionBubbleManager( | 77 PermissionBubbleManager::PermissionBubbleManager( |
| 76 content::WebContents* web_contents) | 78 content::WebContents* web_contents) |
| 77 : content::WebContentsObserver(web_contents), | 79 : content::WebContentsObserver(web_contents), |
| 78 require_user_gesture_(false), | 80 require_user_gesture_(false), |
| 79 #if !defined(OS_ANDROID) // No bubbles in android tests. | 81 #if !defined(OS_ANDROID) // No bubbles in android tests. |
| 80 view_factory_(base::Bind(&PermissionBubbleView::Create)), | 82 view_factory_(base::Bind(&PermissionBubbleView::Create)), |
| 81 #endif | 83 #endif |
| 82 view_(nullptr), | |
| 83 main_frame_has_fully_loaded_(false), | 84 main_frame_has_fully_loaded_(false), |
| 84 auto_response_for_test_(NONE), | 85 auto_response_for_test_(NONE), |
| 85 weak_factory_(this) { | 86 weak_factory_(this) { |
| 86 } | 87 } |
| 87 | 88 |
| 88 PermissionBubbleManager::~PermissionBubbleManager() { | 89 PermissionBubbleManager::~PermissionBubbleManager() { |
| 89 if (view_ != NULL) | 90 HideBubble(); |
| 90 view_->SetDelegate(NULL); | |
| 91 | 91 |
| 92 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 92 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 93 for (requests_iter = requests_.begin(); | 93 for (requests_iter = requests_.begin(); |
| 94 requests_iter != requests_.end(); | 94 requests_iter != requests_.end(); |
| 95 requests_iter++) { | 95 requests_iter++) { |
| 96 (*requests_iter)->RequestFinished(); | 96 (*requests_iter)->RequestFinished(); |
| 97 } | 97 } |
| 98 for (requests_iter = queued_requests_.begin(); | 98 for (requests_iter = queued_requests_.begin(); |
| 99 requests_iter != queued_requests_.end(); | 99 requests_iter != queued_requests_.end(); |
| 100 requests_iter++) { | 100 requests_iter++) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 167 | 167 |
| 168 std::vector<bool>::iterator accepts_iter = accept_states_.begin(); | 168 std::vector<bool>::iterator accepts_iter = accept_states_.begin(); |
| 169 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin(); | 169 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin(); |
| 170 requests_iter != requests_.end(); | 170 requests_iter != requests_.end(); |
| 171 requests_iter++, accepts_iter++) { | 171 requests_iter++, accepts_iter++) { |
| 172 if (*requests_iter != request) | 172 if (*requests_iter != request) |
| 173 continue; | 173 continue; |
| 174 | 174 |
| 175 // We can simply erase the current entry in the request table if we aren't | 175 // We can simply erase the current entry in the request table if we aren't |
| 176 // showing the dialog, or if we are showing it and it can accept the update. | 176 // showing the dialog, or if we are showing it and it can accept the update. |
| 177 bool can_erase = !IsBubbleVisible() || view_->CanAcceptRequestUpdate(); | 177 bool can_erase = !IsBubbleVisible(); |
| 178 |
| 179 // TODO(hcarmona): Don't forget this logic. Maybe improve it? Or remove it? |
| 180 // bool can_erase = !IsBubbleVisible() || view_->CanAcceptRequestUpdate(); |
| 181 |
| 178 if (can_erase) { | 182 if (can_erase) { |
| 179 (*requests_iter)->RequestFinished(); | 183 (*requests_iter)->RequestFinished(); |
| 180 requests_.erase(requests_iter); | 184 requests_.erase(requests_iter); |
| 181 accept_states_.erase(accepts_iter); | 185 accept_states_.erase(accepts_iter); |
| 182 | 186 |
| 183 if (IsBubbleVisible()) { | 187 if (IsBubbleVisible()) { |
| 184 view_->Hide(); | 188 HideBubble(); |
| 185 // Will redraw the bubble if it is being shown. | 189 // Will redraw the bubble if it is being shown. |
| 186 TriggerShowBubble(); | 190 TriggerShowBubble(); |
| 187 } | 191 } |
| 188 return; | 192 return; |
| 189 } | 193 } |
| 190 | 194 |
| 191 // Cancel the existing request and replace it with a dummy. | 195 // Cancel the existing request and replace it with a dummy. |
| 192 PermissionBubbleRequest* cancelled_request = | 196 PermissionBubbleRequest* cancelled_request = |
| 193 new CancelledRequest(*requests_iter); | 197 new CancelledRequest(*requests_iter); |
| 194 (*requests_iter)->RequestFinished(); | 198 (*requests_iter)->RequestFinished(); |
| 195 *requests_iter = cancelled_request; | 199 *requests_iter = cancelled_request; |
| 196 return; | 200 return; |
| 197 } | 201 } |
| 198 | 202 |
| 199 NOTREACHED(); // Callers should not cancel requests that are not pending. | 203 NOTREACHED(); // Callers should not cancel requests that are not pending. |
| 200 } | 204 } |
| 201 | 205 |
| 202 void PermissionBubbleManager::HideBubble() { | 206 void PermissionBubbleManager::HideBubble() { |
| 203 // Disengage from the existing view if there is one. | 207 if (!active_bubble_) |
| 204 if (!view_) | |
| 205 return; | 208 return; |
| 206 | 209 browser_->bubble_manager()->HideBubble(active_bubble_); |
| 207 view_->SetDelegate(nullptr); | |
| 208 view_->Hide(); | |
| 209 view_.reset(); | |
| 210 } | 210 } |
| 211 | 211 |
| 212 void PermissionBubbleManager::DisplayPendingRequests(Browser* browser) { | 212 void PermissionBubbleManager::DisplayPendingRequests() { |
| 213 if (IsBubbleVisible()) | 213 if (IsBubbleVisible()) |
| 214 return; | 214 return; |
| 215 | 215 |
| 216 view_ = view_factory_.Run(browser); | |
| 217 view_->SetDelegate(this); | |
| 218 | |
| 219 TriggerShowBubble(); | 216 TriggerShowBubble(); |
| 220 } | 217 } |
| 221 | 218 |
| 222 void PermissionBubbleManager::UpdateAnchorPosition() { | |
| 223 if (view_) | |
| 224 view_->UpdateAnchorPosition(); | |
| 225 } | |
| 226 | |
| 227 bool PermissionBubbleManager::IsBubbleVisible() { | 219 bool PermissionBubbleManager::IsBubbleVisible() { |
| 228 return view_ && view_->IsVisible(); | 220 // TODO(hcarmona): anything else for "visible check"? |
| 229 } | 221 return active_bubble_; |
| 230 | |
| 231 gfx::NativeWindow PermissionBubbleManager::GetBubbleWindow() { | |
| 232 if (view_) | |
| 233 return view_->GetNativeWindow(); | |
| 234 return nullptr; | |
| 235 } | 222 } |
| 236 | 223 |
| 237 void PermissionBubbleManager::RequireUserGesture(bool required) { | 224 void PermissionBubbleManager::RequireUserGesture(bool required) { |
| 238 require_user_gesture_ = required; | 225 require_user_gesture_ = required; |
| 239 } | 226 } |
| 240 | 227 |
| 241 void PermissionBubbleManager::DidNavigateMainFrame( | 228 void PermissionBubbleManager::DidNavigateMainFrame( |
| 242 const content::LoadCommittedDetails& details, | 229 const content::LoadCommittedDetails& details, |
| 243 const content::FrameNavigateParams& params) { | 230 const content::FrameNavigateParams& params) { |
| 244 if (details.is_in_page) | 231 if (details.is_in_page) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 262 ScheduleShowBubble(); | 249 ScheduleShowBubble(); |
| 263 } | 250 } |
| 264 | 251 |
| 265 void PermissionBubbleManager::NavigationEntryCommitted( | 252 void PermissionBubbleManager::NavigationEntryCommitted( |
| 266 const content::LoadCommittedDetails& details) { | 253 const content::LoadCommittedDetails& details) { |
| 267 // No permissions requests pending. | 254 // No permissions requests pending. |
| 268 if (request_url_.is_empty()) | 255 if (request_url_.is_empty()) |
| 269 return; | 256 return; |
| 270 | 257 |
| 271 // If we have navigated to a new url or reloaded the page... | 258 // If we have navigated to a new url or reloaded the page... |
| 272 // GetAsReferrer strips fragment and username/password, meaning | 259 if (!details.is_in_page || |
| 273 // the navigation is really to the same page. | 260 details.type == content::NAVIGATION_TYPE_SAME_PAGE || |
| 274 if ((request_url_.GetAsReferrer() != | 261 details.type == content::NAVIGATION_TYPE_EXISTING_PAGE) { |
| 275 web_contents()->GetLastCommittedURL().GetAsReferrer()) || | 262 // kill off existing bubble and cancel any pending requests. |
| 276 (details.type == content::NAVIGATION_TYPE_EXISTING_PAGE && | |
| 277 !details.is_in_page)) { | |
| 278 // Kill off existing bubble and cancel any pending requests. | |
| 279 CancelPendingQueues(); | 263 CancelPendingQueues(); |
| 280 FinalizeBubble(); | 264 FinalizeBubble(); |
| 281 } | 265 } |
| 282 } | 266 } |
| 283 | 267 |
| 284 void PermissionBubbleManager::WebContentsDestroyed() { | 268 void PermissionBubbleManager::WebContentsDestroyed() { |
| 285 // If the web contents has been destroyed, treat the bubble as cancelled. | 269 // If the web contents has been destroyed, treat the bubble as cancelled. |
| 286 CancelPendingQueues(); | 270 CancelPendingQueues(); |
| 287 FinalizeBubble(); | 271 FinalizeBubble(); |
| 288 | 272 |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 return; | 324 return; |
| 341 | 325 |
| 342 content::BrowserThread::PostTask( | 326 content::BrowserThread::PostTask( |
| 343 content::BrowserThread::UI, | 327 content::BrowserThread::UI, |
| 344 FROM_HERE, | 328 FROM_HERE, |
| 345 base::Bind(&PermissionBubbleManager::TriggerShowBubble, | 329 base::Bind(&PermissionBubbleManager::TriggerShowBubble, |
| 346 weak_factory_.GetWeakPtr())); | 330 weak_factory_.GetWeakPtr())); |
| 347 } | 331 } |
| 348 | 332 |
| 349 void PermissionBubbleManager::TriggerShowBubble() { | 333 void PermissionBubbleManager::TriggerShowBubble() { |
| 350 if (!view_) | |
| 351 return; | |
| 352 if (IsBubbleVisible()) | 334 if (IsBubbleVisible()) |
| 353 return; | 335 return; |
| 354 if (!main_frame_has_fully_loaded_) | 336 if (!main_frame_has_fully_loaded_) |
| 355 return; | 337 return; |
| 356 if (requests_.empty() && queued_requests_.empty() && | 338 if (requests_.empty() && queued_requests_.empty() && |
| 357 queued_frame_requests_.empty()) { | 339 queued_frame_requests_.empty()) { |
| 358 return; | 340 return; |
| 359 } | 341 } |
| 360 | 342 |
| 361 if (requests_.empty()) { | 343 if (requests_.empty()) { |
| 362 // Queues containing a user-gesture-generated request have priority. | 344 // Queues containing a user-gesture-generated request have priority. |
| 363 if (HasUserGestureRequest(queued_requests_)) | 345 if (HasUserGestureRequest(queued_requests_)) |
| 364 requests_.swap(queued_requests_); | 346 requests_.swap(queued_requests_); |
| 365 else if (HasUserGestureRequest(queued_frame_requests_)) | 347 else if (HasUserGestureRequest(queued_frame_requests_)) |
| 366 requests_.swap(queued_frame_requests_); | 348 requests_.swap(queued_frame_requests_); |
| 367 else if (queued_requests_.size()) | 349 else if (queued_requests_.size()) |
| 368 requests_.swap(queued_requests_); | 350 requests_.swap(queued_requests_); |
| 369 else | 351 else |
| 370 requests_.swap(queued_frame_requests_); | 352 requests_.swap(queued_frame_requests_); |
| 371 | 353 |
| 372 // Sets the default value for each request to be 'accept'. | 354 // Sets the default value for each request to be 'accept'. |
| 373 // TODO(leng): Currently all requests default to true. If that changes: | 355 // TODO(leng): Currently all requests default to true. If that changes: |
| 374 // a) Add additional accept_state queues to store default values. | 356 // a) Add additional accept_state queues to store default values. |
| 375 // b) Change the request API to provide the default value. | 357 // b) Change the request API to provide the default value. |
| 376 accept_states_.resize(requests_.size(), true); | 358 accept_states_.resize(requests_.size(), true); |
| 377 } | 359 } |
| 378 | 360 |
| 379 view_->Show(requests_, accept_states_); | 361 active_bubble_ = browser_->bubble_manager()->ShowBubble( |
| 362 make_scoped_ptr(new PermissionBubbleDelegate(this, view_factory_))); |
| 363 |
| 380 NotifyBubbleAdded(); | 364 NotifyBubbleAdded(); |
| 381 | 365 |
| 382 // If in testing mode, automatically respond to the bubble that was shown. | 366 // If in testing mode, automatically respond to the bubble that was shown. |
| 383 if (auto_response_for_test_ != NONE) | 367 if (auto_response_for_test_ != NONE) |
| 384 DoAutoResponseForTesting(); | 368 DoAutoResponseForTesting(); |
| 385 } | 369 } |
| 386 | 370 |
| 387 void PermissionBubbleManager::FinalizeBubble() { | 371 void PermissionBubbleManager::FinalizeBubble() { |
| 388 if (view_) | 372 HideBubble(); |
| 389 view_->Hide(); | |
| 390 | 373 |
| 391 std::vector<PermissionBubbleRequest*>::iterator requests_iter; | 374 std::vector<PermissionBubbleRequest*>::iterator requests_iter; |
| 392 for (requests_iter = requests_.begin(); | 375 for (requests_iter = requests_.begin(); |
| 393 requests_iter != requests_.end(); | 376 requests_iter != requests_.end(); |
| 394 requests_iter++) { | 377 requests_iter++) { |
| 395 (*requests_iter)->RequestFinished(); | 378 (*requests_iter)->RequestFinished(); |
| 396 } | 379 } |
| 397 requests_.clear(); | 380 requests_.clear(); |
| 398 accept_states_.clear(); | 381 accept_states_.clear(); |
| 399 if (queued_requests_.size() || queued_frame_requests_.size()) | 382 if (queued_requests_.size() || queued_frame_requests_.size()) |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 case DENY_ALL: | 452 case DENY_ALL: |
| 470 Deny(); | 453 Deny(); |
| 471 break; | 454 break; |
| 472 case DISMISS: | 455 case DISMISS: |
| 473 Closing(); | 456 Closing(); |
| 474 break; | 457 break; |
| 475 case NONE: | 458 case NONE: |
| 476 NOTREACHED(); | 459 NOTREACHED(); |
| 477 } | 460 } |
| 478 } | 461 } |
| OLD | NEW |