1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/webui/components_ui.h"
6
7#include <algorithm>
8#include <string>
9#include <vector>
10
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_window.h"
15#include "chrome/common/chrome_paths.h"
16#include "chrome/common/url_constants.h"
17#include "chrome/grit/generated_resources.h"
18#include "components/component_updater/component_updater_service.h"
19#include "components/component_updater/crx_update_item.h"
20#include "content/public/browser/web_ui.h"
21#include "content/public/browser/web_ui_data_source.h"
22#include "content/public/browser/web_ui_message_handler.h"
23#include "grit/browser_resources.h"
24#include "grit/theme_resources.h"
25#include "ui/base/l10n/l10n_util.h"
26#include "ui/base/resource/resource_bundle.h"
27
28#if defined(OS_CHROMEOS)
29#include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
30#endif
31
32using content::WebUIMessageHandler;
33
34namespace {
35
36content::WebUIDataSource* CreateComponentsUIHTMLSource(Profile* profile) {
37  content::WebUIDataSource* source =
38      content::WebUIDataSource::Create(chrome::kChromeUIComponentsHost);
39  source->SetUseJsonJSFormatV2();
40
41  source->AddLocalizedString("componentsTitle", IDS_COMPONENTS_TITLE);
42  source->AddLocalizedString("componentsNoneInstalled",
43                             IDS_COMPONENTS_NONE_INSTALLED);
44  source->AddLocalizedString("componentVersion", IDS_COMPONENTS_VERSION);
45  source->AddLocalizedString("checkUpdate", IDS_COMPONENTS_CHECK_FOR_UPDATE);
46  source->AddLocalizedString("noComponents", IDS_COMPONENTS_NO_COMPONENTS);
47  source->AddLocalizedString("statusLabel", IDS_COMPONENTS_STATUS_LABEL);
48  source->AddLocalizedString("checkingLabel", IDS_COMPONENTS_CHECKING_LABEL);
49
50  source->SetJsonPath("strings.js");
51  source->AddResourcePath("components.js", IDR_COMPONENTS_JS);
52  source->SetDefaultResource(IDR_COMPONENTS_HTML);
53#if defined(OS_CHROMEOS)
54  chromeos::AddAccountUITweaksLocalizedValues(source, profile);
55#endif
56  return source;
57}
58
59////////////////////////////////////////////////////////////////////////////////
60//
61// ComponentsDOMHandler
62//
63////////////////////////////////////////////////////////////////////////////////
64
65// The handler for Javascript messages for the chrome://components/ page.
66class ComponentsDOMHandler : public WebUIMessageHandler {
67 public:
68  ComponentsDOMHandler();
69  virtual ~ComponentsDOMHandler() {}
70
71  // WebUIMessageHandler implementation.
72  virtual void RegisterMessages() OVERRIDE;
73
74  // Callback for the "requestComponentsData" message.
75  void HandleRequestComponentsData(const base::ListValue* args);
76
77  // Callback for the "checkUpdate" message.
78  void HandleCheckUpdate(const base::ListValue* args);
79
80 private:
81  content::NotificationRegistrar registrar_;
82
83  DISALLOW_COPY_AND_ASSIGN(ComponentsDOMHandler);
84};
85
86ComponentsDOMHandler::ComponentsDOMHandler() {
87}
88
89void ComponentsDOMHandler::RegisterMessages() {
90  web_ui()->RegisterMessageCallback(
91      "requestComponentsData",
92      base::Bind(&ComponentsDOMHandler::HandleRequestComponentsData,
93                 base::Unretained(this)));
94
95  web_ui()->RegisterMessageCallback(
96      "checkUpdate",
97      base::Bind(&ComponentsDOMHandler::HandleCheckUpdate,
98                 base::Unretained(this)));
99}
100
101void ComponentsDOMHandler::HandleRequestComponentsData(
102    const base::ListValue* args) {
103  base::ListValue* list = ComponentsUI::LoadComponents();
104  base::DictionaryValue result;
105  result.Set("components", list);
106  web_ui()->CallJavascriptFunction("returnComponentsData", result);
107}
108
109// This function is called when user presses button from html UI.
110// TODO(shrikant): We need to make this button available based on current
111// state e.g. If component state is currently updating then we need to disable
112// button. (https://code.google.com/p/chromium/issues/detail?id=272540)
113void ComponentsDOMHandler::HandleCheckUpdate(const base::ListValue* args) {
114  if (args->GetSize() != 1) {
115    NOTREACHED();
116    return;
117  }
118
119  std::string component_id;
120  if (!args->GetString(0, &component_id)) {
121    NOTREACHED();
122    return;
123  }
124
125  ComponentsUI::OnDemandUpdate(component_id);
126}
127
128}  // namespace
129
130///////////////////////////////////////////////////////////////////////////////
131//
132// ComponentsUI
133//
134///////////////////////////////////////////////////////////////////////////////
135
136ComponentsUI::ComponentsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
137  web_ui->AddMessageHandler(new ComponentsDOMHandler());
138
139  // Set up the chrome://components/ source.
140  Profile* profile = Profile::FromWebUI(web_ui);
141  content::WebUIDataSource::Add(profile, CreateComponentsUIHTMLSource(profile));
142  component_updater::ComponentUpdateService* cus =
143      g_browser_process->component_updater();
144  cus->AddObserver(this);
145}
146
147ComponentsUI::~ComponentsUI() {
148  component_updater::ComponentUpdateService* cus =
149      g_browser_process->component_updater();
150  if (cus)
151    cus->RemoveObserver(this);
152}
153
154// static
155void ComponentsUI::OnDemandUpdate(const std::string& component_id) {
156  component_updater::ComponentUpdateService* cus =
157      g_browser_process->component_updater();
158  cus->GetOnDemandUpdater().OnDemandUpdate(component_id);
159}
160
161// static
162base::ListValue* ComponentsUI::LoadComponents() {
163  component_updater::ComponentUpdateService* cus =
164      g_browser_process->component_updater();
165  std::vector<std::string> component_ids;
166  component_ids = cus->GetComponentIDs();
167
168  // Construct DictionaryValues to return to UI.
169  base::ListValue* component_list = new base::ListValue();
170  for (size_t j = 0; j < component_ids.size(); ++j) {
171    component_updater::CrxUpdateItem item;
172    if (cus->GetComponentDetails(component_ids[j], &item)) {
173      base::DictionaryValue* component_entry = new base::DictionaryValue();
174      component_entry->SetString("id", component_ids[j]);
175      component_entry->SetString("name", item.component.name);
176      component_entry->SetString("version", item.component.version.GetString());
177      component_entry->SetString("status", ServiceStatusToString(item.status));
178      component_list->Append(component_entry);
179    }
180  }
181
182  return component_list;
183}
184
185// static
186base::RefCountedMemory* ComponentsUI::GetFaviconResourceBytes(
187      ui::ScaleFactor scale_factor) {
188  return ResourceBundle::GetSharedInstance().
189      LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
190}
191
192base::string16 ComponentsUI::ComponentEventToString(Events event) {
193  switch (event) {
194    case COMPONENT_UPDATER_STARTED:
195      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_STARTED);
196    case COMPONENT_UPDATER_SLEEPING:
197      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_SLEEPING);
198    case COMPONENT_UPDATE_FOUND:
199      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_FOUND);
200    case COMPONENT_UPDATE_READY:
201      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_READY);
202    case COMPONENT_UPDATED:
203      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_UPDATED);
204    case COMPONENT_NOT_UPDATED:
205      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_NOTUPDATED);
206    case COMPONENT_UPDATE_DOWNLOADING:
207      return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_DOWNLOADING);
208  }
209  return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
210}
211
212base::string16 ComponentsUI::ServiceStatusToString(
213    component_updater::CrxUpdateItem::Status status) {
214  switch (status) {
215    case component_updater::CrxUpdateItem::kNew:
216      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_NEW);
217    case component_updater::CrxUpdateItem::kChecking:
218      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_CHECKING);
219    case component_updater::CrxUpdateItem::kCanUpdate:
220      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATE);
221    case component_updater::CrxUpdateItem::kDownloadingDiff:
222      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_DNL_DIFF);
223    case component_updater::CrxUpdateItem::kDownloading:
224      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_DNL);
225    case component_updater::CrxUpdateItem::kUpdatingDiff:
226      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDT_DIFF);
227    case component_updater::CrxUpdateItem::kUpdating:
228      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATING);
229    case component_updater::CrxUpdateItem::kUpdated:
230      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATED);
231    case component_updater::CrxUpdateItem::kUpToDate:
232      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPTODATE);
233    case component_updater::CrxUpdateItem::kNoUpdate:
234      return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_NOUPDATE);
235    case component_updater::CrxUpdateItem::kLastStatus:
236      return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
237  }
238  return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
239}
240
241void ComponentsUI::OnEvent(Events event, const std::string& id) {
242  base::DictionaryValue parameters;
243  parameters.SetString("event", ComponentEventToString(event));
244  if (!id.empty()) {
245    using component_updater::ComponentUpdateService;
246    if (event == ComponentUpdateService::Observer::COMPONENT_UPDATED) {
247      ComponentUpdateService* cus = g_browser_process->component_updater();
248      component_updater::CrxUpdateItem item;
249      if (cus->GetComponentDetails(id, &item))
250        parameters.SetString("version", item.component.version.GetString());
251    }
252    parameters.SetString("id", id);
253  }
254  web_ui()->CallJavascriptFunction("onComponentEvent", parameters);
255}
256