Commit 85c04ce4 authored by satorux@chromium.org's avatar satorux@chromium.org

chromeos: Change all clients of UpdateLibrary to use UpdateEngineClient.

This is part 2 of the UpdateLibrary to UpdateEngineClient migration.

UpdateLibrary will be removed in the next patch.

BUG=chromium-os:16564
TEST=confirm that the update works as before from chrome://settings/about and OOBE screen.

Review URL: http://codereview.chromium.org/8585025

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111190 0039d316-1c4b-4281-b951-d872f2087c98
parent 5e0d181b
......@@ -17,7 +17,8 @@
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/cros/power_library.h"
#include "chrome/browser/chromeos/cros/screen_lock_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/login/enrollment/enterprise_enrollment_screen.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/login_display.h"
......@@ -42,8 +43,9 @@
#include "ui/views/widget/widget.h"
using chromeos::CrosLibrary;
using chromeos::DBusThreadManager;
using chromeos::NetworkLibrary;
using chromeos::UpdateLibrary;
using chromeos::UpdateEngineClient;
using chromeos::UserManager;
namespace {
......@@ -83,33 +85,33 @@ base::Value* GetProxySetting(Browser* browser,
return NULL;
}
const char* UpdateStatusToString(chromeos::UpdateStatusOperation status) {
const char* UpdateStatusToString(
UpdateEngineClient::UpdateStatusOperation status) {
switch (status) {
case chromeos::UPDATE_STATUS_IDLE:
case UpdateEngineClient::UPDATE_STATUS_IDLE:
return "idle";
case chromeos::UPDATE_STATUS_CHECKING_FOR_UPDATE:
case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
return "checking for update";
case chromeos::UPDATE_STATUS_UPDATE_AVAILABLE:
case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
return "update available";
case chromeos::UPDATE_STATUS_DOWNLOADING:
case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
return "downloading";
case chromeos::UPDATE_STATUS_VERIFYING:
case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
return "verifying";
case chromeos::UPDATE_STATUS_FINALIZING:
case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
return "finalizing";
case chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT:
case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
return "updated need reboot";
case chromeos::UPDATE_STATUS_REPORTING_ERROR_EVENT:
case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
return "reporting error event";
default:
return "unknown";
}
}
void GetReleaseTrackCallback(void* user_data, const char* track) {
AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data);
if (track == NULL) {
void GetReleaseTrackCallback(AutomationJSONReply* reply,
const std::string& track) {
if (track.empty()) {
reply->SendError("Unable to get release track.");
delete reply;
return;
......@@ -118,11 +120,12 @@ void GetReleaseTrackCallback(void* user_data, const char* track) {
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->SetString("release_track", track);
UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
const UpdateLibrary::Status& status = update_library->status();
chromeos::UpdateStatusOperation update_status = status.status;
const UpdateEngineClient::Status& status =
DBusThreadManager::Get()->GetUpdateEngineClient()->GetLastStatus();
UpdateEngineClient::UpdateStatusOperation update_status =
status.status;
return_value->SetString("status", UpdateStatusToString(update_status));
if (update_status == chromeos::UPDATE_STATUS_DOWNLOADING)
if (update_status == UpdateEngineClient::UPDATE_STATUS_DOWNLOADING)
return_value->SetDouble("download_progress", status.download_progress);
if (status.last_checked_time > 0)
return_value->SetInteger("last_checked_time", status.last_checked_time);
......@@ -133,13 +136,12 @@ void GetReleaseTrackCallback(void* user_data, const char* track) {
delete reply;
}
void UpdateCheckCallback(void* user_data, chromeos::UpdateResult result,
const char* error_msg) {
AutomationJSONReply* reply = static_cast<AutomationJSONReply*>(user_data);
if (result == chromeos::UPDATE_RESULT_SUCCESS)
void UpdateCheckCallback(AutomationJSONReply* reply,
UpdateEngineClient::UpdateCheckResult result) {
if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS)
reply->SendSuccess(NULL);
else
reply->SendError(error_msg);
reply->SendError("update check failed");
delete reply;
}
......@@ -1052,17 +1054,17 @@ void TestingAutomationProvider::SetTimezone(DictionaryValue* args,
void TestingAutomationProvider::GetUpdateInfo(DictionaryValue* args,
IPC::Message* reply_message) {
UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message);
update_library->GetReleaseTrack(GetReleaseTrackCallback, reply);
DBusThreadManager::Get()->GetUpdateEngineClient()
->GetReleaseTrack(base::Bind(GetReleaseTrackCallback, reply));
}
void TestingAutomationProvider::UpdateCheck(
DictionaryValue* args,
IPC::Message* reply_message) {
UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
AutomationJSONReply* reply = new AutomationJSONReply(this, reply_message);
update_library->RequestUpdateCheck(UpdateCheckCallback, reply);
DBusThreadManager::Get()->GetUpdateEngineClient()
->RequestUpdateCheck(base::Bind(UpdateCheckCallback, reply));
}
void TestingAutomationProvider::SetReleaseTrack(DictionaryValue* args,
......@@ -1074,8 +1076,7 @@ void TestingAutomationProvider::SetReleaseTrack(DictionaryValue* args,
return;
}
UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
update_library->SetReleaseTrack(track);
DBusThreadManager::Get()->GetUpdateEngineClient()->SetReleaseTrack(track);
reply.SendSuccess(NULL);
}
......
......@@ -14,6 +14,7 @@
#include "chrome/browser/chromeos/dbus/sensors_client.h"
#include "chrome/browser/chromeos/dbus/session_manager_client.h"
#include "chrome/browser/chromeos/dbus/speech_synthesizer_client.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/common/chrome_switches.h"
#include "dbus/bus.h"
......@@ -65,6 +66,8 @@ class DBusThreadManagerImpl : public DBusThreadManager {
// Create the cros-disks client.
cros_disks_client_.reset(
CrosDisksClient::Create(system_bus_.get()));
update_engine_client_.reset(
UpdateEngineClient::Create(system_bus_.get()));
}
virtual ~DBusThreadManagerImpl() {
......@@ -111,6 +114,11 @@ class DBusThreadManagerImpl : public DBusThreadManager {
return cros_disks_client_.get();
}
// DBusThreadManager override.
virtual UpdateEngineClient* GetUpdateEngineClient() OVERRIDE {
return update_engine_client_.get();
}
scoped_ptr<base::Thread> dbus_thread_;
scoped_refptr<dbus::Bus> system_bus_;
scoped_ptr<CrosDBusService> cros_dbus_service_;
......@@ -121,6 +129,7 @@ class DBusThreadManagerImpl : public DBusThreadManager {
scoped_ptr<SessionManagerClient> session_manager_client_;
scoped_ptr<SpeechSynthesizerClient> speech_synthesizer_client_;
scoped_ptr<CrosDisksClient> cros_disks_client_;
scoped_ptr<UpdateEngineClient> update_engine_client_;
};
// static
......
......@@ -26,6 +26,7 @@ class PowerManagerClient;
class SessionManagerClient;
class SensorsClient;
class SpeechSynthesizerClient;
class UpdateEngineClient;
// DBusThreadManager manages the D-Bus thread, the thread dedicated to
// handling asynchronous D-Bus operations.
......@@ -101,6 +102,10 @@ class DBusThreadManager {
// down.
virtual CrosDisksClient* GetCrosDisksClient() = 0;
// Returns the update engine client, owned by DBusThreadManager. Do not
// cache this pointer and use it after DBusThreadManager is shut down.
virtual UpdateEngineClient* GetUpdateEngineClient() = 0;
virtual ~DBusThreadManager();
protected:
......
......@@ -11,6 +11,7 @@
#include "chrome/browser/chromeos/dbus/mock_sensors_client.h"
#include "chrome/browser/chromeos/dbus/mock_session_manager_client.h"
#include "chrome/browser/chromeos/dbus/mock_speech_synthesizer_client.h"
#include "chrome/browser/chromeos/dbus/mock_update_engine_client.h"
using ::testing::AnyNumber;
using ::testing::Return;
......@@ -25,7 +26,8 @@ MockDBusThreadManager::MockDBusThreadManager()
mock_power_manager_client_(new MockPowerManagerClient),
mock_sensors_client_(new MockSensorsClient),
mock_session_manager_client_(new MockSessionManagerClient),
mock_speech_synthesizer_client_(new MockSpeechSynthesizerClient) {
mock_speech_synthesizer_client_(new MockSpeechSynthesizerClient),
mock_update_engine_client_(new MockUpdateEngineClient) {
EXPECT_CALL(*this, GetBluetoothAdapterClient())
.WillRepeatedly(Return(mock_bluetooth_adapter_client_.get()));
EXPECT_CALL(*this, GetBluetoothManagerClient())
......@@ -40,6 +42,8 @@ MockDBusThreadManager::MockDBusThreadManager()
.WillRepeatedly(Return(mock_session_manager_client_.get()));
EXPECT_CALL(*this, GetSpeechSynthesizerClient())
.WillRepeatedly(Return(mock_speech_synthesizer_client_.get()));
EXPECT_CALL(*this, GetUpdateEngineClient())
.WillRepeatedly(Return(mock_update_engine_client_.get()));
// These observers calls are used in ChromeBrowserMainPartsChromeos.
EXPECT_CALL(*mock_power_manager_client_.get(), AddObserver(_))
......
......@@ -19,6 +19,7 @@ class MockPowerManagerClient;
class MockSensorsClient;
class MockSessionManagerClient;
class MockSpeechSynthesizerClient;
class MockUpdateEngineClient;
// This class provides a mock DBusThreadManager with mock clients
// installed. You can customize the behaviors of mock clients with
......@@ -35,6 +36,7 @@ class MockDBusThreadManager : public DBusThreadManager {
MOCK_METHOD0(GetSensorsClient, SensorsClient*(void));
MOCK_METHOD0(GetSessionManagerClient, SessionManagerClient*(void));
MOCK_METHOD0(GetSpeechSynthesizerClient, SpeechSynthesizerClient*(void));
MOCK_METHOD0(GetUpdateEngineClient, UpdateEngineClient*(void));
MockBluetoothAdapterClient* mock_bluetooth_adapter_client() {
return mock_bluetooth_adapter_client_.get();
......@@ -57,6 +59,9 @@ class MockDBusThreadManager : public DBusThreadManager {
MockSpeechSynthesizerClient* mock_speech_synthesizer_client() {
return mock_speech_synthesizer_client_.get();
}
MockUpdateEngineClient* mock_update_engine_client() {
return mock_update_engine_client_.get();
}
private:
scoped_ptr<MockBluetoothAdapterClient> mock_bluetooth_adapter_client_;
......@@ -66,6 +71,7 @@ class MockDBusThreadManager : public DBusThreadManager {
scoped_ptr<MockSensorsClient> mock_sensors_client_;
scoped_ptr<MockSessionManagerClient> mock_session_manager_client_;
scoped_ptr<MockSpeechSynthesizerClient> mock_speech_synthesizer_client_;
scoped_ptr<MockUpdateEngineClient> mock_update_engine_client_;
DISALLOW_COPY_AND_ASSIGN(MockDBusThreadManager);
};
......
......@@ -4,10 +4,11 @@
#include "chrome/browser/chromeos/login/update_screen.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/chromeos/login/update_screen_actor.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
......@@ -39,14 +40,11 @@ const int kUpdateScreenHeight = 305;
const char kUpdateDeadlineFile[] = "/tmp/update-check-response-deadline";
// Invoked from call to RequestUpdateCheck upon completion of the DBus call.
void StartUpdateCallback(void* user_data,
UpdateResult result,
const char* msg) {
void StartUpdateCallback(UpdateScreen* screen,
UpdateEngineClient::UpdateCheckResult result) {
VLOG(1) << "Callback from RequestUpdateCheck, result " << result;
DCHECK(user_data);
UpdateScreen* screen = static_cast<UpdateScreen*>(user_data);
if (UpdateScreen::HasInstance(screen)) {
if (result == chromeos::UPDATE_RESULT_SUCCESS)
if (result == UpdateEngineClient::UPDATE_RESULT_SUCCESS)
screen->SetIgnoreIdleStatus(false);
else
screen->ExitUpdate(UpdateScreen::REASON_UPDATE_INIT_FAILED);
......@@ -84,27 +82,29 @@ UpdateScreen::UpdateScreen(ScreenObserver* screen_observer,
}
UpdateScreen::~UpdateScreen() {
CrosLibrary::Get()->GetUpdateLibrary()->RemoveObserver(this);
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
GetInstanceSet().erase(this);
if (actor_)
actor_->SetDelegate(NULL);
}
void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
void UpdateScreen::UpdateStatusChanged(
const UpdateEngineClient::Status& status) {
if (is_checking_for_update_ &&
status.status > UPDATE_STATUS_CHECKING_FOR_UPDATE) {
status.status > UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE) {
is_checking_for_update_ = false;
}
if (ignore_idle_status_ && status.status > UPDATE_STATUS_IDLE) {
if (ignore_idle_status_ && status.status >
UpdateEngineClient::UPDATE_STATUS_IDLE) {
ignore_idle_status_ = false;
}
switch (status.status) {
case UPDATE_STATUS_CHECKING_FOR_UPDATE:
case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
// Do nothing in these cases, we don't want to notify the user of the
// check unless there is an update.
break;
case UPDATE_STATUS_UPDATE_AVAILABLE:
case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
MakeSureScreenIsShown();
actor_->SetProgress(kBeforeDownloadProgress);
if (!HasCriticalUpdate()) {
......@@ -118,7 +118,7 @@ void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
actor_->ShowCurtain(false);
}
break;
case UPDATE_STATUS_DOWNLOADING:
case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
{
MakeSureScreenIsShown();
if (!is_downloading_update_) {
......@@ -141,15 +141,15 @@ void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
actor_->SetProgress(kBeforeDownloadProgress + download_progress);
}
break;
case UPDATE_STATUS_VERIFYING:
case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
MakeSureScreenIsShown();
actor_->SetProgress(kBeforeVerifyingProgress);
break;
case UPDATE_STATUS_FINALIZING:
case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
MakeSureScreenIsShown();
actor_->SetProgress(kBeforeFinalizingProgress);
break;
case UPDATE_STATUS_UPDATED_NEED_REBOOT:
case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
MakeSureScreenIsShown();
// Make sure that first OOBE stage won't be shown after reboot.
WizardController::MarkOobeCompleted();
......@@ -157,7 +157,7 @@ void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
if (HasCriticalUpdate()) {
actor_->ShowCurtain(false);
VLOG(1) << "Initiate reboot after update";
CrosLibrary::Get()->GetUpdateLibrary()->RebootAfterUpdate();
DBusThreadManager::Get()->GetUpdateEngineClient()->RebootAfterUpdate();
reboot_timer_.Start(FROM_HERE,
base::TimeDelta::FromSeconds(reboot_check_delay_),
this,
......@@ -166,15 +166,15 @@ void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
ExitUpdate(REASON_UPDATE_NON_CRITICAL);
}
break;
case UPDATE_STATUS_IDLE:
case UpdateEngineClient::UPDATE_STATUS_IDLE:
if (ignore_idle_status_) {
// It is first IDLE status that is sent before we initiated the check.
break;
}
// else no break
case UPDATE_STATUS_ERROR:
case UPDATE_STATUS_REPORTING_ERROR_EVENT:
case UpdateEngineClient::UPDATE_STATUS_ERROR:
case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
ExitUpdate(REASON_UPDATE_ENDED);
break;
default:
......@@ -184,10 +184,10 @@ void UpdateScreen::UpdateStatusChanged(const UpdateLibrary::Status& status) {
}
void UpdateScreen::StartUpdate() {
CrosLibrary::Get()->GetUpdateLibrary()->AddObserver(this);
DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
VLOG(1) << "Initiate update check";
CrosLibrary::Get()->GetUpdateLibrary()->RequestUpdateCheck(
StartUpdateCallback, this);
DBusThreadManager::Get()->GetUpdateEngineClient()->RequestUpdateCheck(
base::Bind(StartUpdateCallback, this));
}
void UpdateScreen::CancelUpdate() {
......@@ -211,7 +211,7 @@ void UpdateScreen::PrepareToShow() {
}
void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) {
CrosLibrary::Get()->GetUpdateLibrary()->RemoveObserver(this);
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
switch (reason) {
case REASON_UPDATE_CANCELED:
......@@ -224,21 +224,22 @@ void UpdateScreen::ExitUpdate(UpdateScreen::ExitReason reason) {
case REASON_UPDATE_NON_CRITICAL:
case REASON_UPDATE_ENDED:
{
UpdateLibrary* update_library = CrosLibrary::Get()->GetUpdateLibrary();
switch (update_library->status().status) {
case UPDATE_STATUS_UPDATE_AVAILABLE:
case UPDATE_STATUS_UPDATED_NEED_REBOOT:
case UPDATE_STATUS_DOWNLOADING:
case UPDATE_STATUS_FINALIZING:
case UPDATE_STATUS_VERIFYING:
UpdateEngineClient* update_engine_client =
DBusThreadManager::Get()->GetUpdateEngineClient();
switch (update_engine_client->GetLastStatus().status) {
case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
DCHECK(!HasCriticalUpdate());
// Noncritical update, just exit screen as if there is no update.
// no break
case UPDATE_STATUS_IDLE:
case UpdateEngineClient::UPDATE_STATUS_IDLE:
get_screen_observer()->OnExit(ScreenObserver::UPDATE_NOUPDATE);
break;
case UPDATE_STATUS_ERROR:
case UPDATE_STATUS_REPORTING_ERROR_EVENT:
case UpdateEngineClient::UPDATE_STATUS_ERROR:
case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
get_screen_observer()->OnExit(is_checking_for_update_ ?
ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE :
ScreenObserver::UPDATE_ERROR_UPDATING);
......
......@@ -11,7 +11,7 @@
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/timer.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/login/update_screen_actor.h"
#include "chrome/browser/chromeos/login/wizard_screen.h"
......@@ -22,7 +22,7 @@ class ScreenObserver;
// Controller for the update screen. It does not depend on the specific
// implementation of the screen showing (Views of WebUI based), the dependency
// is moved to the UpdateScreenActor instead.
class UpdateScreen: public UpdateLibrary::Observer,
class UpdateScreen: public UpdateEngineClient::Observer,
public UpdateScreenActor::Delegate,
public WizardScreen {
public:
......@@ -60,8 +60,9 @@ class UpdateScreen: public UpdateLibrary::Observer,
// Reports update results to the ScreenObserver.
virtual void ExitUpdate(ExitReason reason);
// UpdateLibrary::Observer implementation:
virtual void UpdateStatusChanged(const UpdateLibrary::Status& status);
// UpdateEngineClient::Observer implementation:
virtual void UpdateStatusChanged(
const UpdateEngineClient::Status& status) OVERRIDE;
private:
FRIEND_TEST_ALL_PREFIXES(UpdateScreenTest, TestBasic);
......
......@@ -4,9 +4,9 @@
#include "base/message_loop.h"
#include "chrome/browser/chromeos/cros/mock_network_library.h"
#include "chrome/browser/chromeos/cros/mock_update_library.h"
#include "chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/mock_session_manager_client.h"
#include "chrome/browser/chromeos/dbus/mock_update_engine_client.h"
#include "chrome/browser/chromeos/login/mock_screen_observer.h"
#include "chrome/browser/chromeos/login/update_screen.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
......@@ -20,15 +20,17 @@ using ::testing::AtLeast;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::Invoke;
using chromeos::UpdateEngineClient;
static void RequestUpdateCheckSuccess(UpdateCallback callback, void* userdata) {
callback(userdata, chromeos::UPDATE_RESULT_SUCCESS, NULL);
static void RequestUpdateCheckSuccess(
UpdateEngineClient::UpdateCheckCallback callback) {
callback.Run(UpdateEngineClient::UPDATE_RESULT_SUCCESS);
}
class UpdateScreenTest : public WizardInProcessBrowserTest {
public:
UpdateScreenTest() : WizardInProcessBrowserTest("update"),
mock_update_library_(NULL),
mock_update_engine_client_(NULL),
mock_network_library_(NULL) {}
protected:
......@@ -45,17 +47,17 @@ class UpdateScreenTest : public WizardInProcessBrowserTest {
EXPECT_CALL(*mock_session_manager_client, EmitLoginPromptReady())
.Times(1);
mock_update_library_ = new MockUpdateLibrary();
cros_mock_->test_api()->SetUpdateLibrary(mock_update_library_, true);
mock_update_engine_client_
= mock_dbus_thread_manager->mock_update_engine_client();
// UpdateScreen::StartUpdate() will be called by the WizardController
// just after creating the update screen, so the expectations for that
// should be set up here.
EXPECT_CALL(*mock_update_library_, AddObserver(_))
EXPECT_CALL(*mock_update_engine_client_, AddObserver(_))
.Times(AtLeast(1));
EXPECT_CALL(*mock_update_library_, RemoveObserver(_))
EXPECT_CALL(*mock_update_engine_client_, RemoveObserver(_))
.Times(AtLeast(1));
EXPECT_CALL(*mock_update_library_, RequestUpdateCheck(_,_))
EXPECT_CALL(*mock_update_engine_client_, RequestUpdateCheck(_))
.Times(1)
.WillOnce(Invoke(RequestUpdateCheckSuccess));
......@@ -84,12 +86,11 @@ class UpdateScreenTest : public WizardInProcessBrowserTest {
virtual void TearDownInProcessBrowserTestFixture() {
update_screen_->screen_observer_ = (controller());
cros_mock_->test_api()->SetUpdateLibrary(NULL, true);
WizardInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
DBusThreadManager::Shutdown();
}
MockUpdateLibrary* mock_update_library_;
MockUpdateEngineClient* mock_update_engine_client_;
MockNetworkLibrary* mock_network_library_;
scoped_ptr<MockScreenObserver> mock_screen_observer_;
......@@ -105,17 +106,17 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestBasic) {
IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestNoUpdate) {
update_screen_->SetIgnoreIdleStatus(true);
UpdateLibrary::Status status;
status.status = UPDATE_STATUS_IDLE;
UpdateEngineClient::Status status;
status.status = UpdateEngineClient::UPDATE_STATUS_IDLE;
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_CHECKING_FOR_UPDATE;
status.status = UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_IDLE;
// status() will be called via ExitUpdate() called from
status.status = UpdateEngineClient::UPDATE_STATUS_IDLE;
// GetLastStatus() will be called via ExitUpdate() called from
// UpdateStatusChanged().
EXPECT_CALL(*mock_update_library_, status())
EXPECT_CALL(*mock_update_engine_client_, GetLastStatus())
.Times(AtLeast(1))
.WillRepeatedly(ReturnRef(status));
.WillRepeatedly(Return(status));
EXPECT_CALL(*mock_screen_observer_, OnExit(ScreenObserver::UPDATE_NOUPDATE))
.Times(1);
update_screen_->UpdateStatusChanged(status);
......@@ -124,12 +125,12 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestNoUpdate) {
IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateAvailable) {
update_screen_->is_ignore_update_deadlines_ = true;
UpdateLibrary::Status status;
status.status = UPDATE_STATUS_UPDATE_AVAILABLE;
UpdateEngineClient::Status status;
status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
status.new_version = "latest and greatest";
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_DOWNLOADING;
status.status = UpdateEngineClient::UPDATE_STATUS_DOWNLOADING;
status.download_progress = 0.0;
update_screen_->UpdateStatusChanged(status);
......@@ -139,20 +140,21 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateAvailable) {
status.download_progress = 1.0;
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_VERIFYING;
status.status = UpdateEngineClient::UPDATE_STATUS_VERIFYING;
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_FINALIZING;
status.status = UpdateEngineClient::UPDATE_STATUS_FINALIZING;
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_UPDATED_NEED_REBOOT;
EXPECT_CALL(*mock_update_library_, RebootAfterUpdate())
status.status = UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
EXPECT_CALL(*mock_update_engine_client_, RebootAfterUpdate())
.Times(1);
update_screen_->UpdateStatusChanged(status);
}
static void RequestUpdateCheckFail(UpdateCallback callback, void* userdata) {
callback(userdata, chromeos::UPDATE_RESULT_FAILED, NULL);
static void RequestUpdateCheckFail(
UpdateEngineClient::UpdateCheckCallback callback) {
callback.Run(chromeos::UpdateEngineClient::UPDATE_RESULT_FAILED);
}
IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorIssuingUpdateCheck) {
......@@ -164,11 +166,11 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorIssuingUpdateCheck) {
// Run UpdateScreen::StartUpdate() again, but CheckForUpdate() will fail
// issuing the update check this time.
EXPECT_CALL(*mock_update_library_, AddObserver(_))
EXPECT_CALL(*mock_update_engine_client_, AddObserver(_))
.Times(1);
EXPECT_CALL(*mock_update_library_, RemoveObserver(_))
EXPECT_CALL(*mock_update_engine_client_, RemoveObserver(_))
.Times(AtLeast(1));
EXPECT_CALL(*mock_update_library_, RequestUpdateCheck(_,_))
EXPECT_CALL(*mock_update_engine_client_, RequestUpdateCheck(_))
.Times(1)
.WillOnce(Invoke(RequestUpdateCheckFail));
EXPECT_CALL(*mock_screen_observer_,
......@@ -178,13 +180,13 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorIssuingUpdateCheck) {
}
IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorCheckingForUpdate) {
UpdateLibrary::Status status;
status.status = UPDATE_STATUS_ERROR;
// status() will be called via ExitUpdate() called from
UpdateEngineClient::Status status;
status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
// GetLastStatus() will be called via ExitUpdate() called from
// UpdateStatusChanged().
EXPECT_CALL(*mock_update_library_, status())
EXPECT_CALL(*mock_update_engine_client_, GetLastStatus())
.Times(AtLeast(1))
.WillRepeatedly(ReturnRef(status));
.WillRepeatedly(Return(status));
EXPECT_CALL(*mock_screen_observer_,
OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE))
.Times(1);
......@@ -192,22 +194,22 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorCheckingForUpdate) {
}
IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorUpdating) {
UpdateLibrary::Status status;
status.status = UPDATE_STATUS_UPDATE_AVAILABLE;
UpdateEngineClient::Status status;
status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
status.new_version = "latest and greatest";
// status() will be called via ExitUpdate() called from
// GetLastStatus() will be called via ExitUpdate() called from
// UpdateStatusChanged().
EXPECT_CALL(*mock_update_library_, status())
EXPECT_CALL(*mock_update_engine_client_, GetLastStatus())
.Times(AtLeast(1))
.WillRepeatedly(ReturnRef(status));
.WillRepeatedly(Return(status));
update_screen_->UpdateStatusChanged(status);
status.status = UPDATE_STATUS_ERROR;
// status() will be called via ExitUpdate() called from
status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
// GetLastStatus() will be called via ExitUpdate() called from
// UpdateStatusChanged().
EXPECT_CALL(*mock_update_library_, status())
EXPECT_CALL(*mock_update_engine_client_, GetLastStatus())
.Times(AtLeast(1))
.WillRepeatedly(ReturnRef(status));
.WillRepeatedly(Return(status));
EXPECT_CALL(*mock_screen_observer_,
OnExit(ScreenObserver::UPDATE_ERROR_UPDATING))
.Times(1);
......
......@@ -5,7 +5,7 @@
#include "chrome/browser/chromeos/upgrade_detector_chromeos.h"
#include "base/memory/singleton.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
namespace {
......@@ -15,6 +15,9 @@ const int kNotifyCycleTimeMs = 20 * 60 * 1000; // 20 minutes.
} // namespace
using chromeos::DBusThreadManager;
using chromeos::UpdateEngineClient;
UpgradeDetectorChromeos::UpgradeDetectorChromeos() : initialized_(false) {
}
......@@ -22,22 +25,20 @@ UpgradeDetectorChromeos::~UpgradeDetectorChromeos() {
}
void UpgradeDetectorChromeos::Init() {
if (chromeos::CrosLibrary::Get())
chromeos::CrosLibrary::Get()->GetUpdateLibrary()->AddObserver(this);
DBusThreadManager::Get()->GetUpdateEngineClient()->AddObserver(this);
initialized_ = true;
}
void UpgradeDetectorChromeos::Shutdown() {
// Init() may not be called from tests (ex. BrowserMainTest).
// Init() may not be called from tests.
if (!initialized_)
return;
if (chromeos::CrosLibrary::Get())
chromeos::CrosLibrary::Get()->GetUpdateLibrary()->RemoveObserver(this);
DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this);
}
void UpgradeDetectorChromeos::UpdateStatusChanged(
const chromeos::UpdateLibrary::Status& status) {
if (status.status != chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT)
const UpdateEngineClient::Status& status) {
if (status.status != UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT)
return;
NotifyUpgradeDetected();
......
......@@ -7,13 +7,13 @@
#pragma once
#include "base/timer.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/upgrade_detector.h"
template <typename T> struct DefaultSingletonTraits;
class UpgradeDetectorChromeos : public UpgradeDetector,
public chromeos::UpdateLibrary::Observer {
public chromeos::UpdateEngineClient::Observer {
public:
virtual ~UpgradeDetectorChromeos();
......@@ -32,9 +32,9 @@ class UpgradeDetectorChromeos : public UpgradeDetector,
UpgradeDetectorChromeos();
// chromeos::UpdateLibrary::Observer implementation.
// chromeos::UpdateEngineClient::Observer implementation.
virtual void UpdateStatusChanged(
const chromeos::UpdateLibrary::Status& status);
const chromeos::UpdateEngineClient::Status& status) OVERRIDE;
// The function that sends out a notification (after a certain time has
// elapsed) that lets the rest of the UI know we should start notifying the
......
......@@ -15,8 +15,8 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/login/ownership_service.h"
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
#include "chrome/browser/policy/cloud_policy_data_store.h"
......@@ -350,7 +350,8 @@ void DevicePolicyCache::DecodeDevicePolicy(
// TODO(dubroy): Once http://crosbug.com/17015 is implemented, we won't
// have to pass the channel in here, only ping the update engine to tell
// it to fetch the channel from the policy.
chromeos::CrosLibrary::Get()->GetUpdateLibrary()->SetReleaseTrack(channel);
chromeos::DBusThreadManager::Get()->GetUpdateEngineClient()
->SetReleaseTrack(channel);
}
if (policy.has_open_network_configuration() &&
......
......@@ -31,10 +31,9 @@
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/session_manager_client.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/system/runtime_environment.h"
#if defined(TOOLKIT_USES_GTK)
#include "chrome/browser/chromeos/legacy_window_manager/wm_ipc.h"
......@@ -334,11 +333,12 @@ void BrowserList::NotifyAndTerminate(bool fast_path) {
#if defined(OS_CHROMEOS)
NotifyWindowManagerAboutSignout();
if (chromeos::system::runtime_environment::IsRunningOnChromeOS()) {
chromeos::UpdateEngineClient* update_engine_client
= chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
// If update has been installed, reboot, otherwise, sign out.
chromeos::CrosLibrary* cros_library = chromeos::CrosLibrary::Get();
if (cros_library->GetUpdateLibrary()->status().status ==
chromeos::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
cros_library->GetUpdateLibrary()->RebootAfterUpdate();
if (update_engine_client->GetLastStatus().status ==
chromeos::UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
update_engine_client->RebootAfterUpdate();
} else {
chromeos::DBusThreadManager::Get()->GetSessionManagerClient()
->StopSession();
......
......@@ -16,10 +16,9 @@
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/power_manager_client.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/user_cros_settings_provider.h"
......@@ -64,7 +63,7 @@ std::string StringSubRange(const std::string& text, size_t start,
namespace chromeos {
class AboutPageHandler::UpdateObserver
: public UpdateLibrary::Observer {
: public UpdateEngineClient::Observer {
public:
explicit UpdateObserver(AboutPageHandler* handler) : page_handler_(handler) {}
virtual ~UpdateObserver() {}
......@@ -72,7 +71,8 @@ class AboutPageHandler::UpdateObserver
AboutPageHandler* page_handler() const { return page_handler_; }
private:
virtual void UpdateStatusChanged(const UpdateLibrary::Status& status) {
virtual void UpdateStatusChanged(
const UpdateEngineClient::Status& status) OVERRIDE {
page_handler_->UpdateStatus(status);
}
......@@ -89,7 +89,7 @@ AboutPageHandler::AboutPageHandler()
AboutPageHandler::~AboutPageHandler() {
if (update_observer_.get()) {
CrosLibrary::Get()->GetUpdateLibrary()->
DBusThreadManager::Get()->GetUpdateEngineClient()->
RemoveObserver(update_observer_.get());
}
}
......@@ -256,14 +256,14 @@ void AboutPageHandler::PageReady(const ListValue* args) {
base::Bind(&AboutPageHandler::OnOSFirmware,
base::Unretained(this)));
UpdateLibrary* update_library =
CrosLibrary::Get()->GetUpdateLibrary();
UpdateEngineClient* update_engine_client =
DBusThreadManager::Get()->GetUpdateEngineClient();
update_observer_.reset(new UpdateObserver(this));
update_library->AddObserver(update_observer_.get());
update_engine_client->AddObserver(update_observer_.get());
// Update the WebUI page with the current status. See comments below.
UpdateStatus(update_library->status());
UpdateStatus(update_engine_client->GetLastStatus());
// Initiate update check. UpdateStatus() below will be called when we
// get update status via update_observer_. If the update has been
......@@ -273,8 +273,8 @@ void AboutPageHandler::PageReady(const ListValue* args) {
// Request the channel information. Use the observer to track the about
// page handler and ensure it does not get deleted before the callback.
update_library->GetReleaseTrack(UpdateSelectedChannel,
update_observer_.get());
update_engine_client->GetReleaseTrack(
base::Bind(UpdateSelectedChannel, update_observer_.get()));
}
void AboutPageHandler::SetReleaseTrack(const ListValue* args) {
......@@ -283,16 +283,15 @@ void AboutPageHandler::SetReleaseTrack(const ListValue* args) {
return;
}
const std::string channel = UTF16ToUTF8(ExtractStringValue(args));
CrosLibrary::Get()->GetUpdateLibrary()->SetReleaseTrack(channel);
DBusThreadManager::Get()->GetUpdateEngineClient()->SetReleaseTrack(channel);
}
void AboutPageHandler::CheckNow(const ListValue* args) {
// Make sure that libcros is loaded and OOBE is complete.
if (!WizardController::default_controller() ||
WizardController::IsDeviceRegistered()) {
CrosLibrary::Get()->GetUpdateLibrary()->
RequestUpdateCheck(NULL, // no callback
NULL); // no userdata
DBusThreadManager::Get()->GetUpdateEngineClient()->
RequestUpdateCheck(UpdateEngineClient::EmptyUpdateCheckCallback());
}
}
......@@ -301,28 +300,28 @@ void AboutPageHandler::RestartNow(const ListValue* args) {
}
void AboutPageHandler::UpdateStatus(
const UpdateLibrary::Status& status) {
const UpdateEngineClient::Status& status) {
string16 message;
std::string image = "up-to-date";
bool enabled = false;
switch (status.status) {
case UPDATE_STATUS_IDLE:
case UpdateEngineClient::UPDATE_STATUS_IDLE:
if (!sticky_) {
message = l10n_util::GetStringFUTF16(IDS_UPGRADE_ALREADY_UP_TO_DATE,
l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME));
enabled = true;
}
break;
case UPDATE_STATUS_CHECKING_FOR_UPDATE:
case UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE:
message = l10n_util::GetStringUTF16(IDS_UPGRADE_CHECK_STARTED);
sticky_ = false;
break;
case UPDATE_STATUS_UPDATE_AVAILABLE:
case UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE:
message = l10n_util::GetStringUTF16(IDS_UPDATE_AVAILABLE);
started_ = true;
break;
case UPDATE_STATUS_DOWNLOADING:
case UpdateEngineClient::UPDATE_STATUS_DOWNLOADING:
{
int progress = static_cast<int>(status.download_progress * 100.0);
if (progress != progress_) {
......@@ -333,22 +332,22 @@ void AboutPageHandler::UpdateStatus(
started_ = true;
}
break;
case UPDATE_STATUS_VERIFYING:
case UpdateEngineClient::UPDATE_STATUS_VERIFYING:
message = l10n_util::GetStringUTF16(IDS_UPDATE_VERIFYING);
started_ = true;
break;
case UPDATE_STATUS_FINALIZING:
case UpdateEngineClient::UPDATE_STATUS_FINALIZING:
message = l10n_util::GetStringUTF16(IDS_UPDATE_FINALIZING);
started_ = true;
break;
case UPDATE_STATUS_UPDATED_NEED_REBOOT:
case UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT:
message = l10n_util::GetStringUTF16(IDS_UPDATE_COMPLETED);
image = "available";
sticky_ = true;
break;
default:
// case UPDATE_STATUS_ERROR:
// case UPDATE_STATUS_REPORTING_ERROR_EVENT:
// case UpdateEngineClient::UPDATE_STATUS_ERROR:
// case UpdateEngineClient::UPDATE_STATUS_REPORTING_ERROR_EVENT:
// The error is only displayed if we were able to determine an
// update was available.
......@@ -366,7 +365,8 @@ void AboutPageHandler::UpdateStatus(
// "Checking for update..." needs to be shown for a while, so users
// can read it, hence insert delay for this.
scoped_ptr<Value> insert_delay(Value::CreateBooleanValue(
status.status == UPDATE_STATUS_CHECKING_FOR_UPDATE));
status.status ==
UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE));
web_ui_->CallJavascriptFunction("AboutPage.updateStatusCallback",
*update_message, *insert_delay);
......@@ -379,7 +379,7 @@ void AboutPageHandler::UpdateStatus(
*image_string);
}
// We'll change the "Check For Update" button to "Restart" button.
if (status.status == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
if (status.status == UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT) {
web_ui_->CallJavascriptFunction("AboutPage.changeToRestartButton");
}
}
......@@ -404,15 +404,12 @@ void AboutPageHandler::OnOSFirmware(VersionLoader::Handle handle,
// Callback from UpdateEngine with channel information.
// static
void AboutPageHandler::UpdateSelectedChannel(void* user_data,
const char* channel) {
if (!user_data || !channel) {
LOG(WARNING) << "UpdateSelectedChannel returned NULL.";
return;
}
UpdateObserver* observer = static_cast<UpdateObserver*>(user_data);
if (CrosLibrary::Get()->GetUpdateLibrary()->HasObserver(observer)) {
// If UpdateLibrary still has the observer, then the page handler is valid.
void AboutPageHandler::UpdateSelectedChannel(UpdateObserver* observer,
const std::string& channel) {
if (DBusThreadManager::Get()->GetUpdateEngineClient()
->HasObserver(observer)) {
// If UpdateEngineClient still has the observer, then the page handler
// is valid.
AboutPageHandler* handler = observer->page_handler();
scoped_ptr<Value> channel_string(Value::CreateStringValue(channel));
handler->web_ui_->CallJavascriptFunction(
......
......@@ -8,7 +8,7 @@
#include <string>
#include "chrome/browser/ui/webui/options/options_ui.h"
#include "chrome/browser/chromeos/cros/update_library.h"
#include "chrome/browser/chromeos/dbus/update_engine_client.h"
#include "chrome/browser/chromeos/version_loader.h"
namespace chromeos {
......@@ -25,6 +25,8 @@ class AboutPageHandler : public OptionsPageUIHandler {
virtual void RegisterMessages();
private:
class UpdateObserver;
// The function is called from JavaScript when the about page is ready.
void PageReady(const base::ListValue* args);
......@@ -43,10 +45,11 @@ class AboutPageHandler : public OptionsPageUIHandler {
std::string version);
void OnOSFirmware(VersionLoader::Handle handle,
std::string firmware);
void UpdateStatus(const UpdateLibrary::Status& status);
void UpdateStatus(const UpdateEngineClient::Status& status);
// UpdateEngine Callback handler.
static void UpdateSelectedChannel(void* user_data, const char* channel);
static void UpdateSelectedChannel(UpdateObserver* observer,
const std::string& channel);
// Handles asynchronously loading the version.
VersionLoader loader_;
......@@ -55,7 +58,6 @@ class AboutPageHandler : public OptionsPageUIHandler {
CancelableRequestConsumer consumer_;
// Update Observer
class UpdateObserver;
scoped_ptr<UpdateObserver> update_observer_;
int progress_;
......
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