OLD | NEW |
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/ui/webui/ntp/app_launcher_handler.h" | 5 #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
12 #include "base/i18n/rtl.h" | 12 #include "base/i18n/rtl.h" |
13 #include "base/metrics/field_trial.h" | 13 #include "base/metrics/field_trial.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "base/prefs/pref_service.h" | 15 #include "base/prefs/pref_service.h" |
16 #include "base/utf_string_conversions.h" | 16 #include "base/utf_string_conversions.h" |
17 #include "base/values.h" | 17 #include "base/values.h" |
18 #include "chrome/browser/extensions/app_notification.h" | |
19 #include "chrome/browser/extensions/app_notification_manager.h" | |
20 #include "chrome/browser/extensions/crx_installer.h" | 18 #include "chrome/browser/extensions/crx_installer.h" |
21 #include "chrome/browser/extensions/extension_prefs.h" | 19 #include "chrome/browser/extensions/extension_prefs.h" |
22 #include "chrome/browser/extensions/extension_service.h" | 20 #include "chrome/browser/extensions/extension_service.h" |
23 #include "chrome/browser/extensions/extension_sorting.h" | 21 #include "chrome/browser/extensions/extension_sorting.h" |
24 #include "chrome/browser/extensions/extension_system.h" | 22 #include "chrome/browser/extensions/extension_system.h" |
25 #include "chrome/browser/extensions/management_policy.h" | 23 #include "chrome/browser/extensions/management_policy.h" |
26 #include "chrome/browser/favicon/favicon_service_factory.h" | 24 #include "chrome/browser/favicon/favicon_service_factory.h" |
27 #include "chrome/browser/prefs/scoped_user_pref_update.h" | 25 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
28 #include "chrome/browser/profiles/profile.h" | 26 #include "chrome/browser/profiles/profile.h" |
29 #include "chrome/browser/ui/browser_finder.h" | 27 #include "chrome/browser/ui/browser_finder.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 | 80 |
83 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) | 81 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) |
84 : extension_service_(extension_service), | 82 : extension_service_(extension_service), |
85 ignore_changes_(false), | 83 ignore_changes_(false), |
86 attempted_bookmark_app_install_(false), | 84 attempted_bookmark_app_install_(false), |
87 has_loaded_apps_(false) { | 85 has_loaded_apps_(false) { |
88 } | 86 } |
89 | 87 |
90 AppLauncherHandler::~AppLauncherHandler() {} | 88 AppLauncherHandler::~AppLauncherHandler() {} |
91 | 89 |
92 // Serializes |notification| into a new DictionaryValue which the caller then | |
93 // owns. | |
94 static DictionaryValue* SerializeNotification( | |
95 const extensions::AppNotification& notification) { | |
96 DictionaryValue* dictionary = new DictionaryValue(); | |
97 dictionary->SetString("title", notification.title()); | |
98 dictionary->SetString("body", notification.body()); | |
99 if (!notification.link_url().is_empty()) { | |
100 dictionary->SetString("linkUrl", notification.link_url().spec()); | |
101 dictionary->SetString("linkText", notification.link_text()); | |
102 } | |
103 return dictionary; | |
104 } | |
105 | |
106 void AppLauncherHandler::CreateAppInfo( | 90 void AppLauncherHandler::CreateAppInfo( |
107 const Extension* extension, | 91 const Extension* extension, |
108 const extensions::AppNotification* notification, | |
109 ExtensionService* service, | 92 ExtensionService* service, |
110 DictionaryValue* value) { | 93 DictionaryValue* value) { |
111 value->Clear(); | 94 value->Clear(); |
112 | 95 |
113 // The Extension class 'helpfully' wraps bidi control characters that | 96 // The Extension class 'helpfully' wraps bidi control characters that |
114 // impede our ability to determine directionality. | 97 // impede our ability to determine directionality. |
115 string16 name = UTF8ToUTF16(extension->name()); | 98 string16 name = UTF8ToUTF16(extension->name()); |
116 base::i18n::UnadjustStringForLocaleDirection(&name); | 99 base::i18n::UnadjustStringForLocaleDirection(&name); |
117 NewTabUI::SetUrlTitleAndDirection(value, name, extension->GetFullLaunchURL()); | 100 NewTabUI::SetUrlTitleAndDirection(value, name, extension->GetFullLaunchURL()); |
118 | 101 |
(...skipping 25 matching lines...) Expand all Loading... |
144 value->SetInteger("launch_container", extension->launch_container()); | 127 value->SetInteger("launch_container", extension->launch_container()); |
145 ExtensionPrefs* prefs = service->extension_prefs(); | 128 ExtensionPrefs* prefs = service->extension_prefs(); |
146 value->SetInteger("launch_type", | 129 value->SetInteger("launch_type", |
147 prefs->GetLaunchType(extension, | 130 prefs->GetLaunchType(extension, |
148 ExtensionPrefs::LAUNCH_DEFAULT)); | 131 ExtensionPrefs::LAUNCH_DEFAULT)); |
149 value->SetBoolean("is_component", | 132 value->SetBoolean("is_component", |
150 extension->location() == extensions::Manifest::COMPONENT); | 133 extension->location() == extensions::Manifest::COMPONENT); |
151 value->SetBoolean("is_webstore", | 134 value->SetBoolean("is_webstore", |
152 extension->id() == extension_misc::kWebStoreAppId); | 135 extension->id() == extension_misc::kWebStoreAppId); |
153 | 136 |
154 if (extension->HasAPIPermission( | |
155 extensions::APIPermission::kAppNotifications)) { | |
156 value->SetBoolean("notifications_disabled", | |
157 prefs->IsAppNotificationDisabled(extension->id())); | |
158 } | |
159 | |
160 if (notification) | |
161 value->Set("notification", SerializeNotification(*notification)); | |
162 | |
163 ExtensionSorting* sorting = prefs->extension_sorting(); | 137 ExtensionSorting* sorting = prefs->extension_sorting(); |
164 syncer::StringOrdinal page_ordinal = sorting->GetPageOrdinal(extension->id()); | 138 syncer::StringOrdinal page_ordinal = sorting->GetPageOrdinal(extension->id()); |
165 if (!page_ordinal.IsValid()) { | 139 if (!page_ordinal.IsValid()) { |
166 // Make sure every app has a page ordinal (some predate the page ordinal). | 140 // Make sure every app has a page ordinal (some predate the page ordinal). |
167 // The webstore app should be on the first page. | 141 // The webstore app should be on the first page. |
168 page_ordinal = extension->id() == extension_misc::kWebStoreAppId ? | 142 page_ordinal = extension->id() == extension_misc::kWebStoreAppId ? |
169 sorting->CreateFirstAppPageOrdinal() : | 143 sorting->CreateFirstAppPageOrdinal() : |
170 sorting->GetNaturalAppPageOrdinal(); | 144 sorting->GetNaturalAppPageOrdinal(); |
171 sorting->SetPageOrdinal(extension->id(), page_ordinal); | 145 sorting->SetPageOrdinal(extension->id(), page_ordinal); |
172 } | 146 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 base::Unretained(this))); | 188 base::Unretained(this))); |
215 web_ui()->RegisterMessageCallback("saveAppPageName", | 189 web_ui()->RegisterMessageCallback("saveAppPageName", |
216 base::Bind(&AppLauncherHandler::HandleSaveAppPageName, | 190 base::Bind(&AppLauncherHandler::HandleSaveAppPageName, |
217 base::Unretained(this))); | 191 base::Unretained(this))); |
218 web_ui()->RegisterMessageCallback("generateAppForLink", | 192 web_ui()->RegisterMessageCallback("generateAppForLink", |
219 base::Bind(&AppLauncherHandler::HandleGenerateAppForLink, | 193 base::Bind(&AppLauncherHandler::HandleGenerateAppForLink, |
220 base::Unretained(this))); | 194 base::Unretained(this))); |
221 web_ui()->RegisterMessageCallback("recordAppLaunchByURL", | 195 web_ui()->RegisterMessageCallback("recordAppLaunchByURL", |
222 base::Bind(&AppLauncherHandler::HandleRecordAppLaunchByUrl, | 196 base::Bind(&AppLauncherHandler::HandleRecordAppLaunchByUrl, |
223 base::Unretained(this))); | 197 base::Unretained(this))); |
224 web_ui()->RegisterMessageCallback("closeNotification", | |
225 base::Bind(&AppLauncherHandler::HandleNotificationClose, | |
226 base::Unretained(this))); | |
227 web_ui()->RegisterMessageCallback("setNotificationsDisabled", | |
228 base::Bind(&AppLauncherHandler::HandleSetNotificationsDisabled, | |
229 base::Unretained(this))); | |
230 } | 198 } |
231 | 199 |
232 void AppLauncherHandler::Observe(int type, | 200 void AppLauncherHandler::Observe(int type, |
233 const content::NotificationSource& source, | 201 const content::NotificationSource& source, |
234 const content::NotificationDetails& details) { | 202 const content::NotificationDetails& details) { |
235 if (type == chrome::NOTIFICATION_APP_INSTALLED_TO_NTP) { | 203 if (type == chrome::NOTIFICATION_APP_INSTALLED_TO_NTP) { |
236 highlight_app_id_ = *content::Details<const std::string>(details).ptr(); | 204 highlight_app_id_ = *content::Details<const std::string>(details).ptr(); |
237 if (has_loaded_apps_) | 205 if (has_loaded_apps_) |
238 SetAppToBeHighlighted(); | 206 SetAppToBeHighlighted(); |
239 return; | 207 return; |
240 } | 208 } |
241 | 209 |
242 if (ignore_changes_ || !has_loaded_apps_) | 210 if (ignore_changes_ || !has_loaded_apps_) |
243 return; | 211 return; |
244 | 212 |
245 switch (type) { | 213 switch (type) { |
246 case chrome::NOTIFICATION_APP_NOTIFICATION_STATE_CHANGED: { | |
247 const std::string& id = | |
248 *content::Details<const std::string>(details).ptr(); | |
249 const extensions::AppNotification* notification = | |
250 extension_service_->app_notification_manager()->GetLast(id); | |
251 base::StringValue id_value(id); | |
252 if (notification) { | |
253 scoped_ptr<DictionaryValue> notification_value( | |
254 SerializeNotification(*notification)); | |
255 web_ui()->CallJavascriptFunction("ntp.appNotificationChanged", | |
256 id_value, *notification_value.get()); | |
257 } else { | |
258 web_ui()->CallJavascriptFunction("ntp.appNotificationChanged", | |
259 id_value); | |
260 } | |
261 break; | |
262 } | |
263 | |
264 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 214 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
265 const Extension* extension = | 215 const Extension* extension = |
266 content::Details<const Extension>(details).ptr(); | 216 content::Details<const Extension>(details).ptr(); |
267 if (!extension->is_app()) | 217 if (!extension->is_app()) |
268 return; | 218 return; |
269 | 219 |
270 scoped_ptr<DictionaryValue> app_info(GetAppInfo(extension)); | 220 scoped_ptr<DictionaryValue> app_info(GetAppInfo(extension)); |
271 if (app_info.get()) { | 221 if (app_info.get()) { |
272 visible_apps_.insert(extension->id()); | 222 visible_apps_.insert(extension->id()); |
273 | 223 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 break; | 255 break; |
306 } | 256 } |
307 case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: { | 257 case chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED: { |
308 const std::string* id = | 258 const std::string* id = |
309 content::Details<const std::string>(details).ptr(); | 259 content::Details<const std::string>(details).ptr(); |
310 if (id) { | 260 if (id) { |
311 const Extension* extension = | 261 const Extension* extension = |
312 extension_service_->GetExtensionById(*id, false); | 262 extension_service_->GetExtensionById(*id, false); |
313 DictionaryValue app_info; | 263 DictionaryValue app_info; |
314 CreateAppInfo(extension, | 264 CreateAppInfo(extension, |
315 NULL, | |
316 extension_service_, | 265 extension_service_, |
317 &app_info); | 266 &app_info); |
318 web_ui()->CallJavascriptFunction("ntp.appMoved", app_info); | 267 web_ui()->CallJavascriptFunction("ntp.appMoved", app_info); |
319 } else { | 268 } else { |
320 HandleGetApps(NULL); | 269 HandleGetApps(NULL); |
321 } | 270 } |
322 break; | 271 break; |
323 } | 272 } |
324 // The promo may not load until a couple seconds after the first NTP view, | 273 // The promo may not load until a couple seconds after the first NTP view, |
325 // so we listen for the load notification and notify the NTP when ready. | 274 // so we listen for the load notification and notify the NTP when ready. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
384 l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME))); | 333 l10n_util::GetStringUTF16(IDS_APP_DEFAULT_PAGE_NAME))); |
385 dictionary->Set("appPageNames", | 334 dictionary->Set("appPageNames", |
386 static_cast<ListValue*>(list->DeepCopy())); | 335 static_cast<ListValue*>(list->DeepCopy())); |
387 } else { | 336 } else { |
388 dictionary->Set("appPageNames", | 337 dictionary->Set("appPageNames", |
389 static_cast<ListValue*>(app_page_names->DeepCopy())); | 338 static_cast<ListValue*>(app_page_names->DeepCopy())); |
390 } | 339 } |
391 } | 340 } |
392 | 341 |
393 DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) { | 342 DictionaryValue* AppLauncherHandler::GetAppInfo(const Extension* extension) { |
394 extensions::AppNotificationManager* notification_manager = | |
395 extension_service_->app_notification_manager(); | |
396 DictionaryValue* app_info = new DictionaryValue(); | 343 DictionaryValue* app_info = new DictionaryValue(); |
397 // CreateAppInfo can change the extension prefs. | 344 // CreateAppInfo can change the extension prefs. |
398 base::AutoReset<bool> auto_reset(&ignore_changes_, true); | 345 base::AutoReset<bool> auto_reset(&ignore_changes_, true); |
399 CreateAppInfo(extension, | 346 CreateAppInfo(extension, |
400 notification_manager->GetLast(extension->id()), | |
401 extension_service_, | 347 extension_service_, |
402 app_info); | 348 app_info); |
403 return app_info; | 349 return app_info; |
404 } | 350 } |
405 | 351 |
406 void AppLauncherHandler::HandleGetApps(const ListValue* args) { | 352 void AppLauncherHandler::HandleGetApps(const ListValue* args) { |
407 DictionaryValue dictionary; | 353 DictionaryValue dictionary; |
408 | 354 |
409 // Tell the client whether to show the promo for this view. We don't do this | 355 // Tell the client whether to show the promo for this view. We don't do this |
410 // in the case of PREF_CHANGED because: | 356 // in the case of PREF_CHANGED because: |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 // the apps as they change. | 392 // the apps as they change. |
447 if (!has_loaded_apps_) { | 393 if (!has_loaded_apps_) { |
448 base::Closure callback = base::Bind( | 394 base::Closure callback = base::Bind( |
449 &AppLauncherHandler::OnPreferenceChanged, | 395 &AppLauncherHandler::OnPreferenceChanged, |
450 base::Unretained(this)); | 396 base::Unretained(this)); |
451 pref_change_registrar_.Init( | 397 pref_change_registrar_.Init( |
452 extension_service_->extension_prefs()->pref_service()); | 398 extension_service_->extension_prefs()->pref_service()); |
453 pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, callback); | 399 pref_change_registrar_.Add(ExtensionPrefs::kExtensionsPref, callback); |
454 pref_change_registrar_.Add(prefs::kNtpAppPageNames, callback); | 400 pref_change_registrar_.Add(prefs::kNtpAppPageNames, callback); |
455 | 401 |
456 registrar_.Add(this, chrome::NOTIFICATION_APP_NOTIFICATION_STATE_CHANGED, | |
457 content::Source<Profile>(profile)); | |
458 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 402 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
459 content::Source<Profile>(profile)); | 403 content::Source<Profile>(profile)); |
460 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 404 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
461 content::Source<Profile>(profile)); | 405 content::Source<Profile>(profile)); |
462 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, | 406 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LAUNCHER_REORDERED, |
463 content::Source<ExtensionSorting>( | 407 content::Source<ExtensionSorting>( |
464 extension_service_->extension_prefs()->extension_sorting())); | 408 extension_service_->extension_prefs()->extension_sorting())); |
465 registrar_.Add(this, chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED, | 409 registrar_.Add(this, chrome::NOTIFICATION_WEB_STORE_PROMO_LOADED, |
466 content::Source<Profile>(profile)); | 410 content::Source<Profile>(profile)); |
467 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, | 411 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
711 double source; | 655 double source; |
712 CHECK(args->GetDouble(1, &source)); | 656 CHECK(args->GetDouble(1, &source)); |
713 | 657 |
714 extension_misc::AppLaunchBucket bucket = | 658 extension_misc::AppLaunchBucket bucket = |
715 static_cast<extension_misc::AppLaunchBucket>(static_cast<int>(source)); | 659 static_cast<extension_misc::AppLaunchBucket>(static_cast<int>(source)); |
716 CHECK(source < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 660 CHECK(source < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
717 | 661 |
718 RecordAppLaunchByUrl(Profile::FromWebUI(web_ui()), url, bucket); | 662 RecordAppLaunchByUrl(Profile::FromWebUI(web_ui()), url, bucket); |
719 } | 663 } |
720 | 664 |
721 void AppLauncherHandler::HandleNotificationClose(const ListValue* args) { | |
722 std::string extension_id; | |
723 CHECK(args->GetString(0, &extension_id)); | |
724 | |
725 const Extension* extension = extension_service_->GetExtensionById( | |
726 extension_id, true); | |
727 if (!extension) | |
728 return; | |
729 | |
730 UMA_HISTOGRAM_COUNTS("AppNotification.NTPNotificationClosed", 1); | |
731 | |
732 extensions::AppNotificationManager* notification_manager = | |
733 extension_service_->app_notification_manager(); | |
734 notification_manager->ClearAll(extension_id); | |
735 } | |
736 | |
737 void AppLauncherHandler::HandleSetNotificationsDisabled( | |
738 const ListValue* args) { | |
739 std::string extension_id; | |
740 bool disabled = false; | |
741 CHECK(args->GetString(0, &extension_id)); | |
742 CHECK(args->GetBoolean(1, &disabled)); | |
743 | |
744 const Extension* extension = extension_service_->GetExtensionById( | |
745 extension_id, true); | |
746 if (!extension) | |
747 return; | |
748 extension_service_->SetAppNotificationDisabled(extension_id, disabled); | |
749 } | |
750 | |
751 void AppLauncherHandler::OnFaviconForApp( | 665 void AppLauncherHandler::OnFaviconForApp( |
752 scoped_ptr<AppInstallInfo> install_info, | 666 scoped_ptr<AppInstallInfo> install_info, |
753 const history::FaviconImageResult& image_result) { | 667 const history::FaviconImageResult& image_result) { |
754 scoped_ptr<WebApplicationInfo> web_app(new WebApplicationInfo()); | 668 scoped_ptr<WebApplicationInfo> web_app(new WebApplicationInfo()); |
755 web_app->is_bookmark_app = install_info->is_bookmark_app; | 669 web_app->is_bookmark_app = install_info->is_bookmark_app; |
756 web_app->title = install_info->title; | 670 web_app->title = install_info->title; |
757 web_app->app_url = install_info->app_url; | 671 web_app->app_url = install_info->app_url; |
758 web_app->urls.push_back(install_info->app_url); | 672 web_app->urls.push_back(install_info->app_url); |
759 | 673 |
760 if (!image_result.image.IsEmpty()) { | 674 if (!image_result.image.IsEmpty()) { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
897 ExtensionUninstallDialog* AppLauncherHandler::GetExtensionUninstallDialog() { | 811 ExtensionUninstallDialog* AppLauncherHandler::GetExtensionUninstallDialog() { |
898 if (!extension_uninstall_dialog_.get()) { | 812 if (!extension_uninstall_dialog_.get()) { |
899 Browser* browser = chrome::FindBrowserWithWebContents( | 813 Browser* browser = chrome::FindBrowserWithWebContents( |
900 web_ui()->GetWebContents()); | 814 web_ui()->GetWebContents()); |
901 extension_uninstall_dialog_.reset( | 815 extension_uninstall_dialog_.reset( |
902 ExtensionUninstallDialog::Create(extension_service_->profile(), | 816 ExtensionUninstallDialog::Create(extension_service_->profile(), |
903 browser, this)); | 817 browser, this)); |
904 } | 818 } |
905 return extension_uninstall_dialog_.get(); | 819 return extension_uninstall_dialog_.get(); |
906 } | 820 } |
OLD | NEW |