OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/auto_reset.h" | 10 #include "base/auto_reset.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 #include "grit/browser_resources.h" | 46 #include "grit/browser_resources.h" |
47 #include "grit/generated_resources.h" | 47 #include "grit/generated_resources.h" |
48 #include "net/base/escape.h" | 48 #include "net/base/escape.h" |
49 #include "ui/base/animation/animation.h" | 49 #include "ui/base/animation/animation.h" |
50 #include "ui/base/l10n/l10n_util.h" | 50 #include "ui/base/l10n/l10n_util.h" |
51 #include "ui/gfx/codec/png_codec.h" | 51 #include "ui/gfx/codec/png_codec.h" |
52 #include "webkit/glue/window_open_disposition.h" | 52 #include "webkit/glue/window_open_disposition.h" |
53 | 53 |
54 namespace { | 54 namespace { |
55 | 55 |
56 // The URL prefixes used by the NTP to signal when the web store or an app | |
57 // has launched so we can record the proper histogram. | |
58 const char* kPingLaunchAppByID = "record-app-launch-by-id"; | |
59 const char* kPingLaunchWebStore = "record-webstore-launch"; | |
60 const char* kPingLaunchAppByURL = "record-app-launch-by-url"; | |
61 | |
62 const UnescapeRule::Type kUnescapeRules = | 56 const UnescapeRule::Type kUnescapeRules = |
63 UnescapeRule::NORMAL | UnescapeRule::URL_SPECIAL_CHARS; | 57 UnescapeRule::NORMAL | UnescapeRule::URL_SPECIAL_CHARS; |
64 | 58 |
65 extension_misc::AppLaunchBucket ParseLaunchSource( | 59 extension_misc::AppLaunchBucket ParseLaunchSource( |
66 const std::string& launch_source) { | 60 const std::string& launch_source) { |
67 int bucket_num = extension_misc::APP_LAUNCH_BUCKET_INVALID; | 61 int bucket_num = extension_misc::APP_LAUNCH_BUCKET_INVALID; |
68 base::StringToInt(launch_source, &bucket_num); | 62 base::StringToInt(launch_source, &bucket_num); |
69 extension_misc::AppLaunchBucket bucket = | 63 extension_misc::AppLaunchBucket bucket = |
70 static_cast<extension_misc::AppLaunchBucket>(bucket_num); | 64 static_cast<extension_misc::AppLaunchBucket>(bucket_num); |
71 CHECK(bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 65 CHECK(bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
72 return bucket; | 66 return bucket; |
73 } | 67 } |
74 | 68 |
75 } // namespace | 69 } // namespace |
76 | 70 |
77 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) | 71 AppLauncherHandler::AppLauncherHandler(ExtensionService* extension_service) |
78 : extension_service_(extension_service), | 72 : extension_service_(extension_service), |
79 promo_active_(false), | |
80 ignore_changes_(false), | 73 ignore_changes_(false), |
81 attempted_bookmark_app_install_(false), | 74 attempted_bookmark_app_install_(false), |
82 has_loaded_apps_(false) { | 75 has_loaded_apps_(false) { |
83 } | 76 } |
84 | 77 |
85 AppLauncherHandler::~AppLauncherHandler() {} | 78 AppLauncherHandler::~AppLauncherHandler() {} |
86 | 79 |
87 // Serializes |notification| into a new DictionaryValue which the caller then | 80 // Serializes |notification| into a new DictionaryValue which the caller then |
88 // owns. | 81 // owns. |
89 static DictionaryValue* SerializeNotification( | 82 static DictionaryValue* SerializeNotification( |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 if (page_index < 0) { | 176 if (page_index < 0) { |
184 // Make sure every app has a page index (some predate the page index). | 177 // Make sure every app has a page index (some predate the page index). |
185 // The webstore app should be on the first page. | 178 // The webstore app should be on the first page. |
186 page_index = extension->id() == extension_misc::kWebStoreAppId ? | 179 page_index = extension->id() == extension_misc::kWebStoreAppId ? |
187 0 : prefs->GetNaturalAppPageIndex(); | 180 0 : prefs->GetNaturalAppPageIndex(); |
188 prefs->SetPageIndex(extension->id(), page_index); | 181 prefs->SetPageIndex(extension->id(), page_index); |
189 } | 182 } |
190 value->SetInteger("page_index", page_index); | 183 value->SetInteger("page_index", page_index); |
191 } | 184 } |
192 | 185 |
193 // TODO(estade): remove this. We record app launches via js calls rather than | |
194 // pings for ntp4. | |
195 // static | |
196 bool AppLauncherHandler::HandlePing(Profile* profile, const std::string& path) { | |
197 std::vector<std::string> params; | |
198 base::SplitString(path, '+', ¶ms); | |
199 | |
200 // Check if the user launched an app from the most visited or recently | |
201 // closed sections. | |
202 if (kPingLaunchAppByURL == params.at(0)) { | |
203 CHECK(params.size() == 3); | |
204 RecordAppLaunchByURL( | |
205 profile, params.at(1), ParseLaunchSource(params.at(2))); | |
206 return true; | |
207 } | |
208 | |
209 bool is_web_store_ping = kPingLaunchWebStore == params.at(0); | |
210 bool is_app_launch_ping = kPingLaunchAppByID == params.at(0); | |
211 | |
212 if (!is_web_store_ping && !is_app_launch_ping) | |
213 return false; | |
214 | |
215 CHECK(params.size() >= 2); | |
216 | |
217 bool is_promo_active = params.at(1) == "true"; | |
218 | |
219 // At this point, the user must have used the app launcher, so we hide the | |
220 // promo if its still displayed. | |
221 if (is_promo_active) { | |
222 DCHECK(profile->GetExtensionService()); | |
223 profile->GetExtensionService()->apps_promo()->ExpireDefaultApps(); | |
224 } | |
225 | |
226 if (is_web_store_ping) { | |
227 RecordWebStoreLaunch(is_promo_active); | |
228 } else { | |
229 CHECK(params.size() == 3); | |
230 RecordAppLaunchByID(is_promo_active, ParseLaunchSource(params.at(2))); | |
231 } | |
232 | |
233 return true; | |
234 } | |
235 | |
236 WebUIMessageHandler* AppLauncherHandler::Attach(WebUI* web_ui) { | 186 WebUIMessageHandler* AppLauncherHandler::Attach(WebUI* web_ui) { |
237 registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_NTP, | 187 registrar_.Add(this, chrome::NOTIFICATION_APP_INSTALLED_TO_NTP, |
238 content::Source<TabContents>(web_ui->tab_contents())); | 188 content::Source<TabContents>(web_ui->tab_contents())); |
239 return WebUIMessageHandler::Attach(web_ui); | 189 return WebUIMessageHandler::Attach(web_ui); |
240 } | 190 } |
241 | 191 |
242 void AppLauncherHandler::RegisterMessages() { | 192 void AppLauncherHandler::RegisterMessages() { |
243 web_ui_->RegisterMessageCallback("getApps", | 193 web_ui_->RegisterMessageCallback("getApps", |
244 base::Bind(&AppLauncherHandler::HandleGetApps, | 194 base::Bind(&AppLauncherHandler::HandleGetApps, |
245 base::Unretained(this))); | 195 base::Unretained(this))); |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 // expired. | 457 // expired. |
508 // b) Conceptually, it doesn't really make sense to count a | 458 // b) Conceptually, it doesn't really make sense to count a |
509 // prefchange-triggered refresh as a promo 'view'. | 459 // prefchange-triggered refresh as a promo 'view'. |
510 AppsPromo* apps_promo = extension_service_->apps_promo(); | 460 AppsPromo* apps_promo = extension_service_->apps_promo(); |
511 Profile* profile = Profile::FromWebUI(web_ui_); | 461 Profile* profile = Profile::FromWebUI(web_ui_); |
512 bool apps_promo_just_expired = false; | 462 bool apps_promo_just_expired = false; |
513 if (apps_promo->ShouldShowPromo(extension_service_->GetAppIds(), | 463 if (apps_promo->ShouldShowPromo(extension_service_->GetAppIds(), |
514 &apps_promo_just_expired)) { | 464 &apps_promo_just_expired)) { |
515 dictionary.SetBoolean("showPromo", true); | 465 dictionary.SetBoolean("showPromo", true); |
516 FillPromoDictionary(&dictionary); | 466 FillPromoDictionary(&dictionary); |
517 promo_active_ = true; | |
518 } else { | 467 } else { |
519 dictionary.SetBoolean("showPromo", false); | 468 dictionary.SetBoolean("showPromo", false); |
520 promo_active_ = false; | |
521 } | 469 } |
522 | 470 |
523 // If the default apps have just expired (user viewed them too many times with | 471 // If the default apps have just expired (user viewed them too many times with |
524 // no interaction), then we uninstall them and focus the recent sites section. | 472 // no interaction), then we uninstall them and focus the recent sites section. |
525 if (apps_promo_just_expired) { | 473 if (apps_promo_just_expired) { |
526 ignore_changes_ = true; | 474 ignore_changes_ = true; |
527 UninstallDefaultApps(); | 475 UninstallDefaultApps(); |
528 ignore_changes_ = false; | 476 ignore_changes_ = false; |
529 } | 477 } |
530 | 478 |
(...skipping 24 matching lines...) Expand all Loading... |
555 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, | 503 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, |
556 content::Source<Profile>(profile)); | 504 content::Source<Profile>(profile)); |
557 } | 505 } |
558 | 506 |
559 has_loaded_apps_ = true; | 507 has_loaded_apps_ = true; |
560 } | 508 } |
561 | 509 |
562 void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { | 510 void AppLauncherHandler::HandleLaunchApp(const ListValue* args) { |
563 std::string extension_id; | 511 std::string extension_id; |
564 double source = -1.0; | 512 double source = -1.0; |
| 513 std::string url; |
565 bool alt_key = false; | 514 bool alt_key = false; |
566 bool ctrl_key = false; | 515 bool ctrl_key = false; |
567 bool meta_key = false; | 516 bool meta_key = false; |
568 bool shift_key = false; | 517 bool shift_key = false; |
569 double button = 0.0; | 518 double button = 0.0; |
570 | 519 |
571 CHECK(args->GetString(0, &extension_id)); | 520 CHECK(args->GetString(0, &extension_id)); |
572 CHECK(args->GetDouble(1, &source)); | 521 CHECK(args->GetDouble(1, &source)); |
573 if (args->GetSize() > 2) { | 522 if (args->GetSize() > 2) |
574 CHECK(args->GetBoolean(2, &alt_key)); | 523 CHECK(args->GetString(2, &url)); |
575 CHECK(args->GetBoolean(3, &ctrl_key)); | 524 if (args->GetSize() > 3) { |
576 CHECK(args->GetBoolean(4, &meta_key)); | 525 CHECK(args->GetBoolean(3, &alt_key)); |
577 CHECK(args->GetBoolean(5, &shift_key)); | 526 CHECK(args->GetBoolean(4, &ctrl_key)); |
578 CHECK(args->GetDouble(6, &button)); | 527 CHECK(args->GetBoolean(5, &meta_key)); |
| 528 CHECK(args->GetBoolean(6, &shift_key)); |
| 529 CHECK(args->GetDouble(7, &button)); |
579 } | 530 } |
580 | 531 |
581 extension_misc::AppLaunchBucket launch_bucket = | 532 extension_misc::AppLaunchBucket launch_bucket = |
582 static_cast<extension_misc::AppLaunchBucket>( | 533 static_cast<extension_misc::AppLaunchBucket>( |
583 static_cast<int>(source)); | 534 static_cast<int>(source)); |
584 CHECK(launch_bucket >= 0 && | 535 CHECK(launch_bucket >= 0 && |
585 launch_bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 536 launch_bucket < extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
586 | 537 |
587 const Extension* extension = | 538 const Extension* extension = |
588 extension_service_->GetExtensionById(extension_id, false); | 539 extension_service_->GetExtensionById(extension_id, false); |
589 | 540 |
590 // Prompt the user to re-enable the application if disabled. | 541 // Prompt the user to re-enable the application if disabled. |
591 if (!extension) { | 542 if (!extension) { |
592 PromptToEnableApp(extension_id); | 543 PromptToEnableApp(extension_id); |
593 return; | 544 return; |
594 } | 545 } |
595 | 546 |
596 Profile* profile = extension_service_->profile(); | 547 Profile* profile = extension_service_->profile(); |
597 | 548 |
598 // If the user pressed special keys when clicking, override the saved | 549 // If the user pressed special keys when clicking, override the saved |
599 // preference for launch container. | 550 // preference for launch container. |
600 bool middle_button = (button == 1.0); | 551 bool middle_button = (button == 1.0); |
601 WindowOpenDisposition disposition = | 552 WindowOpenDisposition disposition = |
602 disposition_utils::DispositionFromClick(middle_button, alt_key, | 553 disposition_utils::DispositionFromClick(middle_button, alt_key, |
603 ctrl_key, meta_key, shift_key); | 554 ctrl_key, meta_key, shift_key); |
604 | 555 |
605 if (extension_id != extension_misc::kWebStoreAppId) { | 556 if (extension_id != extension_misc::kWebStoreAppId) { |
606 RecordAppLaunchByID(promo_active_, launch_bucket); | 557 RecordAppLaunchByID(launch_bucket); |
607 extension_service_->apps_promo()->ExpireDefaultApps(); | 558 extension_service_->apps_promo()->ExpireDefaultApps(); |
608 } else if (NewTabUI::NTP4Enabled()) { | 559 } else if (NewTabUI::NTP4Enabled()) { |
609 RecordWebStoreLaunch(promo_active_); | 560 RecordWebStoreLaunch(url.find("chrome-ntp-promo") != std::string::npos); |
610 } | 561 } |
611 | 562 |
612 if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) { | 563 if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) { |
613 // TODO(jamescook): Proper support for background tabs. | 564 // TODO(jamescook): Proper support for background tabs. |
614 Browser::OpenApplication( | 565 Browser::OpenApplication( |
615 profile, extension, extension_misc::LAUNCH_TAB, disposition); | 566 profile, extension, extension_misc::LAUNCH_TAB, GURL(url), disposition); |
616 } else if (disposition == NEW_WINDOW) { | 567 } else if (disposition == NEW_WINDOW) { |
617 // Force a new window open. | 568 // Force a new window open. |
618 Browser::OpenApplication( | 569 Browser::OpenApplication( |
619 profile, extension, extension_misc::LAUNCH_WINDOW, disposition); | 570 profile, extension, extension_misc::LAUNCH_WINDOW, GURL(url), |
| 571 disposition); |
620 } else { | 572 } else { |
621 // Look at preference to find the right launch container. If no preference | 573 // Look at preference to find the right launch container. If no preference |
622 // is set, launch as a regular tab. | 574 // is set, launch as a regular tab. |
623 extension_misc::LaunchContainer launch_container = | 575 extension_misc::LaunchContainer launch_container = |
624 extension_service_->extension_prefs()->GetLaunchContainer( | 576 extension_service_->extension_prefs()->GetLaunchContainer( |
625 extension, ExtensionPrefs::LAUNCH_REGULAR); | 577 extension, ExtensionPrefs::LAUNCH_REGULAR); |
626 | 578 |
627 // To give a more "launchy" experience when using the NTP launcher, we close | 579 // To give a more "launchy" experience when using the NTP launcher, we close |
628 // it automatically. | 580 // it automatically. |
629 Browser* browser = BrowserList::GetLastActiveWithProfile(profile); | 581 Browser* browser = BrowserList::GetLastActiveWithProfile(profile); |
630 TabContents* old_contents = NULL; | 582 TabContents* old_contents = NULL; |
631 if (browser) | 583 if (browser) |
632 old_contents = browser->GetSelectedTabContents(); | 584 old_contents = browser->GetSelectedTabContents(); |
633 | 585 |
634 TabContents* new_contents = Browser::OpenApplication( | 586 TabContents* new_contents = Browser::OpenApplication( |
635 profile, extension, launch_container, | 587 profile, extension, launch_container, GURL(url), |
636 old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB); | 588 old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB); |
637 | 589 |
638 // This will also destroy the handler, so do not perform any actions after. | 590 // This will also destroy the handler, so do not perform any actions after. |
639 if (new_contents != old_contents && browser && browser->tab_count() > 1) | 591 if (new_contents != old_contents && browser && browser->tab_count() > 1) |
640 browser->CloseTabContents(old_contents); | 592 browser->CloseTabContents(old_contents); |
641 } | 593 } |
642 } | 594 } |
643 | 595 |
644 void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) { | 596 void AppLauncherHandler::HandleSetLaunchType(const ListValue* args) { |
645 std::string extension_id; | 597 std::string extension_id; |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 | 855 |
904 if (!promo_active) return; | 856 if (!promo_active) return; |
905 | 857 |
906 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, | 858 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, |
907 extension_misc::PROMO_LAUNCH_WEB_STORE, | 859 extension_misc::PROMO_LAUNCH_WEB_STORE, |
908 extension_misc::PROMO_BUCKET_BOUNDARY); | 860 extension_misc::PROMO_BUCKET_BOUNDARY); |
909 } | 861 } |
910 | 862 |
911 // static | 863 // static |
912 void AppLauncherHandler::RecordAppLaunchByID( | 864 void AppLauncherHandler::RecordAppLaunchByID( |
913 bool promo_active, extension_misc::AppLaunchBucket bucket) { | 865 extension_misc::AppLaunchBucket bucket) { |
914 CHECK(bucket != extension_misc::APP_LAUNCH_BUCKET_INVALID); | 866 CHECK(bucket != extension_misc::APP_LAUNCH_BUCKET_INVALID); |
915 | 867 |
916 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, bucket, | 868 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppLaunchHistogram, bucket, |
917 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); | 869 extension_misc::APP_LAUNCH_BUCKET_BOUNDARY); |
918 | |
919 if (!promo_active) return; | |
920 | |
921 UMA_HISTOGRAM_ENUMERATION(extension_misc::kAppsPromoHistogram, | |
922 extension_misc::PROMO_LAUNCH_APP, | |
923 extension_misc::PROMO_BUCKET_BOUNDARY); | |
924 } | 870 } |
925 | 871 |
926 // static | 872 // static |
927 void AppLauncherHandler::RecordAppLaunchByURL( | 873 void AppLauncherHandler::RecordAppLaunchByURL( |
928 Profile* profile, | 874 Profile* profile, |
929 std::string escaped_url, | 875 std::string escaped_url, |
930 extension_misc::AppLaunchBucket bucket) { | 876 extension_misc::AppLaunchBucket bucket) { |
931 CHECK(bucket != extension_misc::APP_LAUNCH_BUCKET_INVALID); | 877 CHECK(bucket != extension_misc::APP_LAUNCH_BUCKET_INVALID); |
932 | 878 |
933 GURL url(net::UnescapeURLComponent(escaped_url, kUnescapeRules)); | 879 GURL url(net::UnescapeURLComponent(escaped_url, kUnescapeRules)); |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1049 | 995 |
1050 void AppLauncherHandler::UninstallDefaultApps() { | 996 void AppLauncherHandler::UninstallDefaultApps() { |
1051 AppsPromo* apps_promo = extension_service_->apps_promo(); | 997 AppsPromo* apps_promo = extension_service_->apps_promo(); |
1052 const ExtensionIdSet& app_ids = apps_promo->old_default_apps(); | 998 const ExtensionIdSet& app_ids = apps_promo->old_default_apps(); |
1053 for (ExtensionIdSet::const_iterator iter = app_ids.begin(); | 999 for (ExtensionIdSet::const_iterator iter = app_ids.begin(); |
1054 iter != app_ids.end(); ++iter) { | 1000 iter != app_ids.end(); ++iter) { |
1055 if (extension_service_->GetExtensionById(*iter, true)) | 1001 if (extension_service_->GetExtensionById(*iter, true)) |
1056 extension_service_->UninstallExtension(*iter, false, NULL); | 1002 extension_service_->UninstallExtension(*iter, false, NULL); |
1057 } | 1003 } |
1058 } | 1004 } |
OLD | NEW |