Commit 68bf09e0 authored by shrikant@chromium.org's avatar shrikant@chromium.org

Modified components ui to address concern of all the time disabled check update button.

With this change we take into account current status of update from update service.

+jhawkins for owners

BUG=272540
R=sorin,cpu,jhawkins

Review URL: https://codereview.chromium.org/209313002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274385 0039d316-1c4b-4281-b951-d872f2087c98
parent edf08a24
......@@ -5236,6 +5236,66 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_COMPONENTS_CHECK_FOR_UPDATE" desc="The button label for triggering update check.">
Check for update
</message>
<message name="IDS_COMPONENTS_STATUS_LABEL" desc="Status label">
Status
</message>
<message name="IDS_COMPONENTS_CHECKING_LABEL" desc="Checking label">
Checking for status...
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_NEW" desc="Service Status">
New
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_CHECKING" desc="Service Status">
Checking
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_UPDATE" desc="Service Status">
Update
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_DNL_DIFF" desc="Service Status">
Downloading diff
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_DNL" desc="Service Status">
Downloading
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_UPDT_DIFF" desc="Service Status">
Updating diff
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_UPDATING" desc="Service Status">
Updating
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_UPDATED" desc="Service Status">
Updated
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_UPTODATE" desc="Service Status">
Up-to-date
</message>
<message name="IDS_COMPONENTS_SVC_STATUS_NOUPDATE" desc="Service Status">
No update
</message>
<message name="IDS_COMPONENTS_UNKNOWN" desc="Service Status">
Unknown
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_STARTED" desc="Service Status">
Updater started
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_SLEEPING" desc="Service Status">
Updater sleeping
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_FOUND" desc="Service Status">
Update found
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_READY" desc="Service Status">
Update ready
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_UPDATED" desc="Service Status">
Component updated
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_NOTUPDATED" desc="Service Status">
Component not updated
</message>
<message name="IDS_COMPONENTS_EVT_STATUS_DOWNLOADING" desc="Service Status">
Component downloading
</message>
<!-- Plugins -->
<if expr="enable_plugins">
......
......@@ -88,12 +88,6 @@ CrxComponent::CrxComponent()
CrxComponent::~CrxComponent() {
}
CrxComponentInfo::CrxComponentInfo() {
}
CrxComponentInfo::~CrxComponentInfo() {
}
///////////////////////////////////////////////////////////////////////////////
// In charge of blocking url requests until the |crx_id| component has been
// updated. This class is touched solely from the IO thread. The UI thread
......@@ -160,8 +154,9 @@ class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater {
virtual Status Start() OVERRIDE;
virtual Status Stop() OVERRIDE;
virtual Status RegisterComponent(const CrxComponent& component) OVERRIDE;
virtual void GetComponents(
std::vector<CrxComponentInfo>* components) OVERRIDE;
virtual std::vector<std::string> GetComponentIDs() const OVERRIDE;
virtual CrxUpdateItem* GetComponentDetails(
const std::string& component_id) const OVERRIDE;
virtual OnDemandUpdater& GetOnDemandUpdater() OVERRIDE;
// Overrides for OnDemandUpdater.
......@@ -238,7 +233,7 @@ class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater {
size_t ChangeItemStatus(CrxUpdateItem::Status from, CrxUpdateItem::Status to);
CrxUpdateItem* FindUpdateItemById(const std::string& id);
CrxUpdateItem* FindUpdateItemById(const std::string& id) const;
void NotifyObservers(Observer::Events event, const std::string& id);
......@@ -247,6 +242,8 @@ class CrxUpdateService : public ComponentUpdateService, public OnDemandUpdater {
void OnNewResourceThrottle(base::WeakPtr<CUResourceThrottle> rt,
const std::string& crx_id);
Status GetServiceStatus(const CrxUpdateItem::Status status);
scoped_ptr<ComponentUpdateService::Configurator> config_;
scoped_ptr<UpdateChecker> update_checker_;
......@@ -399,10 +396,11 @@ void CrxUpdateService::ScheduleNextRun(StepDelayInterval step_delay) {
}
// Given a extension-like component id, find the associated component.
CrxUpdateItem* CrxUpdateService::FindUpdateItemById(const std::string& id) {
CrxUpdateItem* CrxUpdateService::FindUpdateItemById(
const std::string& id) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
CrxUpdateItem::FindById finder(id);
UpdateItems::iterator it =
UpdateItems::const_iterator it =
std::find_if(work_items_.begin(), work_items_.end(), finder);
return it != work_items_.end() ? *it : NULL;
}
......@@ -499,19 +497,22 @@ ComponentUpdateService::Status CrxUpdateService::RegisterComponent(
return kOk;
}
void CrxUpdateService::GetComponents(
std::vector<CrxComponentInfo>* components) {
std::vector<std::string> CrxUpdateService::GetComponentIDs() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
std::vector<std::string> component_ids;
for (UpdateItems::const_iterator it = work_items_.begin();
it != work_items_.end();
++it) {
const CrxUpdateItem* item = *it;
CrxComponentInfo info;
info.id = GetCrxComponentID(item->component);
info.version = item->component.version.GetString();
info.name = item->component.name;
components->push_back(info);
component_ids.push_back(item->id);
}
return component_ids;
}
CrxUpdateItem* CrxUpdateService::GetComponentDetails(
const std::string& component_id) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return FindUpdateItemById(component_id);
}
OnDemandUpdater& CrxUpdateService::GetOnDemandUpdater() {
......@@ -963,6 +964,9 @@ void CrxUpdateService::OnNewResourceThrottle(
UnblockResourceThrottle(rt);
}
// Start the process of checking for an update, for a particular component
// that was previously registered.
// |component_id| is a value returned from GetCrxComponentID().
ComponentUpdateService::Status CrxUpdateService::OnDemandUpdate(
const std::string& component_id) {
return OnDemandUpdateInternal(FindUpdateItemById(component_id));
......@@ -978,9 +982,33 @@ ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
if (delta < base::TimeDelta::FromSeconds(config_->OnDemandDelay()))
return kError;
switch (uit->status) {
// If the item is already in the process of being updated, there is
// no point in this call, so return kInProgress.
Status service_status = GetServiceStatus(uit->status);
// If the item is already in the process of being updated, there is
// no point in this call, so return kInProgress.
if (service_status == kInProgress)
return service_status;
// Otherwise the item was already checked a while back (or it is new),
// set its status to kNew to give it a slightly higher priority.
ChangeItemState(uit, CrxUpdateItem::kNew);
uit->on_demand = true;
// In case the current delay is long, set the timer to a shorter value
// to get the ball rolling.
if (timer_.IsRunning()) {
timer_.Stop();
timer_.Start(FROM_HERE,
base::TimeDelta::FromSeconds(config_->StepDelay()),
this,
&CrxUpdateService::ProcessPendingItems);
}
return kOk;
}
ComponentUpdateService::Status CrxUpdateService::GetServiceStatus(
CrxUpdateItem::Status status) {
switch (status) {
case CrxUpdateItem::kChecking:
case CrxUpdateItem::kCanUpdate:
case CrxUpdateItem::kDownloadingDiff:
......@@ -988,30 +1016,15 @@ ComponentUpdateService::Status CrxUpdateService::OnDemandUpdateInternal(
case CrxUpdateItem::kUpdatingDiff:
case CrxUpdateItem::kUpdating:
return kInProgress;
// Otherwise the item was already checked a while back (or it is new),
// set its status to kNew to give it a slightly higher priority.
case CrxUpdateItem::kNew:
case CrxUpdateItem::kUpdated:
case CrxUpdateItem::kUpToDate:
case CrxUpdateItem::kNoUpdate:
ChangeItemState(uit, CrxUpdateItem::kNew);
uit->on_demand = true;
break;
return kOk;
case CrxUpdateItem::kLastStatus:
NOTREACHED() << uit->status;
}
// In case the current delay is long, set the timer to a shorter value
// to get the ball rolling.
if (timer_.IsRunning()) {
timer_.Stop();
timer_.Start(FROM_HERE,
base::TimeDelta::FromSeconds(config_->StepDelay()),
this,
&CrxUpdateService::ProcessPendingItems);
NOTREACHED() << status;
}
return kOk;
return kError;
}
///////////////////////////////////////////////////////////////////////////////
......
......@@ -78,16 +78,7 @@ struct CrxComponent {
~CrxComponent();
};
// Convenience structure to use with component listing / enumeration.
struct CrxComponentInfo {
// |id| is currently derived from |CrxComponent.pk_hash|, see rest of the
// class implementation for details.
std::string id;
std::string version;
std::string name;
CrxComponentInfo();
~CrxComponentInfo();
};
struct CrxUpdateItem;
// The component update service is in charge of installing or upgrading
// select parts of chrome. Each part is called a component and managed by
......@@ -206,7 +197,13 @@ class ComponentUpdateService {
virtual Status RegisterComponent(const CrxComponent& component) = 0;
// Returns a list of registered components.
virtual void GetComponents(std::vector<CrxComponentInfo>* components) = 0;
virtual std::vector<std::string> GetComponentIDs() const = 0;
// Returns details about registered component.
// Note: Object returned here is owned by this class, in simple words
// don't try to free this object.
virtual CrxUpdateItem* GetComponentDetails(
const std::string& component_id) const = 0;
// Returns an interface for on-demand updates. On-demand updates are
// proactively triggered outside the normal component update service schedule.
......@@ -249,7 +246,6 @@ class OnDemandUpdater {
// the heap which the component updater will own.
ComponentUpdateService* ComponentUpdateServiceFactory(
ComponentUpdateService::Configurator* config);
} // namespace component_updater
#endif // CHROME_BROWSER_COMPONENT_UPDATER_COMPONENT_UPDATER_SERVICE_H_
......@@ -13,57 +13,56 @@
<div id="body-container" style="visibility:hidden">
<div id="header"><h1 i18n-content="componentsTitle">TITLE</h1></div>
<div id="componentTemplate">
<div id="component-placeholder"></div>
<div id="component-template" hidden>
<div id="container" class="vbox-container">
<div id="top" class="wbox">
<div class="section-header">
<table><tr>
<td>
<span class="section-header-title" i18n-content="componentsTitle"
>TITLE</span>
<span class="section-header-title"
jsdisplay="components.length > 0">(<span
jscontent="components.length"></span>)</span>
</td>
</tr></table>
<span class="section-header-title" i18n-content="componentsTitle">
</span>
<span class="section-header-title"
jsdisplay="components.length > 0">(<span
jscontent="components.length"></span>)</span>
</div>
</div>
</div>
<div class="content">
<div class="component-name no-components" jsdisplay="components.length === 0">
<div i18n-content="noComponents">NO_COMPONENTS_ARE_INSTALLED</div>
<div class="component-name no-components"
jsdisplay="components.length === 0">
<div i18n-content="noComponents"></div>
</div>
<div jsdisplay="components.length > 0">
<div class="component"
jsselect="components">
<table>
<tr class='component-enabled'>
<td>
<div class='component-enabled'>
<div class="component-text">
<div>
<span class="component-name" dir="ltr"
jscontent="name">NAME</span>
jscontent="name">
</span>
<span>
- <span i18n-content="componentVersion">VERSION</span>
<span dir="ltr" jscontent="version">x.x.x.x</span>
- <span i18n-content="componentVersion"></span>
<span dir="ltr" jscontent="version"></span>
</span>
</div>
<div class="component-actions" guest-visibility="disabled">
<button class="button-check-update" jsvalues=".id:id"
i18n-content="checkUpdate">
CHECK_UPDATE
</button>
</div>
</div>
</td>
</tr>
</table>
</div>
<div class="component-text">
<span i18n-content="statusLabel"></span>
-
<span jscontent="status" jsvalues=".id: 'status-' + id">
<span>
</div>
<div class="component-actions" guest-visibility="disabled">
<button class="button-check-update"
jsvalues=".id:id" i18n-content="checkUpdate">
</button>
</div>
</div>
</div>
</div>
......
......@@ -14,8 +14,11 @@
function renderTemplate(componentsData) {
// This is the javascript code that processes the template:
var input = new JsEvalContext(componentsData);
var output = $('componentTemplate');
var output = $('component-template').cloneNode(true);
$('component-placeholder').innerHTML = '';
$('component-placeholder').appendChild(output);
jstProcess(input, output);
output.removeAttribute('hidden');
}
/**
......@@ -72,19 +75,31 @@ function returnComponentsData(componentsData) {
body.className = 'show-tmi-mode-initial';
}
/**
* This event function is called from component UI indicating changed state
* of component updater service.
* @param {Object} eventArgs Contains event and component ID. Component ID is
* optional.
*/
function onComponentEvent(eventArgs) {
if (eventArgs['id']) {
var id = eventArgs['id'];
$('status-' + id).textContent = eventArgs['event'];
}
}
/**
* Handles an 'enable' or 'disable' button getting clicked.
* @param {HTMLElement} node The HTML element representing the component
* being checked for update.
*/
function handleCheckUpdate(node) {
node.disabled = true;
$('status-' + String(node.id)).textContent =
loadTimeData.getString('checkingLabel');
// Tell the C++ ComponentssDOMHandler to check for update.
chrome.send('checkUpdate', [String(node.id)]);
}
// Get data and have it displayed upon loading.
document.addEventListener('DOMContentLoaded', requestComponentsData);
// Add handlers to static HTML elements.
$('button-check-update').onclick = handleCheckUpdate;
......@@ -11,6 +11,7 @@
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/component_updater/crx_update_item.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_paths.h"
......@@ -43,6 +44,8 @@ content::WebUIDataSource* CreateComponentsUIHTMLSource(Profile* profile) {
source->AddLocalizedString("componentVersion", IDS_COMPONENTS_VERSION);
source->AddLocalizedString("checkUpdate", IDS_COMPONENTS_CHECK_FOR_UPDATE);
source->AddLocalizedString("noComponents", IDS_COMPONENTS_NO_COMPONENTS);
source->AddLocalizedString("statusLabel", IDS_COMPONENTS_STATUS_LABEL);
source->AddLocalizedString("checkingLabel", IDS_COMPONENTS_CHECKING_LABEL);
source->SetJsonPath("strings.js");
source->AddResourcePath("components.js", IDR_COMPONENTS_JS);
......@@ -75,8 +78,6 @@ class ComponentsDOMHandler : public WebUIMessageHandler {
void HandleCheckUpdate(const base::ListValue* args);
private:
void LoadComponents();
content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ComponentsDOMHandler);
......@@ -86,18 +87,23 @@ ComponentsDOMHandler::ComponentsDOMHandler() {
}
void ComponentsDOMHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("requestComponentsData",
web_ui()->RegisterMessageCallback(
"requestComponentsData",
base::Bind(&ComponentsDOMHandler::HandleRequestComponentsData,
base::Unretained(this)));
web_ui()->RegisterMessageCallback("checkUpdate",
web_ui()->RegisterMessageCallback(
"checkUpdate",
base::Bind(&ComponentsDOMHandler::HandleCheckUpdate,
base::Unretained(this)));
}
void ComponentsDOMHandler::HandleRequestComponentsData(
const base::ListValue* args) {
LoadComponents();
base::ListValue* list = ComponentsUI::LoadComponents();
base::DictionaryValue result;
result.Set("components", list);
web_ui()->CallJavascriptFunction("returnComponentsData", result);
}
// This function is called when user presses button from html UI.
......@@ -119,30 +125,6 @@ void ComponentsDOMHandler::HandleCheckUpdate(const base::ListValue* args) {
ComponentsUI::OnDemandUpdate(component_id);
}
void ComponentsDOMHandler::LoadComponents() {
component_updater::ComponentUpdateService* cus =
g_browser_process->component_updater();
std::vector<component_updater::CrxComponentInfo> components;
cus->GetComponents(&components);
// Construct DictionaryValues to return to UI.
base::ListValue* component_list = new base::ListValue();
for (size_t j = 0; j < components.size(); ++j) {
const component_updater::CrxComponentInfo& component = components[j];
base::DictionaryValue* component_entry = new base::DictionaryValue();
component_entry->SetString("id", component.id);
component_entry->SetString("name", component.name);
component_entry->SetString("version", component.version);
component_list->Append(component_entry);
}
base::DictionaryValue results;
results.Set("components", component_list);
web_ui()->CallJavascriptFunction("returnComponentsData", results);
}
} // namespace
///////////////////////////////////////////////////////////////////////////////
......@@ -157,6 +139,16 @@ ComponentsUI::ComponentsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
// Set up the chrome://components/ source.
Profile* profile = Profile::FromWebUI(web_ui);
content::WebUIDataSource::Add(profile, CreateComponentsUIHTMLSource(profile));
component_updater::ComponentUpdateService* cus =
g_browser_process->component_updater();
cus->AddObserver(this);
}
ComponentsUI::~ComponentsUI() {
component_updater::ComponentUpdateService* cus =
g_browser_process->component_updater();
if (cus)
cus->RemoveObserver(this);
}
// static
......@@ -166,9 +158,95 @@ void ComponentsUI::OnDemandUpdate(const std::string& component_id) {
cus->GetOnDemandUpdater().OnDemandUpdate(component_id);
}
// static
base::ListValue* ComponentsUI::LoadComponents() {
component_updater::ComponentUpdateService* cus =
g_browser_process->component_updater();
std::vector<std::string> component_ids;
component_ids = cus->GetComponentIDs();
// Construct DictionaryValues to return to UI.
base::ListValue* component_list = new base::ListValue();
for (size_t j = 0; j < component_ids.size(); ++j) {
const component_updater::CrxUpdateItem* item =
cus->GetComponentDetails(component_ids[j]);
if (item) {
base::DictionaryValue* component_entry = new base::DictionaryValue();
component_entry->SetString("id", component_ids[j]);
component_entry->SetString("name", item->component.name);
component_entry->SetString("version",
item->component.version.GetString());
component_entry->SetString("status",
ServiceStatusToString(item->status));
component_list->Append(component_entry);
}
}
return component_list;
}
// static
base::RefCountedMemory* ComponentsUI::GetFaviconResourceBytes(
ui::ScaleFactor scale_factor) {
return ResourceBundle::GetSharedInstance().
LoadDataResourceBytesForScale(IDR_PLUGINS_FAVICON, scale_factor);
}
base::string16 ComponentsUI::ComponentEventToString(Events event) {
switch (event) {
case COMPONENT_UPDATER_STARTED:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_STARTED);
case COMPONENT_UPDATER_SLEEPING:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_SLEEPING);
case COMPONENT_UPDATE_FOUND:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_FOUND);
case COMPONENT_UPDATE_READY:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_READY);
case COMPONENT_UPDATED:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_UPDATED);
case COMPONENT_NOT_UPDATED:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_NOTUPDATED);
case COMPONENT_UPDATE_DOWNLOADING:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_EVT_STATUS_DOWNLOADING);
}
return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
}
base::string16 ComponentsUI::ServiceStatusToString(
component_updater::CrxUpdateItem::Status status) {
switch (status) {
case component_updater::CrxUpdateItem::kNew:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_NEW);
case component_updater::CrxUpdateItem::kChecking:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_CHECKING);
case component_updater::CrxUpdateItem::kCanUpdate:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATE);
case component_updater::CrxUpdateItem::kDownloadingDiff:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_DNL_DIFF);
case component_updater::CrxUpdateItem::kDownloading:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_DNL);
case component_updater::CrxUpdateItem::kUpdatingDiff:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDT_DIFF);
case component_updater::CrxUpdateItem::kUpdating:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATING);
case component_updater::CrxUpdateItem::kUpdated:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPDATED);
case component_updater::CrxUpdateItem::kUpToDate:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_UPTODATE);
case component_updater::CrxUpdateItem::kNoUpdate:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_SVC_STATUS_NOUPDATE);
case component_updater::CrxUpdateItem::kLastStatus:
return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
}
return l10n_util::GetStringUTF16(IDS_COMPONENTS_UNKNOWN);
}
void ComponentsUI::OnEvent(Events event, const std::string& id) {
base::DictionaryValue parameters;
parameters.SetString("event", ComponentEventToString(event));
if (!id.empty())
parameters.SetString("id", id);
web_ui()->CallJavascriptFunction("onComponentEvent", parameters);
}
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_UI_WEBUI_COMPONENTS_UI_H_
#define CHROME_BROWSER_UI_WEBUI_COMPONENTS_UI_H_
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/component_updater/crx_update_item.h"
#include "content/public/browser/web_ui_controller.h"
#include "ui/base/layout.h"
......@@ -16,16 +18,26 @@ namespace user_prefs {
class PrefRegistrySyncable;
}
class ComponentsUI : public content::WebUIController {
class ComponentsUI : public content::WebUIController,
public component_updater::ServiceObserver {
public:
explicit ComponentsUI(content::WebUI* web_ui);
virtual ~ComponentsUI();
static void OnDemandUpdate(const std::string& component_id);
static base::ListValue* LoadComponents();
static base::RefCountedMemory* GetFaviconResourceBytes(
ui::ScaleFactor scale_factor);
// ServiceObserver implementation.
virtual void OnEvent(Events event, const std::string& id) OVERRIDE;
private:
static base::string16 ComponentEventToString(Events event);
static base::string16 ServiceStatusToString(
component_updater::CrxUpdateItem::Status status);
DISALLOW_COPY_AND_ASSIGN(ComponentsUI);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment