[Eraser strings] Remove unused Supervised User infobar and corresponding strings
[chromium-blink-merge.git] / chrome / browser / ui / website_settings / permission_bubble_manager.cc
bloba2ace674da4eeb7e68fd9d0f0648eea5cbe140ae
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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
7 #include "base/command_line.h"
8 #include "base/metrics/user_metrics_action.h"
9 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_details.h"
13 #include "content/public/browser/user_metrics.h"
15 namespace {
17 class CancelledRequest : public PermissionBubbleRequest {
18 public:
19 explicit CancelledRequest(PermissionBubbleRequest* cancelled)
20 : icon_(cancelled->GetIconID()),
21 message_text_(cancelled->GetMessageText()),
22 message_fragment_(cancelled->GetMessageTextFragment()),
23 user_gesture_(cancelled->HasUserGesture()),
24 hostname_(cancelled->GetRequestingHostname()) {}
25 ~CancelledRequest() override {}
27 int GetIconID() const override { return icon_; }
28 base::string16 GetMessageText() const override { return message_text_; }
29 base::string16 GetMessageTextFragment() const override {
30 return message_fragment_;
32 bool HasUserGesture() const override { return user_gesture_; }
33 GURL GetRequestingHostname() const override { return hostname_; }
35 // These are all no-ops since the placeholder is non-forwarding.
36 void PermissionGranted() override {}
37 void PermissionDenied() override {}
38 void Cancelled() override {}
40 void RequestFinished() override { delete this; }
42 private:
43 int icon_;
44 base::string16 message_text_;
45 base::string16 message_fragment_;
46 bool user_gesture_;
47 GURL hostname_;
50 } // namespace
52 // PermissionBubbleManager::Observer -------------------------------------------
54 PermissionBubbleManager::Observer::~Observer() {
57 void PermissionBubbleManager::Observer::OnBubbleAdded() {
60 // PermissionBubbleManager -----------------------------------------------------
62 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionBubbleManager);
64 // static
65 bool PermissionBubbleManager::Enabled() {
66 #if defined(OS_ANDROID) || defined(OS_IOS)
67 return false;
68 #endif
69 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
70 switches::kDisablePermissionsBubbles))
71 return false;
72 return true;
75 PermissionBubbleManager::PermissionBubbleManager(
76 content::WebContents* web_contents)
77 : content::WebContentsObserver(web_contents),
78 require_user_gesture_(false),
79 #if !defined(OS_ANDROID) // No bubbles in android tests.
80 view_factory_(base::Bind(&PermissionBubbleView::Create)),
81 #endif
82 view_(nullptr),
83 main_frame_has_fully_loaded_(false),
84 auto_response_for_test_(NONE),
85 weak_factory_(this) {
88 PermissionBubbleManager::~PermissionBubbleManager() {
89 if (view_ != NULL)
90 view_->SetDelegate(NULL);
92 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
93 for (requests_iter = requests_.begin();
94 requests_iter != requests_.end();
95 requests_iter++) {
96 (*requests_iter)->RequestFinished();
98 for (requests_iter = queued_requests_.begin();
99 requests_iter != queued_requests_.end();
100 requests_iter++) {
101 (*requests_iter)->RequestFinished();
105 void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) {
106 content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
107 // TODO(gbillock): is there a race between an early request on a
108 // newly-navigated page and the to-be-cleaned-up requests on the previous
109 // page? We should maybe listen to DidStartNavigationToPendingEntry (and
110 // any other renderer-side nav initiations?). Double-check this for
111 // correct behavior on interstitials -- we probably want to basically queue
112 // any request for which GetVisibleURL != GetLastCommittedURL.
113 request_url_ = web_contents()->GetLastCommittedURL();
114 bool is_main_frame =
115 request->GetRequestingHostname().GetOrigin() == request_url_.GetOrigin();
117 // Don't re-add an existing request or one with a duplicate text request.
118 bool same_object = false;
119 if (ExistingRequest(request, requests_, &same_object) ||
120 ExistingRequest(request, queued_requests_, &same_object) ||
121 ExistingRequest(request, queued_frame_requests_, &same_object)) {
122 if (!same_object)
123 request->RequestFinished();
124 return;
127 if (IsBubbleVisible()) {
128 if (is_main_frame) {
129 content::RecordAction(
130 base::UserMetricsAction("PermissionBubbleRequestQueued"));
131 queued_requests_.push_back(request);
132 } else {
133 content::RecordAction(
134 base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
135 queued_frame_requests_.push_back(request);
137 return;
140 if (is_main_frame) {
141 requests_.push_back(request);
142 // TODO(gbillock): do we need to make default state a request property?
143 accept_states_.push_back(true);
144 } else {
145 content::RecordAction(
146 base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
147 queued_frame_requests_.push_back(request);
150 if (!require_user_gesture_ || request->HasUserGesture())
151 ScheduleShowBubble();
154 void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) {
155 // First look in the queued requests, where we can simply delete the request
156 // and go on.
157 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
158 for (requests_iter = queued_requests_.begin();
159 requests_iter != queued_requests_.end();
160 requests_iter++) {
161 if (*requests_iter == request) {
162 (*requests_iter)->RequestFinished();
163 queued_requests_.erase(requests_iter);
164 return;
168 std::vector<bool>::iterator accepts_iter = accept_states_.begin();
169 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
170 requests_iter != requests_.end();
171 requests_iter++, accepts_iter++) {
172 if (*requests_iter != request)
173 continue;
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.
177 bool can_erase = !IsBubbleVisible() || view_->CanAcceptRequestUpdate();
178 if (can_erase) {
179 (*requests_iter)->RequestFinished();
180 requests_.erase(requests_iter);
181 accept_states_.erase(accepts_iter);
183 if (IsBubbleVisible()) {
184 view_->Hide();
185 // Will redraw the bubble if it is being shown.
186 TriggerShowBubble();
188 return;
191 // Cancel the existing request and replace it with a dummy.
192 PermissionBubbleRequest* cancelled_request =
193 new CancelledRequest(*requests_iter);
194 (*requests_iter)->RequestFinished();
195 *requests_iter = cancelled_request;
196 return;
199 NOTREACHED(); // Callers should not cancel requests that are not pending.
202 void PermissionBubbleManager::HideBubble() {
203 // Disengage from the existing view if there is one.
204 if (!view_)
205 return;
207 view_->SetDelegate(nullptr);
208 view_->Hide();
209 view_.reset();
212 void PermissionBubbleManager::DisplayPendingRequests(Browser* browser) {
213 if (IsBubbleVisible())
214 return;
216 view_ = view_factory_.Run(browser);
217 view_->SetDelegate(this);
219 TriggerShowBubble();
222 void PermissionBubbleManager::UpdateAnchorPosition() {
223 if (view_)
224 view_->UpdateAnchorPosition();
227 bool PermissionBubbleManager::IsBubbleVisible() {
228 return view_ && view_->IsVisible();
231 gfx::NativeWindow PermissionBubbleManager::GetBubbleWindow() {
232 if (view_)
233 return view_->GetNativeWindow();
234 return nullptr;
237 void PermissionBubbleManager::RequireUserGesture(bool required) {
238 require_user_gesture_ = required;
241 void PermissionBubbleManager::DidNavigateMainFrame(
242 const content::LoadCommittedDetails& details,
243 const content::FrameNavigateParams& params) {
244 if (details.is_in_page)
245 return;
247 main_frame_has_fully_loaded_ = false;
250 void PermissionBubbleManager::DocumentOnLoadCompletedInMainFrame() {
251 main_frame_has_fully_loaded_ = true;
252 // This is scheduled because while all calls to the browser have been
253 // issued at DOMContentLoaded, they may be bouncing around in scheduled
254 // callbacks finding the UI thread still. This makes sure we allow those
255 // scheduled calls to AddRequest to complete before we show the page-load
256 // permissions bubble.
257 ScheduleShowBubble();
260 void PermissionBubbleManager::DocumentLoadedInFrame(
261 content::RenderFrameHost* render_frame_host) {
262 ScheduleShowBubble();
265 void PermissionBubbleManager::NavigationEntryCommitted(
266 const content::LoadCommittedDetails& details) {
267 // No permissions requests pending.
268 if (request_url_.is_empty())
269 return;
271 // If we have navigated to a new url or reloaded the page...
272 // GetAsReferrer strips fragment and username/password, meaning
273 // the navigation is really to the same page.
274 if ((request_url_.GetAsReferrer() !=
275 web_contents()->GetLastCommittedURL().GetAsReferrer()) ||
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();
280 FinalizeBubble();
284 void PermissionBubbleManager::WebContentsDestroyed() {
285 // If the web contents has been destroyed, treat the bubble as cancelled.
286 CancelPendingQueues();
287 FinalizeBubble();
289 // The WebContents is going away; be aggressively paranoid and delete
290 // ourselves lest other parts of the system attempt to add permission bubbles
291 // or use us otherwise during the destruction.
292 web_contents()->RemoveUserData(UserDataKey());
293 // That was the equivalent of "delete this". This object is now destroyed;
294 // returning from this function is the only safe thing to do.
297 void PermissionBubbleManager::ToggleAccept(int request_index, bool new_value) {
298 DCHECK(request_index < static_cast<int>(accept_states_.size()));
299 accept_states_[request_index] = new_value;
302 void PermissionBubbleManager::Accept() {
303 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
304 std::vector<bool>::iterator accepts_iter = accept_states_.begin();
305 for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
306 requests_iter != requests_.end();
307 requests_iter++, accepts_iter++) {
308 if (*accepts_iter)
309 (*requests_iter)->PermissionGranted();
310 else
311 (*requests_iter)->PermissionDenied();
313 FinalizeBubble();
316 void PermissionBubbleManager::Deny() {
317 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
318 for (requests_iter = requests_.begin();
319 requests_iter != requests_.end();
320 requests_iter++) {
321 (*requests_iter)->PermissionDenied();
323 FinalizeBubble();
326 void PermissionBubbleManager::Closing() {
327 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
328 for (requests_iter = requests_.begin();
329 requests_iter != requests_.end();
330 requests_iter++) {
331 (*requests_iter)->Cancelled();
333 FinalizeBubble();
336 void PermissionBubbleManager::ScheduleShowBubble() {
337 // ::ScheduleShowBubble() will be called again when the main frame will be
338 // loaded.
339 if (!main_frame_has_fully_loaded_)
340 return;
342 content::BrowserThread::PostTask(
343 content::BrowserThread::UI,
344 FROM_HERE,
345 base::Bind(&PermissionBubbleManager::TriggerShowBubble,
346 weak_factory_.GetWeakPtr()));
349 void PermissionBubbleManager::TriggerShowBubble() {
350 if (!view_)
351 return;
352 if (IsBubbleVisible())
353 return;
354 if (!main_frame_has_fully_loaded_)
355 return;
356 if (requests_.empty() && queued_requests_.empty() &&
357 queued_frame_requests_.empty()) {
358 return;
361 if (requests_.empty()) {
362 // Queues containing a user-gesture-generated request have priority.
363 if (HasUserGestureRequest(queued_requests_))
364 requests_.swap(queued_requests_);
365 else if (HasUserGestureRequest(queued_frame_requests_))
366 requests_.swap(queued_frame_requests_);
367 else if (queued_requests_.size())
368 requests_.swap(queued_requests_);
369 else
370 requests_.swap(queued_frame_requests_);
372 // Sets the default value for each request to be 'accept'.
373 // TODO(leng): Currently all requests default to true. If that changes:
374 // a) Add additional accept_state queues to store default values.
375 // b) Change the request API to provide the default value.
376 accept_states_.resize(requests_.size(), true);
379 view_->Show(requests_, accept_states_);
380 NotifyBubbleAdded();
382 // If in testing mode, automatically respond to the bubble that was shown.
383 if (auto_response_for_test_ != NONE)
384 DoAutoResponseForTesting();
387 void PermissionBubbleManager::FinalizeBubble() {
388 if (view_)
389 view_->Hide();
391 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
392 for (requests_iter = requests_.begin();
393 requests_iter != requests_.end();
394 requests_iter++) {
395 (*requests_iter)->RequestFinished();
397 requests_.clear();
398 accept_states_.clear();
399 if (queued_requests_.size() || queued_frame_requests_.size())
400 TriggerShowBubble();
401 else
402 request_url_ = GURL();
405 void PermissionBubbleManager::CancelPendingQueues() {
406 std::vector<PermissionBubbleRequest*>::iterator requests_iter;
407 for (requests_iter = queued_requests_.begin();
408 requests_iter != queued_requests_.end();
409 requests_iter++) {
410 (*requests_iter)->RequestFinished();
412 for (requests_iter = queued_frame_requests_.begin();
413 requests_iter != queued_frame_requests_.end();
414 requests_iter++) {
415 (*requests_iter)->RequestFinished();
417 queued_requests_.clear();
418 queued_frame_requests_.clear();
421 bool PermissionBubbleManager::ExistingRequest(
422 PermissionBubbleRequest* request,
423 const std::vector<PermissionBubbleRequest*>& queue,
424 bool* same_object) {
425 CHECK(same_object);
426 *same_object = false;
427 std::vector<PermissionBubbleRequest*>::const_iterator iter;
428 for (iter = queue.begin(); iter != queue.end(); iter++) {
429 if (*iter == request) {
430 *same_object = true;
431 return true;
433 if ((*iter)->GetMessageTextFragment() ==
434 request->GetMessageTextFragment() &&
435 (*iter)->GetRequestingHostname() == request->GetRequestingHostname()) {
436 return true;
439 return false;
442 bool PermissionBubbleManager::HasUserGestureRequest(
443 const std::vector<PermissionBubbleRequest*>& queue) {
444 std::vector<PermissionBubbleRequest*>::const_iterator iter;
445 for (iter = queue.begin(); iter != queue.end(); iter++) {
446 if ((*iter)->HasUserGesture())
447 return true;
449 return false;
452 void PermissionBubbleManager::AddObserver(Observer* observer) {
453 observer_list_.AddObserver(observer);
456 void PermissionBubbleManager::RemoveObserver(Observer* observer) {
457 observer_list_.RemoveObserver(observer);
460 void PermissionBubbleManager::NotifyBubbleAdded() {
461 FOR_EACH_OBSERVER(Observer, observer_list_, OnBubbleAdded());
464 void PermissionBubbleManager::DoAutoResponseForTesting() {
465 switch (auto_response_for_test_) {
466 case ACCEPT_ALL:
467 Accept();
468 break;
469 case DENY_ALL:
470 Deny();
471 break;
472 case DISMISS:
473 Closing();
474 break;
475 case NONE:
476 NOTREACHED();