15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/command_line.h"
8010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/metrics/user_metrics_action.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/website_settings/permission_bubble_request.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/public/browser/browser_thread.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_details.h"
13010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
14010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)namespace {
16010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
17010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class CancelledRequest : public PermissionBubbleRequest {
18010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
19010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  explicit CancelledRequest(PermissionBubbleRequest* cancelled)
20010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      : icon_(cancelled->GetIconID()),
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        message_text_(cancelled->GetMessageText()),
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        message_fragment_(cancelled->GetMessageTextFragment()),
23010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        user_gesture_(cancelled->HasUserGesture()),
24010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        hostname_(cancelled->GetRequestingHostname()) {}
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual ~CancelledRequest() {}
26010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual int GetIconID() const OVERRIDE {
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return icon_;
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
30010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual base::string16 GetMessageText() const OVERRIDE {
31010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return message_text_;
32010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
33010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual base::string16 GetMessageTextFragment() const OVERRIDE {
34010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return message_fragment_;
35010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
36010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual bool HasUserGesture() const OVERRIDE {
37010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return user_gesture_;
38010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
39010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual GURL GetRequestingHostname() const OVERRIDE {
40010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return hostname_;
41010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
42010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
43010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // These are all no-ops since the placeholder is non-forwarding.
44010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void PermissionGranted() OVERRIDE {}
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void PermissionDenied() OVERRIDE {}
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void Cancelled() OVERRIDE {}
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void RequestFinished() OVERRIDE {
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    delete this;
50010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
51010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
52010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) private:
53010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  int icon_;
54010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::string16 message_text_;
55010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::string16 message_fragment_;
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool user_gesture_;
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  GURL hostname_;
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DEFINE_WEB_CONTENTS_USER_DATA_KEY(PermissionBubbleManager);
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool PermissionBubbleManager::Enabled() {
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          switches::kEnablePermissionsBubbles))
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return true;
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (CommandLine::ForCurrentProcess()->HasSwitch(
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          switches::kDisablePermissionsBubbles))
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return false;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PermissionBubbleManager::PermissionBubbleManager(
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content::WebContents* web_contents)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  : content::WebContentsObserver(web_contents),
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bubble_showing_(false),
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    view_(NULL),
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    request_url_has_loaded_(false),
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    customization_mode_(false),
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    weak_factory_(this) {}
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PermissionBubbleManager::~PermissionBubbleManager() {
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (view_ != NULL)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    view_->SetDelegate(NULL);
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (requests_iter = requests_.begin();
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       requests_iter != requests_.end();
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       requests_iter++) {
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    (*requests_iter)->RequestFinished();
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (requests_iter = queued_requests_.begin();
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       requests_iter != queued_requests_.end();
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       requests_iter++) {
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    (*requests_iter)->RequestFinished();
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::AddRequest(PermissionBubbleRequest* request) {
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  content::RecordAction(base::UserMetricsAction("PermissionBubbleRequest"));
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(gbillock): is there a race between an early request on a
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // newly-navigated page and the to-be-cleaned-up requests on the previous
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // page? We should maybe listen to DidStartNavigationToPendingEntry (and
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // any other renderer-side nav initiations?). Double-check this for
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // correct behavior on interstitials -- we probably want to basically queue
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // any request for which GetVisibleURL != GetLastCommittedURL.
1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  request_url_ = web_contents()->GetLastCommittedURL();
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool is_main_frame =
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      request->GetRequestingHostname().GetOrigin() == request_url_.GetOrigin();
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Don't re-add an existing request or one with a duplicate text request.
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool same_object = false;
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (ExistingRequest(request, requests_, &same_object) ||
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExistingRequest(request, queued_requests_, &same_object) ||
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExistingRequest(request, queued_frame_requests_, &same_object)) {
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!same_object)
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      request->RequestFinished();
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (bubble_showing_) {
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (is_main_frame) {
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      content::RecordAction(
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::UserMetricsAction("PermissionBubbleRequestQueued"));
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      queued_requests_.push_back(request);
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else {
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      content::RecordAction(
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      queued_frame_requests_.push_back(request);
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (is_main_frame) {
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    requests_.push_back(request);
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(gbillock): do we need to make default state a request property?
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    accept_states_.push_back(true);
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::RecordAction(
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        base::UserMetricsAction("PermissionBubbleIFrameRequestQueued"));
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    queued_frame_requests_.push_back(request);
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (request->HasUserGesture())
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ScheduleShowBubble();
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PermissionBubbleManager::CancelRequest(PermissionBubbleRequest* request) {
153010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // First look in the queued requests, where we can simply delete the request
154010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // and go on.
155010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
156010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (requests_iter = queued_requests_.begin();
157010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       requests_iter != queued_requests_.end();
158010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       requests_iter++) {
159010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (*requests_iter == request) {
160010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      (*requests_iter)->RequestFinished();
161010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      queued_requests_.erase(requests_iter);
162010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return;
163010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
164010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
165010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
166010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<bool>::iterator accepts_iter = accept_states_.begin();
167010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       requests_iter != requests_.end();
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)       requests_iter++, accepts_iter++) {
170010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (*requests_iter != request)
171010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      continue;
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // We can simply erase the current entry in the request table if we aren't
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // showing the dialog, or if we are showing it and it can accept the update.
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    bool can_erase = !bubble_showing_ ||
176010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                     !view_ || view_->CanAcceptRequestUpdate();
177010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    if (can_erase) {
178010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      (*requests_iter)->RequestFinished();
179010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      requests_.erase(requests_iter);
180010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      accept_states_.erase(accepts_iter);
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      TriggerShowBubble();  // Will redraw the bubble if it is being shown.
182010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      return;
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    }
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Cancel the existing request and replace it with a dummy.
186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    PermissionBubbleRequest* cancelled_request =
187010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        new CancelledRequest(*requests_iter);
188010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    (*requests_iter)->RequestFinished();
189010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    *requests_iter = cancelled_request;
190010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
191010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
192010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
193010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  NOTREACHED();  // Callers should not cancel requests that are not pending.
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::SetView(PermissionBubbleView* view) {
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (view == view_)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
200010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Disengage from the existing view if there is one.
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (view_ != NULL) {
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    view_->SetDelegate(NULL);
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    view_->Hide();
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bubble_showing_ = false;
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  view_ = view;
208010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!view)
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
211010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  view->SetDelegate(this);
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  TriggerShowBubble();
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void PermissionBubbleManager::DocumentOnLoadCompletedInMainFrame() {
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  request_url_has_loaded_ = true;
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // This is scheduled because while all calls to the browser have been
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // issued at DOMContentLoaded, they may be bouncing around in scheduled
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // callbacks finding the UI thread still. This makes sure we allow those
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // scheduled calls to AddRequest to complete before we show the page-load
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // permissions bubble.
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ScheduleShowBubble();
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionBubbleManager::DocumentLoadedInFrame(
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    content::RenderFrameHost* render_frame_host) {
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (request_url_has_loaded_)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ScheduleShowBubble();
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid PermissionBubbleManager::NavigationEntryCommitted(
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const content::LoadCommittedDetails& details) {
233010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // No permissions requests pending.
234010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (request_url_.is_empty())
235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // If we have navigated to a new url or reloaded the page...
238116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // GetAsReferrer strips fragment and username/password, meaning
239116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // the navigation is really to the same page.
240116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if ((request_url_.GetAsReferrer() !=
241116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       web_contents()->GetLastCommittedURL().GetAsReferrer()) ||
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      details.type == content::NAVIGATION_TYPE_EXISTING_PAGE) {
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Kill off existing bubble and cancel any pending requests.
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CancelPendingQueues();
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    FinalizeBubble();
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
249010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)void PermissionBubbleManager::WebContentsDestroyed() {
250010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // If the web contents has been destroyed, treat the bubble as cancelled.
251116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CancelPendingQueues();
252c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  FinalizeBubble();
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The WebContents is going away; be aggressively paranoid and delete
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ourselves lest other parts of the system attempt to add permission bubbles
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // or use us otherwise during the destruction.
257010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  web_contents()->RemoveUserData(UserDataKey());
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // That was the equivalent of "delete this". This object is now destroyed;
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // returning from this function is the only safe thing to do.
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::ToggleAccept(int request_index, bool new_value) {
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(request_index < static_cast<int>(accept_states_.size()));
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accept_states_[request_index] = new_value;
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::SetCustomizationMode() {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  customization_mode_ = true;
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (view_)
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    view_->Show(requests_, accept_states_, customization_mode_);
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::Accept() {
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<bool>::iterator accepts_iter = accept_states_.begin();
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter != requests_.end();
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter++, accepts_iter++) {
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (*accepts_iter)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (*requests_iter)->PermissionGranted();
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      (*requests_iter)->PermissionDenied();
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FinalizeBubble();
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::Deny() {
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (requests_iter = requests_.begin();
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter != requests_.end();
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter++) {
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*requests_iter)->PermissionDenied();
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FinalizeBubble();
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::Closing() {
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (requests_iter = requests_.begin();
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter != requests_.end();
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter++) {
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*requests_iter)->Cancelled();
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FinalizeBubble();
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionBubbleManager::ScheduleShowBubble() {
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::BrowserThread::PostTask(
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      content::BrowserThread::UI,
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      FROM_HERE,
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&PermissionBubbleManager::TriggerShowBubble,
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionBubbleManager::TriggerShowBubble() {
316010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!view_)
317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (bubble_showing_)
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
320010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!request_url_has_loaded_)
321010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return;
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (requests_.empty() && queued_requests_.empty() &&
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      queued_frame_requests_.empty()) {
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
325116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (requests_.empty()) {
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Queues containing a user-gesture-generated request have priority.
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (HasUserGestureRequest(queued_requests_))
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      requests_.swap(queued_requests_);
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else if (HasUserGestureRequest(queued_frame_requests_))
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      requests_.swap(queued_frame_requests_);
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else if (queued_requests_.size())
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      requests_.swap(queued_requests_);
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    else
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      requests_.swap(queued_frame_requests_);
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Sets the default value for each request to be 'accept'.
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(leng):  Currently all requests default to true.  If that changes:
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // a) Add additional accept_state queues to store default values.
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // b) Change the request API to provide the default value.
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    accept_states_.resize(requests_.size(), true);
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
344010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
345010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Note: this should appear above Show() for testing, since in that
346010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // case we may do in-line calling of finalization.
347010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bubble_showing_ = true;
348010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  view_->Show(requests_, accept_states_, customization_mode_);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void PermissionBubbleManager::FinalizeBubble() {
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (view_)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    view_->Hide();
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bubble_showing_ = false;
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (requests_iter = requests_.begin();
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter != requests_.end();
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       requests_iter++) {
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*requests_iter)->RequestFinished();
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  requests_.clear();
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accept_states_.clear();
364116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (queued_requests_.size() || queued_frame_requests_.size())
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    TriggerShowBubble();
366116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  else
3670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    request_url_ = GURL();
3680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
370116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid PermissionBubbleManager::CancelPendingQueues() {
3710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::vector<PermissionBubbleRequest*>::iterator requests_iter;
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (requests_iter = queued_requests_.begin();
3730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       requests_iter != queued_requests_.end();
3740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       requests_iter++) {
3750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    (*requests_iter)->RequestFinished();
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
377116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  for (requests_iter = queued_frame_requests_.begin();
378116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       requests_iter != queued_frame_requests_.end();
379116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch       requests_iter++) {
380116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    (*requests_iter)->RequestFinished();
381116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
382116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_requests_.clear();
383116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  queued_frame_requests_.clear();
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool PermissionBubbleManager::ExistingRequest(
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PermissionBubbleRequest* request,
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::vector<PermissionBubbleRequest*>& queue,
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool* same_object) {
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(same_object);
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  *same_object = false;
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::const_iterator iter;
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (iter = queue.begin(); iter != queue.end(); iter++) {
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (*iter == request) {
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      *same_object = true;
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return true;
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if ((*iter)->GetMessageTextFragment() ==
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            request->GetMessageTextFragment() &&
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        (*iter)->GetRequestingHostname() == request->GetRequestingHostname()) {
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return true;
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool PermissionBubbleManager::HasUserGestureRequest(
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::vector<PermissionBubbleRequest*>& queue) {
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<PermissionBubbleRequest*>::const_iterator iter;
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (iter = queue.begin(); iter != queue.end(); iter++) {
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if ((*iter)->HasUserGesture())
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return true;
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return false;
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
416116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
417