summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:11:26 +0000
committerxiyuan@chromium.org <xiyuan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:11:26 +0000
commit919b2f83216c7a9f07d2e3569ad74ab8c1a06675 (patch)
tree7d190452fedf4dc798acfc32d2dd27afb241bf82 /chrome/browser
parentd9440363af79abd7a4638b6949cd601449721551 (diff)
downloadchromium_src-919b2f83216c7a9f07d2e3569ad74ab8c1a06675.zip
chromium_src-919b2f83216c7a9f07d2e3569ad74ab8c1a06675.tar.gz
chromium_src-919b2f83216c7a9f07d2e3569ad74ab8c1a06675.tar.bz2
app_list: Initial version of the start page.
- Add a StartPageService PKS that holds the start page contents and app recommendation generator; - Implement the initial app recommendation using the 4 most recent apps; - Expose the start page contents in AppListViewDelegate; - Update AppsGridView could to handle start page case; - Implement a WebUI for the start page contents; - Put the start page feature behind a flag; - Add a switch to override the start page url for easier mocking; BUG=268660,268661 Review URL: https://codereview.chromium.org/25152002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226940 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/about_flags.cc9
-rw-r--r--chrome/browser/browser_resources.grd5
-rw-r--r--chrome/browser/chromeos/login/login_utils.cc4
-rw-r--r--chrome/browser/extensions/api/app_runtime/app_runtime_api.cc5
-rw-r--r--chrome/browser/extensions/extension_prefs.cc25
-rw-r--r--chrome/browser/extensions/extension_prefs.h5
-rw-r--r--chrome/browser/extensions/install_observer.h2
-rw-r--r--chrome/browser/resources/app_list/recommended_apps.css31
-rw-r--r--chrome/browser/resources/app_list/recommended_apps.js90
-rw-r--r--chrome/browser/resources/app_list/start_page.css26
-rw-r--r--chrome/browser/resources/app_list/start_page.html18
-rw-r--r--chrome/browser/resources/app_list/start_page.js72
-rw-r--r--chrome/browser/ui/app_list/app_list_service.h2
-rw-r--r--chrome/browser/ui/app_list/app_list_view_delegate.cc10
-rw-r--r--chrome/browser/ui/app_list/app_list_view_delegate.h1
-rw-r--r--chrome/browser/ui/app_list/recommended_apps.cc139
-rw-r--r--chrome/browser/ui/app_list/recommended_apps.h72
-rw-r--r--chrome/browser/ui/app_list/recommended_apps_observer.h22
-rw-r--r--chrome/browser/ui/app_list/start_page_service.cc123
-rw-r--r--chrome/browser/ui/app_list/start_page_service.h63
-rw-r--r--chrome/browser/ui/extensions/application_launch.cc1
-rw-r--r--chrome/browser/ui/webui/app_list/start_page_browsertest.js65
-rw-r--r--chrome/browser/ui/webui/app_list/start_page_handler.cc112
-rw-r--r--chrome/browser/ui/webui/app_list/start_page_handler.h49
-rw-r--r--chrome/browser/ui/webui/app_list/start_page_ui.cc39
-rw-r--r--chrome/browser/ui/webui/app_list/start_page_ui.h28
-rw-r--r--chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc8
27 files changed, 1025 insertions, 1 deletions
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ee4db2e..5ab1999 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1707,6 +1707,15 @@ const Experiment kExperiments[] = {
kOsMac | kOsWin,
SINGLE_VALUE_TYPE(switches::kDisableAppList)
},
+#if defined(ENABLE_APP_LIST)
+ {
+ "enable-app-launcher-start-page",
+ IDS_FLAGS_ENABLE_APP_LIST_START_PAGE_NAME,
+ IDS_FLAGS_ENABLE_APP_LIST_START_PAGE_DESCRIPTION,
+ kOsWin | kOsCrOS,
+ SINGLE_VALUE_TYPE(switches::kShowAppListStartPage)
+ },
+#endif
#if defined(OS_CHROMEOS)
{
"disable-user-image-sync",
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 0435551..43eaafe 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -24,6 +24,11 @@
<structure name="IDR_ABOUT_WELCOME_HTML" file="resources\about_welcome_android\about_welcome_android.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_ABOUT_WELCOME_CSS" file="resources\about_welcome_android\about_welcome_android.css" flattenhtml="true" type="chrome_html" />
</if>
+ <if expr="pp_ifdef('enable_app_list')">
+ <structure name="IDR_APP_LIST_START_PAGE_CSS" file="resources\app_list\start_page.css" flattenhtml="true" type="chrome_html" />
+ <structure name="IDR_APP_LIST_START_PAGE_HTML" file="resources\app_list\start_page.html" flattenhtml="true" type="chrome_html" />
+ <structure name="IDR_APP_LIST_START_PAGE_JS" file="resources\app_list\start_page.js" flattenhtml="true" type="chrome_html" />
+ </if>
<if expr="pp_ifdef('chromeos')">
<structure name="IDR_DEMO_USER_LOGIN_HTML" file="resources\chromeos\login\demo_user_login.html" flattenhtml="true" type="chrome_html" />
<structure name="IDR_DEMO_USER_LOGIN_JS" file="resources\chromeos\login\demo_user_login.js" flattenhtml="true" type="chrome_html" />
diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc
index e70f78e..87202ab 100644
--- a/chrome/browser/chromeos/login/login_utils.cc
+++ b/chrome/browser/chromeos/login/login_utils.cc
@@ -58,6 +58,7 @@
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/ui/app_list/start_page_service.h"
#include "chrome/browser/ui/startup/startup_browser_creator.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
@@ -296,6 +297,9 @@ void LoginUtilsImpl::DoBrowserLaunch(Profile* profile,
first_run,
&return_code);
+ // Triggers app launcher start page service to load start page web contents.
+ app_list::StartPageService::Get(profile);
+
// Mark login host for deletion after browser starts. This
// guarantees that the message loop will be referenced by the
// browser before it is dereferenced by the login host.
diff --git a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
index ab955db..a0725b7 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
@@ -8,9 +8,12 @@
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/event_router.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/app_runtime.h"
@@ -46,6 +49,8 @@ void DispatchOnLaunchedEventImpl(const std::string& extension_id,
event->restrict_to_profile = profile;
system->event_router()->DispatchEventWithLazyListener(extension_id,
event.Pass());
+ system->extension_service()->extension_prefs()->SetLastLaunchTime(
+ extension_id, base::Time::Now());
}
} // anonymous namespace
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 3c66561..a9d5d0e 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -184,6 +184,9 @@ const char kPrefWasInstalledByDefault[] = "was_installed_by_default";
// Key for Geometry Cache preference.
const char kPrefGeometryCache[] = "geometry_cache";
+// A preference that indicates when an extension is last launched.
+const char kPrefLastLaunchTime[] = "last_launch_time";
+
// Provider of write access to a dictionary storing extension prefs.
class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
public:
@@ -1549,6 +1552,28 @@ base::Time ExtensionPrefs::GetInstallTime(
return base::Time::FromInternalValue(install_time_i64);
}
+base::Time ExtensionPrefs::GetLastLaunchTime(
+ const std::string& extension_id) const {
+ const DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return base::Time();
+
+ std::string launch_time_str;
+ if (!extension->GetString(kPrefLastLaunchTime, &launch_time_str))
+ return base::Time();
+ int64 launch_time_i64 = 0;
+ if (!base::StringToInt64(launch_time_str, &launch_time_i64))
+ return base::Time();
+ return base::Time::FromInternalValue(launch_time_i64);
+}
+
+void ExtensionPrefs::SetLastLaunchTime(const std::string& extension_id,
+ const base::Time& time) {
+ DCHECK(Extension::IdIsValid(extension_id));
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ SaveTime(update.Get(), kPrefLastLaunchTime, time);
+}
+
void ExtensionPrefs::GetExtensions(ExtensionIdList* out) {
CHECK(out);
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 1a03127..c8e3c48 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -464,6 +464,11 @@ class ExtensionPrefs : public ExtensionScopedPrefs,
// found.
base::Time GetInstallTime(const std::string& extension_id) const;
+ // Gets/sets the last launch time of an extension.
+ base::Time GetLastLaunchTime(const std::string& extension_id) const;
+ void SetLastLaunchTime(const std::string& extension_id,
+ const base::Time& time);
+
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
bool extensions_disabled() { return extensions_disabled_; }
diff --git a/chrome/browser/extensions/install_observer.h b/chrome/browser/extensions/install_observer.h
index 95370da..cc79df0 100644
--- a/chrome/browser/extensions/install_observer.h
+++ b/chrome/browser/extensions/install_observer.h
@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_EXTENSIONS_INSTALL_OBSERVER_H_
#define CHROME_BROWSER_EXTENSIONS_INSTALL_OBSERVER_H_
+#include <string>
+
namespace gfx {
class ImageSkia;
}
diff --git a/chrome/browser/resources/app_list/recommended_apps.css b/chrome/browser/resources/app_list/recommended_apps.css
new file mode 100644
index 0000000..b02c496
--- /dev/null
+++ b/chrome/browser/resources/app_list/recommended_apps.css
@@ -0,0 +1,31 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.recommended-apps {
+ -webkit-align-items: center;
+ -webkit-justify-content: space-around;
+ display: -webkit-flex;
+ padding: 0 10px;
+}
+
+.app {
+ background-position: center 5px;
+ background-repeat: no-repeat;
+ background-size: 48px;
+ color: rgb(90, 90, 90);
+ cursor: default;
+ font-size: 11px;
+ font-weight: bold;
+ height: 20px;
+ overflow: hidden;
+ padding-top: 58px;
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 88px;
+}
+
+.app:hover {
+ background-color: rgb(230, 230, 230);
+}
diff --git a/chrome/browser/resources/app_list/recommended_apps.js b/chrome/browser/resources/app_list/recommended_apps.js
new file mode 100644
index 0000000..d5fe706
--- /dev/null
+++ b/chrome/browser/resources/app_list/recommended_apps.js
@@ -0,0 +1,90 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview Implement the recommended apps card in the launcher start page.
+ */
+
+cr.define('appList.startPage', function() {
+ 'use strict';
+
+ /**
+ * Create a view with icon and label for the given app data.
+ * @constructor
+ * @extends {HTMLDivElement}
+ */
+ var AppItemView = cr.ui.define('div');
+
+ AppItemView.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /**
+ * The app id of the app displayed by this view. Used to launch
+ * the app when the view is clicked.
+ * @type {string}
+ */
+ appId: '',
+
+ /**
+ * Sets the icon URL to display the app icon.
+ * @type {string}
+ */
+ set iconUrl(url) {
+ this.style.backgroundImage = 'url(' + url + ')';
+ },
+
+ /**
+ * Sets the text title.
+ * @type {string}
+ */
+ set textTitle(title) {
+ this.textContent = title;
+ },
+
+ /** @override */
+ decorate: function() {
+ this.className = 'app';
+ this.addEventListener('click', this.handleClick_.bind(this));
+ },
+
+ /**
+ * Handles 'click' event.
+ * @private
+ */
+ handleClick_: function() {
+ assert(this.appId);
+ chrome.send('launchApp', [this.appId]);
+ }
+ };
+
+ /**
+ * Create recommended apps card.
+ * @constructor
+ * @extends {HTMLDivElement}
+ */
+ var RecommendedApps = cr.ui.define('div');
+
+ RecommendedApps.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /** @override */
+ decorate: function() {
+ this.className = 'recommended-apps';
+ },
+
+ /**
+ * Sets the apps to be displayed in this card.
+ */
+ setApps: function(apps) {
+ this.textContent = '';
+ for (var i = 0; i < apps.length; ++i) {
+ this.appendChild(new AppItemView(apps[i]));
+ }
+ }
+ };
+
+ return {
+ RecommendedApps: RecommendedApps
+ };
+});
diff --git a/chrome/browser/resources/app_list/start_page.css b/chrome/browser/resources/app_list/start_page.css
new file mode 100644
index 0000000..cd8f3c0
--- /dev/null
+++ b/chrome/browser/resources/app_list/start_page.css
@@ -0,0 +1,26 @@
+/* Copyright 2013 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+html,
+body,
+#start-page {
+ background-color: rgb(245, 245, 245);
+ height: 100%;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ width: 100%;
+}
+
+#start-page {
+ -webkit-align-items: stretch;
+ -webkit-flex-direction: column;
+ -webkit-justify-content: flex-start;
+ -webkit-user-select: none;
+ box-sizing: border-box;
+ display: -webkit-flex;
+ padding: 10px;
+}
+
+<include src="recommended_apps.css"/>
diff --git a/chrome/browser/resources/app_list/start_page.html b/chrome/browser/resources/app_list/start_page.html
new file mode 100644
index 0000000..8b86ae1
--- /dev/null
+++ b/chrome/browser/resources/app_list/start_page.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html i18n-values="dir:textdirection">
+<head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="chrome://app-list/start_page.css">
+ <script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="chrome://resources/js/cr/ui.js"></script>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="chrome://app-list/strings.js"></script>
+ <script src="chrome://app-list/start_page.js"></script>
+</head>
+
+<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+ <div id="start-page"></div>
+ <script src="chrome://resources/js/i18n_template2.js"></script>
+</body>
+</html>
diff --git a/chrome/browser/resources/app_list/start_page.js b/chrome/browser/resources/app_list/start_page.js
new file mode 100644
index 0000000..942b3a9
--- /dev/null
+++ b/chrome/browser/resources/app_list/start_page.js
@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview App launcher start page implementation.
+ */
+
+<include src="recommended_apps.js"/>
+
+cr.define('appList.startPage', function() {
+ 'use strict';
+
+ /**
+ * Creates a StartPage object.
+ * @constructor
+ * @extends {HTMLDivElement}
+ */
+ var StartPage = cr.ui.define('div');
+
+ StartPage.prototype = {
+ __proto__: HTMLDivElement.prototype,
+
+ /**
+ * Instance of the recommended apps card.
+ * @type {appsList.startPage.RecommendedApps}
+ * @private
+ */
+ recommendedApps_: null,
+
+ /** @override */
+ decorate: function() {
+ this.recommendedApps_ = new appList.startPage.RecommendedApps();
+ this.appendChild(this.recommendedApps_);
+ },
+
+ /**
+ * Sets the recommended apps.
+ * @param {!Array.<!{appId: string,
+ * iconUrl: string,
+ * textTitle: string}>} apps An array of app info
+ * dictionary to be displayed in the AppItemView.
+ */
+ setRecommendedApps: function(apps) {
+ this.recommendedApps_.setApps(apps);
+ }
+ };
+
+ /**
+ * Initialize the page.
+ */
+ function initialize() {
+ StartPage.decorate($('start-page'));
+ chrome.send('initialize');
+ }
+
+ /**
+ * Sets the recommended apps.
+ * @param {Array.<Object>} apps An array of app info dictionary.
+ */
+ function setRecommendedApps(apps) {
+ $('start-page').setRecommendedApps(apps);
+ }
+
+ return {
+ initialize: initialize,
+ setRecommendedApps: setRecommendedApps
+ };
+});
+
+document.addEventListener('contextmenu', function(e) { e.preventDefault(); });
+document.addEventListener('DOMContentLoaded', appList.startPage.initialize);
diff --git a/chrome/browser/ui/app_list/app_list_service.h b/chrome/browser/ui/app_list/app_list_service.h
index 60144f0..ddbd76a 100644
--- a/chrome/browser/ui/app_list/app_list_service.h
+++ b/chrome/browser/ui/app_list/app_list_service.h
@@ -77,7 +77,7 @@ class AppListService {
// Get the window the app list is in, or NULL if the app list isn't visible.
virtual gfx::NativeWindow GetAppListWindow() = 0;
- // Exposed to allow testing of the controller delegate.
+ // Creates a platform specific AppListControllerDelegate.
virtual AppListControllerDelegate* CreateControllerDelegate() = 0;
protected:
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index 57b0253..8321882 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -19,6 +19,7 @@
#include "chrome/browser/ui/app_list/apps_model_builder.h"
#include "chrome/browser/ui/app_list/chrome_app_list_item.h"
#include "chrome/browser/ui/app_list/search/search_controller.h"
+#include "chrome/browser/ui/app_list/start_page_service.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/host_desktop.h"
@@ -291,3 +292,12 @@ void AppListViewDelegate::OnProfileNameChanged(
const base::string16& old_profile_name) {
OnProfileChanged();
}
+
+content::WebContents* AppListViewDelegate::GetStartPageContents() {
+ app_list::StartPageService* service =
+ app_list::StartPageService::Get(profile_);
+ if (!service)
+ return NULL;
+
+ return service->contents();
+}
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index c1f3a95..2a43cd4 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -80,6 +80,7 @@ class AppListViewDelegate : public app_list::AppListViewDelegate,
virtual void OpenFeedback() OVERRIDE;
virtual void ShowForProfileByPath(
const base::FilePath& profile_path) OVERRIDE;
+ virtual content::WebContents* GetStartPageContents() OVERRIDE;
// Overridden from content::NotificationObserver:
virtual void Observe(int type,
diff --git a/chrome/browser/ui/app_list/recommended_apps.cc b/chrome/browser/ui/app_list/recommended_apps.cc
new file mode 100644
index 0000000..5b32f10
--- /dev/null
+++ b/chrome/browser/ui/app_list/recommended_apps.cc
@@ -0,0 +1,139 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/recommended_apps.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/install_tracker.h"
+#include "chrome/browser/extensions/install_tracker_factory.h"
+#include "chrome/browser/ui/app_list/recommended_apps_observer.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
+
+namespace app_list {
+
+namespace {
+
+struct AppSortInfo {
+ AppSortInfo() : app(NULL) {}
+ AppSortInfo(const extensions::Extension* app,
+ const base::Time& last_launch_time)
+ : app(app), last_launch_time(last_launch_time) {}
+
+ const extensions::Extension* app;
+ base::Time last_launch_time;
+};
+
+bool AppLaunchedMoreRecent(const AppSortInfo& app1, const AppSortInfo& app2) {
+ return app1.last_launch_time > app2.last_launch_time;
+}
+
+} // namespace
+
+RecommendedApps::RecommendedApps(Profile* profile) : profile_(profile) {
+ extensions::InstallTrackerFactory::GetForProfile(profile_)->AddObserver(this);
+
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile_)->extension_service();
+ extensions::ExtensionPrefs* prefs = service->extension_prefs();
+ pref_change_registrar_.Init(prefs->pref_service());
+ pref_change_registrar_.Add(prefs::kExtensionsPref,
+ base::Bind(&RecommendedApps::Update,
+ base::Unretained(this)));
+
+ Update();
+}
+
+RecommendedApps::~RecommendedApps() {
+ extensions::InstallTrackerFactory::GetForProfile(profile_)
+ ->RemoveObserver(this);
+}
+
+void RecommendedApps::AddObserver(RecommendedAppsObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void RecommendedApps::RemoveObserver(RecommendedAppsObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void RecommendedApps::Update() {
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile_)->extension_service();
+ extensions::ExtensionPrefs* prefs = service->extension_prefs();
+
+ std::vector<AppSortInfo> sorted_apps;
+ const ExtensionSet* extensions = service->extensions();
+ for (ExtensionSet::const_iterator app = extensions->begin();
+ app != extensions->end(); ++app) {
+ if (!(*app)->ShouldDisplayInAppLauncher())
+ continue;
+
+ sorted_apps.push_back(
+ AppSortInfo(app->get(), prefs->GetLastLaunchTime((*app)->id())));
+ }
+
+ std::sort(sorted_apps.begin(), sorted_apps.end(), &AppLaunchedMoreRecent);
+
+ const size_t kMaxRecommendedApps = 4;
+ sorted_apps.resize(std::min(kMaxRecommendedApps, sorted_apps.size()));
+
+ Apps new_recommends;
+ for (size_t i = 0; i < sorted_apps.size(); ++i)
+ new_recommends.push_back(sorted_apps[i].app);
+
+ const bool changed = apps_.size() != new_recommends.size() ||
+ !std::equal(apps_.begin(), apps_.end(), new_recommends.begin());
+ if (changed) {
+ apps_.swap(new_recommends);
+ FOR_EACH_OBSERVER(
+ RecommendedAppsObserver, observers_, OnRecommendedAppsChanged());
+ }
+}
+
+void RecommendedApps::OnBeginExtensionInstall(const std::string& extension_id,
+ const std::string& extension_name,
+ const gfx::ImageSkia& installing_icon,
+ bool is_app,
+ bool is_platform_app) {}
+
+void RecommendedApps::OnDownloadProgress(const std::string& extension_id,
+ int percent_downloaded) {}
+
+void RecommendedApps::OnInstallFailure(const std::string& extension_id) {}
+
+void RecommendedApps::OnExtensionInstalled(
+ const extensions::Extension* extension) {
+ Update();
+}
+
+void RecommendedApps::OnExtensionLoaded(
+ const extensions::Extension* extension) {
+ Update();
+}
+
+void RecommendedApps::OnExtensionUnloaded(
+ const extensions::Extension* extension) {
+ Update();
+}
+
+void RecommendedApps::OnExtensionUninstalled(
+ const extensions::Extension* extension) {
+ Update();
+}
+
+void RecommendedApps::OnAppsReordered() {}
+
+void RecommendedApps::OnAppInstalledToAppList(
+ const std::string& extension_id) {}
+
+void RecommendedApps::OnShutdown() {}
+
+} // namespace app_list
diff --git a/chrome/browser/ui/app_list/recommended_apps.h b/chrome/browser/ui/app_list/recommended_apps.h
new file mode 100644
index 0000000..c89f39a
--- /dev/null
+++ b/chrome/browser/ui/app_list/recommended_apps.h
@@ -0,0 +1,72 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_H_
+#define CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/extensions/install_observer.h"
+
+class Profile;
+
+namespace app_list {
+
+class RecommendedAppsObserver;
+
+// A class that maintains a list of recommended apps by watching changes
+// to app state.
+class RecommendedApps : public extensions::InstallObserver {
+ public:
+ typedef std::vector<scoped_refptr<const extensions::Extension> > Apps;
+
+ explicit RecommendedApps(Profile* profile);
+ virtual ~RecommendedApps();
+
+ void AddObserver(RecommendedAppsObserver* observer);
+ void RemoveObserver(RecommendedAppsObserver* observer);
+
+ const Apps& apps() const { return apps_; }
+
+ private:
+ void Update();
+
+ // extensions::InstallObserver overrides:
+ virtual void OnBeginExtensionInstall(const std::string& extension_id,
+ const std::string& extension_name,
+ const gfx::ImageSkia& installing_icon,
+ bool is_app,
+ bool is_platform_app) OVERRIDE;
+ virtual void OnDownloadProgress(const std::string& extension_id,
+ int percent_downloaded) OVERRIDE;
+ virtual void OnInstallFailure(const std::string& extension_id) OVERRIDE;
+ virtual void OnExtensionInstalled(
+ const extensions::Extension* extension) OVERRIDE;
+ virtual void OnExtensionLoaded(
+ const extensions::Extension* extension) OVERRIDE;
+ virtual void OnExtensionUnloaded(
+ const extensions::Extension* extension) OVERRIDE;
+ virtual void OnExtensionUninstalled(
+ const extensions::Extension* extension) OVERRIDE;
+ virtual void OnAppsReordered() OVERRIDE;
+ virtual void OnAppInstalledToAppList(
+ const std::string& extension_id) OVERRIDE;
+ virtual void OnShutdown() OVERRIDE;
+
+ Profile* profile_;
+ PrefChangeRegistrar pref_change_registrar_;
+
+ Apps apps_;
+ ObserverList<RecommendedAppsObserver, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecommendedApps);
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_H_
diff --git a/chrome/browser/ui/app_list/recommended_apps_observer.h b/chrome/browser/ui/app_list/recommended_apps_observer.h
new file mode 100644
index 0000000..ab8e76a
--- /dev/null
+++ b/chrome/browser/ui/app_list/recommended_apps_observer.h
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_OBSERVER_H_
+#define CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_OBSERVER_H_
+
+namespace app_list {
+
+// An interface for observing RecommendedApps change.
+class RecommendedAppsObserver {
+ public:
+ // Invoked when RecommendedApps changed.
+ virtual void OnRecommendedAppsChanged() = 0;
+
+ protected:
+ virtual ~RecommendedAppsObserver() {}
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_APP_LIST_RECOMMENDED_APPS_OBSERVER_H_
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
new file mode 100644
index 0000000..6c9d35f
--- /dev/null
+++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/start_page_service.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/memory/singleton.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/install_tracker_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/recommended_apps.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/url_constants.h"
+#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/web_contents.h"
+
+namespace app_list {
+
+class StartPageService::Factory : public BrowserContextKeyedServiceFactory {
+ public:
+ static StartPageService* GetForProfile(Profile* profile) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kShowAppListStartPage)) {
+ return NULL;
+ }
+
+ return static_cast<StartPageService*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+ }
+
+ static Factory* GetInstance() {
+ return Singleton<Factory>::get();
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<Factory>;
+
+ Factory()
+ : BrowserContextKeyedServiceFactory(
+ "AppListStartPageService",
+ BrowserContextDependencyManager::GetInstance()) {
+ DependsOn(extensions::ExtensionSystemFactory::GetInstance());
+ DependsOn(extensions::InstallTrackerFactory::GetInstance());
+ }
+
+ virtual ~Factory() {}
+
+ // BrowserContextKeyedServiceFactory overrides:
+ virtual BrowserContextKeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const OVERRIDE {
+ Profile* profile = static_cast<Profile*>(context);
+ return new StartPageService(profile);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+class StartPageService::ExitObserver : public content::NotificationObserver {
+ public:
+ explicit ExitObserver(StartPageService* service) : service_(service) {
+ registrar_.Add(this,
+ chrome::NOTIFICATION_APP_TERMINATING,
+ content::NotificationService::AllSources());
+ }
+ virtual ~ExitObserver() {}
+
+ private:
+ // content::NotificationObserver
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE {
+ DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
+ service_->Shutdown();
+ }
+
+ StartPageService* service_; // Owner of this class.
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExitObserver);
+};
+
+// static
+StartPageService* StartPageService::Get(Profile* profile) {
+ return Factory::GetForProfile(profile);
+}
+
+StartPageService::StartPageService(Profile* profile)
+ : profile_(profile),
+ exit_observer_(new ExitObserver(this)),
+ recommended_apps_(new RecommendedApps(profile)) {
+ contents_.reset(content::WebContents::Create(
+ content::WebContents::CreateParams(profile_)));
+
+ GURL url(chrome::kChromeUIAppListStartPageURL);
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kAppListStartPageURL)) {
+ url = GURL(
+ command_line->GetSwitchValueASCII(switches::kAppListStartPageURL));
+ }
+
+ contents_->GetController().LoadURL(
+ url,
+ content::Referrer(),
+ content::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ std::string());
+}
+
+StartPageService::~StartPageService() {}
+
+void StartPageService::Shutdown() {
+ contents_.reset();
+}
+
+} // namespace app_list
diff --git a/chrome/browser/ui/app_list/start_page_service.h b/chrome/browser/ui/app_list/start_page_service.h
new file mode 100644
index 0000000..1b7db3b
--- /dev/null
+++ b/chrome/browser/ui/app_list/start_page_service.h
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_START_PAGE_SERVICE_H_
+#define CHROME_BROWSER_UI_APP_LIST_START_PAGE_SERVICE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
+#include "content/public/browser/web_contents.h"
+
+namespace extensions {
+class Extension;
+}
+
+class Profile;
+
+namespace app_list {
+
+class RecommendedApps;
+
+// StartPageService collects data to be displayed in app list's start page
+// and hosts the start page contents.
+class StartPageService : public BrowserContextKeyedService {
+ public:
+ typedef std::vector<scoped_refptr<const extensions::Extension> >
+ ExtensionList;
+ // Gets the instance for the given profile.
+ static StartPageService* Get(Profile* profile);
+
+ content::WebContents* contents() { return contents_.get(); }
+ RecommendedApps* recommended_apps() { return recommended_apps_.get(); }
+
+ private:
+ // A BrowserContextKeyedServiceFactory for this service.
+ class Factory;
+
+ // ExitObserver to shutdown the service on exiting. WebContents depends
+ // on the profile and needs to be closed before the profile and its
+ // keyed service shutdown.
+ class ExitObserver;
+
+ explicit StartPageService(Profile* profile);
+ virtual ~StartPageService();
+
+ // BrowserContextKeyedService overrides:
+ virtual void Shutdown() OVERRIDE;
+
+ Profile* profile_;
+ scoped_ptr<content::WebContents> contents_;
+ scoped_ptr<ExitObserver> exit_observer_;
+ scoped_ptr<RecommendedApps> recommended_apps_;
+
+ DISALLOW_COPY_AND_ASSIGN(StartPageService);
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_APP_LIST_START_PAGE_SERVICE_H_
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 92c25e7..8e96a5e 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -335,6 +335,7 @@ WebContents* OpenEnabledApplication(const AppLaunchParams& params) {
ExtensionPrefs* prefs = extensions::ExtensionSystem::Get(profile)->
extension_service()->extension_prefs();
prefs->SetActiveBit(extension->id(), true);
+ prefs->SetLastLaunchTime(extension->id(), base::Time::Now());
UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
diff --git a/chrome/browser/ui/webui/app_list/start_page_browsertest.js b/chrome/browser/ui/webui/app_list/start_page_browsertest.js
new file mode 100644
index 0000000..1fa27db
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/start_page_browsertest.js
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * TestFixture for kiosk app settings WebUI testing.
+ * @extends {testing.Test}
+ * @constructor
+ **/
+function AppListStartPageWebUITest() {}
+
+AppListStartPageWebUITest.prototype = {
+ __proto__: testing.Test.prototype,
+
+ /**
+ * Browser to app launcher start page.
+ */
+ browsePreload: 'chrome://app-list/',
+
+ /**
+ * Recommend apps data.
+ * @private
+ */
+ recommendedApps_: [
+ {
+ 'appId': 'app_id_1',
+ 'textTitle': 'app 1',
+ 'iconUrl': 'icon_url_1'
+ },
+ {
+ 'appId': 'app_id_2',
+ 'textTitle': 'app 2',
+ 'iconUrl': 'icon_url_2'
+ },
+ ],
+
+ /** @override */
+ preLoad: function() {
+ this.makeAndRegisterMockHandler(['initialize', 'launchApp']);
+ this.mockHandler.stubs().initialize().will(callFunction(function() {
+ appList.startPage.setRecommendedApps(this.recommendedApps_);
+ }.bind(this)));
+ this.mockHandler.stubs().launchApp(ANYTHING);
+ }
+};
+
+TEST_F('AppListStartPageWebUITest', 'Basic', function() {
+ assertEquals(this.browsePreload, document.location.href);
+
+ var recommendedApp = $('start-page').querySelector('.recommended-apps');
+ assertEquals(this.recommendedApps_.length, recommendedApp.childElementCount);
+ for (var i = 0; i < recommendedApp.childElementCount; ++i) {
+ assertEquals(this.recommendedApps_[i].appId,
+ recommendedApp.children[i].appId);
+ }
+});
+
+TEST_F('AppListStartPageWebUITest', 'ClickToLaunch', function() {
+ var recommendedApp = $('start-page').querySelector('.recommended-apps');
+ for (var i = 0; i < recommendedApp.childElementCount; ++i) {
+ this.mockHandler.expects(once()).launchApp(
+ [this.recommendedApps_[i].appId]);
+ cr.dispatchSimpleEvent(recommendedApp.children[i], 'click');
+ }
+});
diff --git a/chrome/browser/ui/webui/app_list/start_page_handler.cc b/chrome/browser/ui/webui/app_list/start_page_handler.cc
new file mode 100644
index 0000000..a7be1ee
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/start_page_handler.cc
@@ -0,0 +1,112 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/app_list/start_page_handler.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/recommended_apps.h"
+#include "chrome/browser/ui/app_list/start_page_service.h"
+#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_icon_set.h"
+#include "content/public/browser/web_ui.h"
+#include "ui/events/event_constants.h"
+
+namespace app_list {
+
+namespace {
+
+scoped_ptr<base::DictionaryValue> CreateAppInfo(
+ const extensions::Extension* app) {
+ scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
+ dict->SetString("appId", app->id());
+ dict->SetString("textTitle", app->short_name());
+ dict->SetString("title", app->name());
+
+ const bool grayscale = false;
+ bool icon_exists = true;
+ GURL icon_url = extensions::ExtensionIconSource::GetIconURL(
+ app,
+ extension_misc::EXTENSION_ICON_MEDIUM,
+ ExtensionIconSet::MATCH_BIGGER,
+ grayscale,
+ &icon_exists);
+ dict->SetString("iconUrl", icon_url.spec());
+
+ return dict.Pass();
+}
+
+} // namespace
+
+StartPageHandler::StartPageHandler() : recommended_apps_(NULL) {}
+
+StartPageHandler::~StartPageHandler() {
+ if (recommended_apps_)
+ recommended_apps_->RemoveObserver(this);
+}
+
+void StartPageHandler::RegisterMessages() {
+ web_ui()->RegisterMessageCallback(
+ "initialize",
+ base::Bind(&StartPageHandler::HandleInitialize, base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "launchApp",
+ base::Bind(&StartPageHandler::HandleLaunchApp, base::Unretained(this)));
+}
+
+void StartPageHandler::OnRecommendedAppsChanged() {
+ SendRecommendedApps();
+}
+
+void StartPageHandler::SendRecommendedApps() {
+ const RecommendedApps::Apps& recommends = recommended_apps_->apps();
+
+ base::ListValue recommended_list;
+ for (size_t i = 0; i < recommends.size(); ++i) {
+ recommended_list.Append(CreateAppInfo(recommends[i].get()).release());
+ }
+
+ web_ui()->CallJavascriptFunction("appList.startPage.setRecommendedApps",
+ recommended_list);
+}
+
+void StartPageHandler::HandleInitialize(const base::ListValue* args) {
+ Profile* profile = Profile::FromWebUI(web_ui());
+ recommended_apps_ = StartPageService::Get(profile)->recommended_apps();
+ recommended_apps_->AddObserver(this);
+
+ SendRecommendedApps();
+}
+
+void StartPageHandler::HandleLaunchApp(const base::ListValue* args) {
+ std::string app_id;
+ CHECK(args->GetString(0, &app_id));
+
+ Profile* profile = Profile::FromWebUI(web_ui());
+ ExtensionService* service =
+ extensions::ExtensionSystem::Get(profile)->extension_service();
+ const extensions::Extension* app = service->GetInstalledExtension(app_id);
+ if (!app) {
+ NOTREACHED();
+ return;
+ }
+
+ scoped_ptr<AppListControllerDelegate> controller(
+ AppListService::Get()->CreateControllerDelegate());
+ controller->ActivateApp(profile,
+ app,
+ AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
+ ui::EF_NONE);
+}
+
+} // namespace app_list
diff --git a/chrome/browser/ui/webui/app_list/start_page_handler.h b/chrome/browser/ui/webui/app_list/start_page_handler.h
new file mode 100644
index 0000000..54e79fe
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/start_page_handler.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_HANDLER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/browser/ui/app_list/recommended_apps_observer.h"
+#include "content/public/browser/web_ui_message_handler.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace app_list {
+
+class RecommendedApps;
+
+// Handler for the app launcher start page.
+class StartPageHandler : public content::WebUIMessageHandler,
+ public RecommendedAppsObserver {
+ public:
+ StartPageHandler();
+ virtual ~StartPageHandler();
+
+ private:
+ // content::WebUIMessageHandler overrides:
+ virtual void RegisterMessages() OVERRIDE;
+
+ // RecommendedAppsObserver overrdies:
+ virtual void OnRecommendedAppsChanged() OVERRIDE;
+
+ // Creates a ListValue for the recommended apps and sends it to js side.
+ void SendRecommendedApps();
+
+ // JS callbacks.
+ void HandleInitialize(const base::ListValue* args);
+ void HandleLaunchApp(const base::ListValue* args);
+
+ RecommendedApps* recommended_apps_; // Not owned.
+
+ DISALLOW_COPY_AND_ASSIGN(StartPageHandler);
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_HANDLER_H_
diff --git a/chrome/browser/ui/webui/app_list/start_page_ui.cc b/chrome/browser/ui/webui/app_list/start_page_ui.cc
new file mode 100644
index 0000000..5a88ec3
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/start_page_ui.cc
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/app_list/start_page_ui.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/app_list/start_page_handler.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/web_ui.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "grit/browser_resources.h"
+
+namespace app_list {
+
+StartPageUI::StartPageUI(content::WebUI* web_ui)
+ : content::WebUIController(web_ui) {
+ web_ui->AddMessageHandler(new StartPageHandler);
+ InitDataSource();
+}
+
+StartPageUI::~StartPageUI() {}
+
+void StartPageUI::InitDataSource() {
+ scoped_ptr<content::WebUIDataSource> source(
+ content::WebUIDataSource::Create(chrome::kChromeUIAppListStartPageHost));
+
+ source->SetUseJsonJSFormatV2();
+ source->SetJsonPath("strings.js");
+
+ source->AddResourcePath("start_page.css", IDR_APP_LIST_START_PAGE_CSS);
+ source->AddResourcePath("start_page.js", IDR_APP_LIST_START_PAGE_JS);
+ source->SetDefaultResource(IDR_APP_LIST_START_PAGE_HTML);
+
+ content::WebUIDataSource::Add(Profile::FromWebUI(web_ui()), source.release());
+}
+
+} // namespace app_list
diff --git a/chrome/browser/ui/webui/app_list/start_page_ui.h b/chrome/browser/ui/webui/app_list/start_page_ui.h
new file mode 100644
index 0000000..63a5252
--- /dev/null
+++ b/chrome/browser/ui/webui/app_list/start_page_ui.h
@@ -0,0 +1,28 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_UI_H_
+#define CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_UI_H_
+
+#include "base/basictypes.h"
+#include "content/public/browser/web_ui_controller.h"
+
+namespace app_list {
+
+// StartPageUI for the app launcher start page.
+class StartPageUI : public content::WebUIController {
+ public:
+ explicit StartPageUI(content::WebUI* web_ui);
+ virtual ~StartPageUI();
+
+ private:
+ // Initializes the data source used for this webui.
+ void InitDataSource();
+
+ DISALLOW_COPY_AND_ASSIGN(StartPageUI);
+};
+
+} // namespace app_list
+
+#endif // CHROME_BROWSER_UI_WEBUI_APP_LIST_START_PAGE_UI_H_
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index dbaf799..bcd3c9d 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -136,6 +136,10 @@
#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui.h"
#endif
+#if defined(ENABLE_APP_LIST)
+#include "chrome/browser/ui/webui/app_list/start_page_ui.h"
+#endif
+
using content::WebUI;
using content::WebUIController;
using ui::ExternalWebDialogUI;
@@ -290,6 +294,10 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui,
if (url.host() == chrome::kChromeUIWebRtcLogsHost)
return &NewWebUI<WebRtcLogsUI>;
#endif
+#if defined(ENABLE_APP_LIST)
+ if (url.host() == chrome::kChromeUIAppListStartPageHost)
+ return &NewWebUI<app_list::StartPageUI>;
+#endif
/****************************************************************************
* OS Specific #defines