Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/notifications/notification_permission_context.h" | 5 #include "chrome/browser/notifications/notification_permission_context.h" |
| 6 | 6 |
| 7 #include <queue> | |
| 8 | |
| 9 #include "base/callback.h" | |
| 10 #include "base/location.h" | |
| 11 #include "base/rand_util.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "base/thread_task_runner_handle.h" | |
| 14 #include "base/timer/timer.h" | |
| 7 #include "chrome/browser/notifications/desktop_notification_profile_util.h" | 15 #include "chrome/browser/notifications/desktop_notification_profile_util.h" |
| 16 #include "chrome/browser/permissions/permission_request_id.h" | |
| 17 #include "chrome/browser/profiles/profile.h" | |
| 8 #include "components/content_settings/core/common/content_settings_pattern.h" | 18 #include "components/content_settings/core/common/content_settings_pattern.h" |
| 19 #include "content/public/browser/browser_thread.h" | |
| 9 #include "content/public/browser/permission_type.h" | 20 #include "content/public/browser/permission_type.h" |
| 21 #include "content/public/browser/render_frame_host.h" | |
| 22 #include "content/public/browser/web_contents_observer.h" | |
| 23 #include "content/public/browser/web_contents_user_data.h" | |
| 10 #include "url/gurl.h" | 24 #include "url/gurl.h" |
| 11 | 25 |
| 26 namespace { | |
| 27 | |
| 28 // At most one of these is attached to each WebContents. | |
| 29 class VisibilityTimerTabHelper | |
| 30 : public content::WebContentsObserver, | |
| 31 public content::WebContentsUserData<VisibilityTimerTabHelper> { | |
| 32 public: | |
| 33 ~VisibilityTimerTabHelper() override {}; | |
| 34 | |
| 35 // Runs |task| after the WebContents has been visible for a consecutive | |
| 36 // duration of at least |visible_delay|. | |
| 37 void PostTaskAfterVisibleDelay(const tracked_objects::Location& from_here, | |
| 38 const base::Closure& task, | |
| 39 base::TimeDelta visible_delay); | |
| 40 | |
| 41 // WebContentsObserver: | |
| 42 void WasShown() override; | |
| 43 void WasHidden() override; | |
| 44 void WebContentsDestroyed() override; | |
| 45 | |
| 46 private: | |
| 47 friend class content::WebContentsUserData<VisibilityTimerTabHelper>; | |
| 48 explicit VisibilityTimerTabHelper(content::WebContents* contents); | |
| 49 | |
| 50 void RunTask(const base::Closure& task); | |
| 51 | |
| 52 bool is_visible_; | |
| 53 std::queue<scoped_ptr<base::Timer>> task_queue_; | |
| 54 | |
| 55 DISALLOW_COPY_AND_ASSIGN(VisibilityTimerTabHelper); | |
| 56 }; | |
| 57 | |
| 58 VisibilityTimerTabHelper::VisibilityTimerTabHelper( | |
| 59 content::WebContents* contents) | |
| 60 : content::WebContentsObserver(contents) { | |
| 61 if (!contents->GetMainFrame()) { | |
| 62 is_visible_ = false; | |
| 63 } else { | |
| 64 switch (contents->GetMainFrame()->GetVisibilityState()) { | |
| 65 case blink::WebPageVisibilityStateHidden: | |
| 66 case blink::WebPageVisibilityStatePrerender: | |
| 67 is_visible_ = false; | |
| 68 break; | |
| 69 case blink::WebPageVisibilityStateVisible: | |
| 70 is_visible_ = true; | |
| 71 break; | |
| 72 } | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 void VisibilityTimerTabHelper::PostTaskAfterVisibleDelay( | |
| 77 const tracked_objects::Location& from_here, | |
| 78 const base::Closure& task, | |
| 79 base::TimeDelta visible_delay) { | |
| 80 // Safe to use Unretained, as destroying this will destroy task_queue_, hence | |
| 81 // cancelling all timers. | |
| 82 task_queue_.push(make_scoped_ptr(new base::Timer( | |
| 83 from_here, visible_delay, base::Bind(&VisibilityTimerTabHelper::RunTask, | |
| 84 base::Unretained(this), task), | |
| 85 false /* is_repeating */))); | |
| 86 DCHECK(!task_queue_.back()->IsRunning()); | |
| 87 if (is_visible_ && task_queue_.size() == 1) | |
| 88 task_queue_.front()->Reset(); | |
| 89 } | |
| 90 | |
| 91 void VisibilityTimerTabHelper::WasShown() { | |
| 92 if (!is_visible_ && !task_queue_.empty()) | |
| 93 task_queue_.front()->Reset(); | |
| 94 is_visible_ = true; | |
| 95 } | |
| 96 | |
| 97 void VisibilityTimerTabHelper::WasHidden() { | |
| 98 if (is_visible_ && !task_queue_.empty()) | |
| 99 task_queue_.front()->Stop(); | |
| 100 is_visible_ = false; | |
| 101 } | |
| 102 | |
| 103 void VisibilityTimerTabHelper::WebContentsDestroyed() { | |
| 104 // Delete ourselves, to avoid running tasks after WebContents is destroyed. | |
| 105 web_contents()->RemoveUserData(UserDataKey()); | |
| 106 // |this| has been deleted now. | |
| 107 } | |
| 108 | |
| 109 void VisibilityTimerTabHelper::RunTask(const base::Closure& task) { | |
| 110 DCHECK(is_visible_); | |
| 111 task.Run(); | |
| 112 task_queue_.pop(); | |
| 113 if (!task_queue_.empty()) { | |
| 114 task_queue_.front()->Reset(); | |
| 115 return; | |
| 116 } | |
| 117 web_contents()->RemoveUserData(UserDataKey()); | |
| 118 // |this| has been deleted now. | |
| 119 } | |
| 120 | |
| 121 } // namespace | |
| 122 | |
| 123 DEFINE_WEB_CONTENTS_USER_DATA_KEY(VisibilityTimerTabHelper); | |
| 124 | |
| 12 NotificationPermissionContext::NotificationPermissionContext(Profile* profile) | 125 NotificationPermissionContext::NotificationPermissionContext(Profile* profile) |
| 13 : PermissionContextBase(profile, | 126 : PermissionContextBase(profile, |
| 14 content::PermissionType::NOTIFICATIONS, | 127 content::PermissionType::NOTIFICATIONS, |
| 15 CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {} | 128 CONTENT_SETTINGS_TYPE_NOTIFICATIONS), |
| 129 weak_factory_ui_thread_(this) {} | |
| 16 | 130 |
| 17 NotificationPermissionContext::~NotificationPermissionContext() {} | 131 NotificationPermissionContext::~NotificationPermissionContext() {} |
| 18 | 132 |
| 19 void NotificationPermissionContext::ResetPermission( | 133 void NotificationPermissionContext::ResetPermission( |
| 20 const GURL& requesting_origin, | 134 const GURL& requesting_origin, |
| 21 const GURL& embedder_origin) { | 135 const GURL& embedder_origin) { |
| 22 DesktopNotificationProfileUtil::ClearSetting( | 136 DesktopNotificationProfileUtil::ClearSetting( |
| 23 profile(), ContentSettingsPattern::FromURLNoWildcard(requesting_origin)); | 137 profile(), ContentSettingsPattern::FromURLNoWildcard(requesting_origin)); |
| 24 } | 138 } |
| 25 | 139 |
| 140 void NotificationPermissionContext::DecidePermission( | |
| 141 content::WebContents* web_contents, | |
| 142 const PermissionRequestID& id, | |
| 143 const GURL& requesting_origin, | |
| 144 const GURL& embedding_origin, | |
| 145 bool user_gesture, | |
| 146 const BrowserPermissionCallback& callback) { | |
| 147 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 148 | |
| 149 // Notifications is always denied in incognito. To prevent sites from using | |
|
mlamouri (slow - plz ping)
2016/01/12 18:13:15
nit: "Notification permission is alway [..]"
johnme
2016/01/12 18:42:44
Done.
| |
| 150 // that to detect whether incognito mode is active, we deny after a random | |
| 151 // time delay, to simulate a user clicking a bubble/infobar. See also | |
| 152 // ContentSettingsRegistry::Init, which marks notifications as | |
| 153 // INHERIT_IN_INCOGNITO_EXCEPT_ALLOW, and | |
| 154 // PermissionMenuModel::PermissionMenuModel which prevents users from manually | |
| 155 // allowing the permission. | |
| 156 if (profile()->IsOffTheRecord()) { | |
| 157 // Random number of seconds in the range [1.0, 2.0). | |
|
mlamouri (slow - plz ping)
2016/01/12 18:13:15
My two cents: this is so fast and with a range so
johnme
2016/01/12 18:42:44
Acknowledged, though there would be a high false p
| |
| 158 double delay_seconds = 1.0 + 1.0 * base::RandDouble(); | |
| 159 VisibilityTimerTabHelper::CreateForWebContents(web_contents); | |
| 160 VisibilityTimerTabHelper::FromWebContents(web_contents) | |
| 161 ->PostTaskAfterVisibleDelay( | |
| 162 FROM_HERE, | |
| 163 base::Bind(&NotificationPermissionContext::NotifyPermissionSet, | |
| 164 weak_factory_ui_thread_.GetWeakPtr(), id, | |
| 165 requesting_origin, embedding_origin, callback, | |
| 166 true /* persist */, CONTENT_SETTING_BLOCK), | |
| 167 base::TimeDelta::FromSecondsD(delay_seconds)); | |
| 168 return; | |
| 169 } | |
| 170 | |
| 171 PermissionContextBase::DecidePermission(web_contents, id, requesting_origin, | |
| 172 embedding_origin, user_gesture, | |
| 173 callback); | |
| 174 } | |
| 175 | |
| 26 // Unlike other permission types, granting a notification for a given origin | 176 // Unlike other permission types, granting a notification for a given origin |
| 27 // will not take into account the |embedder_origin|, it will only be based | 177 // will not take into account the |embedder_origin|, it will only be based |
| 28 // on the requesting iframe origin. | 178 // on the requesting iframe origin. |
| 29 // TODO(mukai) Consider why notifications behave differently than | 179 // TODO(mukai) Consider why notifications behave differently than |
| 30 // other permissions. https://crbug.com/416894 | 180 // other permissions. https://crbug.com/416894 |
| 31 void NotificationPermissionContext::UpdateContentSetting( | 181 void NotificationPermissionContext::UpdateContentSetting( |
| 32 const GURL& requesting_origin, | 182 const GURL& requesting_origin, |
| 33 const GURL& embedder_origin, | 183 const GURL& embedder_origin, |
| 34 ContentSetting content_setting) { | 184 ContentSetting content_setting) { |
| 35 DCHECK(content_setting == CONTENT_SETTING_ALLOW || | 185 DCHECK(content_setting == CONTENT_SETTING_ALLOW || |
| 36 content_setting == CONTENT_SETTING_BLOCK); | 186 content_setting == CONTENT_SETTING_BLOCK); |
| 37 | 187 |
| 38 if (content_setting == CONTENT_SETTING_ALLOW) { | 188 if (content_setting == CONTENT_SETTING_ALLOW) { |
| 39 DesktopNotificationProfileUtil::GrantPermission(profile(), | 189 DesktopNotificationProfileUtil::GrantPermission(profile(), |
| 40 requesting_origin); | 190 requesting_origin); |
| 41 } else { | 191 } else { |
| 42 DesktopNotificationProfileUtil::DenyPermission(profile(), | 192 DesktopNotificationProfileUtil::DenyPermission(profile(), |
| 43 requesting_origin); | 193 requesting_origin); |
| 44 } | 194 } |
| 45 } | 195 } |
| 46 | 196 |
| 47 bool NotificationPermissionContext::IsRestrictedToSecureOrigins() const { | 197 bool NotificationPermissionContext::IsRestrictedToSecureOrigins() const { |
| 48 return false; | 198 return false; |
| 49 } | 199 } |
| OLD | NEW |