Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: chrome/browser/extensions/api/notifications/notifications_api.cc

Issue 2921263002: Remove many delegates, let's see what breaks
Patch Set: fix test Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/extensions/api/notifications/notifications_api.h" 5 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/feature_list.h" 12 #include "base/feature_list.h"
13 #include "base/guid.h" 13 #include "base/guid.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
17 #include "base/rand_util.h" 17 #include "base/rand_util.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
20 #include "base/time/time.h" 20 #include "base/time/time.h"
21 #include "build/build_config.h" 21 #include "build/build_config.h"
22 #include "chrome/browser/browser_process.h" 22 #include "chrome/browser/browser_process.h"
23 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper.h" 23 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper.h"
24 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper_factory.h" 24 #include "chrome/browser/extensions/api/notifications/extension_notification_dis play_helper_factory.h"
25 #include "chrome/browser/notifications/native_notification_delegate.h"
26 #include "chrome/browser/notifications/notification.h" 25 #include "chrome/browser/notifications/notification.h"
27 #include "chrome/browser/notifications/notification_common.h" 26 #include "chrome/browser/notifications/notification_common.h"
28 #include "chrome/browser/notifications/notification_delegate.h" 27 #include "chrome/browser/notifications/notification_delegate.h"
29 #include "chrome/browser/notifications/notifier_state_tracker.h" 28 #include "chrome/browser/notifications/notifier_state_tracker.h"
30 #include "chrome/browser/notifications/notifier_state_tracker_factory.h" 29 #include "chrome/browser/notifications/notifier_state_tracker_factory.h"
30 #include "chrome/browser/notifications/web_notification_delegate.h"
31 #include "chrome/browser/profiles/profile.h" 31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/common/chrome_features.h"
33 #include "chrome/common/extensions/api/notifications/notification_style.h" 32 #include "chrome/common/extensions/api/notifications/notification_style.h"
34 #include "chrome/common/features.h"
35 #include "components/keyed_service/content/browser_context_keyed_service_shutdow n_notifier_factory.h" 33 #include "components/keyed_service/content/browser_context_keyed_service_shutdow n_notifier_factory.h"
36 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h" 34 #include "components/keyed_service/core/keyed_service_shutdown_notifier.h"
37 #include "content/public/browser/render_process_host.h" 35 #include "content/public/browser/render_process_host.h"
38 #include "content/public/browser/render_view_host.h" 36 #include "content/public/browser/render_view_host.h"
39 #include "content/public/browser/web_contents.h" 37 #include "content/public/browser/web_contents.h"
40 #include "extensions/browser/app_window/app_window.h" 38 #include "extensions/browser/app_window/app_window.h"
41 #include "extensions/browser/app_window/app_window_registry.h" 39 #include "extensions/browser/app_window/app_window_registry.h"
42 #include "extensions/browser/app_window/native_app_window.h" 40 #include "extensions/browser/app_window/native_app_window.h"
43 #include "extensions/browser/event_router.h" 41 #include "extensions/browser/event_router.h"
44 #include "extensions/browser/extension_system_provider.h" 42 #include "extensions/browser/extension_system_provider.h"
45 #include "extensions/browser/extensions_browser_client.h" 43 #include "extensions/browser/extensions_browser_client.h"
46 #include "extensions/common/extension.h" 44 #include "extensions/common/extension.h"
47 #include "extensions/common/features/feature.h"
48 #include "third_party/skia/include/core/SkBitmap.h" 45 #include "third_party/skia/include/core/SkBitmap.h"
49 #include "ui/base/layout.h" 46 #include "ui/base/layout.h"
50 #include "ui/gfx/image/image.h" 47 #include "ui/gfx/image/image.h"
51 #include "ui/gfx/image/image_skia.h" 48 #include "ui/gfx/image/image_skia.h"
52 #include "ui/gfx/image/image_skia_operations.h" 49 #include "ui/gfx/image/image_skia_operations.h"
53 #include "ui/gfx/image/image_skia_rep.h" 50 #include "ui/gfx/image/image_skia_rep.h"
54 #include "ui/gfx/skia_util.h" 51 #include "ui/gfx/skia_util.h"
55 #include "ui/message_center/message_center_style.h" 52 #include "ui/message_center/message_center_style.h"
56 #include "ui/message_center/notifier_settings.h" 53 #include "ui/message_center/notifier_settings.h"
57 #include "url/gurl.h" 54 #include "url/gurl.h"
58 55
59 using message_center::NotifierId; 56 using message_center::NotifierId;
60 57
61 namespace extensions { 58 namespace extensions {
62 59
63 namespace notifications = api::notifications; 60 namespace notifications = api::notifications;
64 61
65 const base::Feature kAllowFullscreenAppNotificationsFeature{
66 "FSNotificationsApp", base::FEATURE_ENABLED_BY_DEFAULT
67 };
68
69 namespace { 62 namespace {
70 63
71 const char kMissingRequiredPropertiesForCreateNotification[] = 64 const char kMissingRequiredPropertiesForCreateNotification[] =
72 "Some of the required properties are missing: type, iconUrl, title and " 65 "Some of the required properties are missing: type, iconUrl, title and "
73 "message."; 66 "message.";
74 const char kUnableToDecodeIconError[] = 67 const char kUnableToDecodeIconError[] =
75 "Unable to successfully use the provided image."; 68 "Unable to successfully use the provided image.";
76 const char kUnexpectedProgressValueForNonProgressType[] = 69 const char kUnexpectedProgressValueForNonProgressType[] =
77 "The progress value should not be specified for non-progress notification"; 70 "The progress value should not be specified for non-progress notification";
78 const char kInvalidProgressValue[] = 71 const char kInvalidProgressValue[] =
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0)); 176 ((c_rgba_data[rgba_index + 2] & 0xFF) << 0));
184 } 177 }
185 178
186 // TODO(dewittj): Handle HiDPI images with more than one scale factor 179 // TODO(dewittj): Handle HiDPI images with more than one scale factor
187 // representation. 180 // representation.
188 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f)); 181 gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f));
189 *return_image = gfx::Image(skia); 182 *return_image = gfx::Image(skia);
190 return true; 183 return true;
191 } 184 }
192 185
193 class ShutdownNotifierFactory
194 : public BrowserContextKeyedServiceShutdownNotifierFactory {
195 public:
196 static ShutdownNotifierFactory* GetInstance() {
197 return base::Singleton<ShutdownNotifierFactory>::get();
198 }
199
200 private:
201 friend struct base::DefaultSingletonTraits<ShutdownNotifierFactory>;
202
203 ShutdownNotifierFactory()
204 : BrowserContextKeyedServiceShutdownNotifierFactory(
205 "NotificationsApiDelegate") {
206 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
207 }
208 ~ShutdownNotifierFactory() override {}
209
210 DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory);
211 };
212
213 // Message center based notification delegate with all the functionality.
214 class NotificationApiDelegate : public NotificationDelegate {
215 public:
216 NotificationApiDelegate(ChromeAsyncExtensionFunction* api_function,
217 Profile* profile,
218 const std::string& extension_id,
219 const std::string& id)
220 : api_function_(api_function),
221 event_router_(EventRouter::Get(profile)),
222 display_helper_(
223 ExtensionNotificationDisplayHelperFactory::GetForProfile(profile)),
224 extension_id_(extension_id),
225 scoped_id_(CreateScopedIdentifier(extension_id, id)) {
226 DCHECK(api_function_);
227 DCHECK(display_helper_);
228
229 shutdown_notifier_subscription_ =
230 ShutdownNotifierFactory::GetInstance()->Get(profile)->Subscribe(
231 base::Bind(&NotificationApiDelegate::Shutdown,
232 base::Unretained(this)));
233 }
234
235 void Close(bool by_user) override {
236 EventRouter::UserGestureState gesture =
237 by_user ? EventRouter::USER_GESTURE_ENABLED
238 : EventRouter::USER_GESTURE_NOT_ENABLED;
239 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs());
240 args->AppendBoolean(by_user);
241 SendEvent(events::NOTIFICATIONS_ON_CLOSED,
242 notifications::OnClosed::kEventName, gesture, std::move(args));
243
244 DCHECK(display_helper_);
245 display_helper_->EraseDataForNotificationId(scoped_id_);
246 }
247
248 void Click() override {
249 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs());
250 SendEvent(events::NOTIFICATIONS_ON_CLICKED,
251 notifications::OnClicked::kEventName,
252 EventRouter::USER_GESTURE_ENABLED, std::move(args));
253 }
254
255 bool HasClickedListener() override {
256 if (!event_router_)
257 return false;
258
259 return event_router_->HasEventListener(
260 notifications::OnClicked::kEventName);
261 }
262
263 void ButtonClick(int index) override {
264 std::unique_ptr<base::ListValue> args(CreateBaseEventArgs());
265 args->AppendInteger(index);
266 SendEvent(events::NOTIFICATIONS_ON_BUTTON_CLICKED,
267 notifications::OnButtonClicked::kEventName,
268 EventRouter::USER_GESTURE_ENABLED, std::move(args));
269 }
270
271 std::string id() const override { return scoped_id_; }
272
273 // Should only display when fullscreen if this app is the source of the
274 // fullscreen window.
275 bool ShouldDisplayOverFullscreen() const override {
276 AppWindowRegistry::AppWindowList windows = AppWindowRegistry::Get(
277 api_function_->GetProfile())->GetAppWindowsForApp(extension_id_);
278 for (auto* window : windows) {
279 // Window must be fullscreen and visible
280 if (window->IsFullscreen() && window->GetBaseWindow()->IsActive()) {
281 bool enabled = base::FeatureList::IsEnabled(
282 kAllowFullscreenAppNotificationsFeature);
283 if (enabled) {
284 UMA_HISTOGRAM_ENUMERATION("Notifications.Display_Fullscreen.Shown",
285 NotifierId::APPLICATION,
286 NotifierId::SIZE);
287 } else {
288 UMA_HISTOGRAM_ENUMERATION(
289 "Notifications.Display_Fullscreen.Suppressed",
290 NotifierId::APPLICATION,
291 NotifierId::SIZE);
292
293 }
294 return enabled;
295 }
296 }
297
298 return false;
299 }
300
301 private:
302 ~NotificationApiDelegate() override {}
303
304 void SendEvent(events::HistogramValue histogram_value,
305 const std::string& name,
306 EventRouter::UserGestureState user_gesture,
307 std::unique_ptr<base::ListValue> args) {
308 if (!event_router_)
309 return;
310
311 std::unique_ptr<Event> event(
312 new Event(histogram_value, name, std::move(args)));
313 event->user_gesture = user_gesture;
314 event_router_->DispatchEventToExtension(extension_id_, std::move(event));
315 }
316
317 void Shutdown() {
318 shutdown_notifier_subscription_.reset();
319 event_router_ = nullptr;
320 display_helper_ = nullptr;
321 }
322
323 std::unique_ptr<base::ListValue> CreateBaseEventArgs() {
324 std::unique_ptr<base::ListValue> args(new base::ListValue());
325 args->AppendString(StripScopeFromIdentifier(extension_id_, scoped_id_));
326 return args;
327 }
328
329 scoped_refptr<ChromeAsyncExtensionFunction> api_function_;
330
331 // Since this class is refcounted it may outlive the profile. We listen for
332 // profile-keyed service shutdown events and reset to nullptr at that time,
333 // so make sure to check for a valid pointer before use.
334 EventRouter* event_router_;
335 ExtensionNotificationDisplayHelper* display_helper_;
336
337 const std::string extension_id_;
338 const std::string scoped_id_;
339
340 std::unique_ptr<KeyedServiceShutdownNotifier::Subscription>
341 shutdown_notifier_subscription_;
342
343 DISALLOW_COPY_AND_ASSIGN(NotificationApiDelegate);
344 };
345
346 } // namespace 186 } // namespace
347 187
348 bool NotificationsApiFunction::IsNotificationsApiAvailable() { 188 bool NotificationsApiFunction::IsNotificationsApiAvailable() {
349 // We need to check this explicitly rather than letting 189 // We need to check this explicitly rather than letting
350 // _permission_features.json enforce it, because we're sharing the 190 // _permission_features.json enforce it, because we're sharing the
351 // chrome.notifications permissions namespace with WebKit notifications. 191 // chrome.notifications permissions namespace with WebKit notifications.
352 return extension()->is_platform_app() || extension()->is_extension(); 192 return extension()->is_platform_app() || extension()->is_extension();
353 } 193 }
354 194
355 NotificationsApiFunction::NotificationsApiFunction() { 195 NotificationsApiFunction::NotificationsApiFunction() {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 optional_fields.items.push_back(message_center::NotificationItem( 330 optional_fields.items.push_back(message_center::NotificationItem(
491 base::UTF8ToUTF16(api_item.title), 331 base::UTF8ToUTF16(api_item.title),
492 base::UTF8ToUTF16(api_item.message))); 332 base::UTF8ToUTF16(api_item.message)));
493 } 333 }
494 } 334 }
495 335
496 if (options->is_clickable.get()) 336 if (options->is_clickable.get())
497 optional_fields.clickable = *options->is_clickable; 337 optional_fields.clickable = *options->is_clickable;
498 338
499 // Create the notification api delegate. Ownership passed to the notification. 339 // Create the notification api delegate. Ownership passed to the notification.
500 NotificationDelegate* api_delegate; 340 NotificationDelegate* api_delegate = new WebNotificationDelegate(
501 #if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) 341 NotificationCommon::EXTENSION, GetProfile(),
502 if (base::FeatureList::IsEnabled(features::kNativeNotifications) && 342 CreateScopedIdentifier(extension_->id(), id), extension_->url());
503 g_browser_process->notification_platform_bridge()) {
504 api_delegate = new NativeNotificationDelegate(
505 CreateScopedIdentifier(extension_->id(), id));
506 } else {
507 api_delegate =
508 new NotificationApiDelegate(this, GetProfile(), extension_->id(), id);
509 }
510 #else
511 api_delegate =
512 new NotificationApiDelegate(this, GetProfile(), extension_->id(), id);
513 #endif // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
514 343
515 Notification notification( 344 Notification notification(
516 type, title, message, icon, 345 type, title, message, icon,
517 message_center::NotifierId(message_center::NotifierId::APPLICATION, 346 message_center::NotifierId(message_center::NotifierId::APPLICATION,
518 extension_->id()), 347 extension_->id()),
519 base::UTF8ToUTF16(extension_->name()), extension_->url(), 348 base::UTF8ToUTF16(extension_->name()), extension_->url(),
520 api_delegate->id(), optional_fields, api_delegate); 349 api_delegate->id(), optional_fields, api_delegate);
521 350
522 // Apply the "requireInteraction" flag. The value defaults to false. 351 // Apply the "requireInteraction" flag. The value defaults to false.
523 notification.set_never_timeout(options->require_interaction && 352 notification.set_never_timeout(options->require_interaction &&
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
848 : api::notifications::PERMISSION_LEVEL_DENIED; 677 : api::notifications::PERMISSION_LEVEL_DENIED;
849 678
850 SetResult( 679 SetResult(
851 base::MakeUnique<base::Value>(api::notifications::ToString(result))); 680 base::MakeUnique<base::Value>(api::notifications::ToString(result)));
852 SendResponse(true); 681 SendResponse(true);
853 682
854 return true; 683 return true;
855 } 684 }
856 685
857 } // namespace extensions 686 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698