text: // Copyright (c) 2011 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/chromeos/cros/update_library.h"
  
  #include "base/message_loop.h"
  #include "base/string_util.h"
  #include "chrome/browser/chromeos/cros/cros_library.h"
  #include "content/browser/browser_thread.h"
  #include "content/common/notification_service.h"
  #include "content/common/notification_type.h"
  
  namespace chromeos {
  
  class UpdateLibraryImpl : public UpdateLibrary {
   public:
    UpdateLibraryImpl()
      : status_connection_(NULL) {
      if (CrosLibrary::Get()->EnsureLoaded()) {
        Init();
      }
    }
  
    ~UpdateLibraryImpl() {
      if (status_connection_) {
        DisconnectUpdateProgress(status_connection_);
      }
    }
  
    void AddObserver(Observer* observer) {
      observers_.AddObserver(observer);
    }
  
    void RemoveObserver(Observer* observer) {
      observers_.RemoveObserver(observer);
    }
  
    bool HasObserver(Observer* observer) {
      return observers_.HasObserver(observer);
    }
  
    void RequestUpdateCheck(chromeos::UpdateCallback callback, void* user_data) {
      if (CrosLibrary::Get()->EnsureLoaded())
        chromeos::RequestUpdateCheck(callback, user_data);
    }
  
    bool RebootAfterUpdate() {
      if (!CrosLibrary::Get()->EnsureLoaded())
        return false;
  
      return RebootIfUpdated();
    }
  
    void SetReleaseTrack(const std::string& track) {
      if (CrosLibrary::Get()->EnsureLoaded())
        chromeos::SetUpdateTrack(track);
    }
  
    void GetReleaseTrack(chromeos::UpdateTrackCallback callback,
                         void* user_data) {
      if (CrosLibrary::Get()->EnsureLoaded())
        chromeos::RequestUpdateTrack(callback, user_data);
    }
  
    const UpdateLibrary::Status& status() const {
      return status_;
    }
  
   private:
    static void ChangedHandler(void* object,
        const UpdateProgress& status) {
      UpdateLibraryImpl* updater = static_cast<UpdateLibraryImpl*>(object);
      updater->UpdateStatus(Status(status));
    }
  
    void Init() {
      status_connection_ = MonitorUpdateStatus(&ChangedHandler, this);
    }
  
    void UpdateStatus(const Status& status) {
      // Make sure we run on UI thread.
      if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
        BrowserThread::PostTask(
            BrowserThread::UI, FROM_HERE,
            NewRunnableMethod(this, &UpdateLibraryImpl::UpdateStatus, status));
        return;
      }
  
      status_ = status;
      FOR_EACH_OBSERVER(Observer, observers_, UpdateStatusChanged(this));
  
      // If the update is ready to install, send a notification so that Chrome
      // can update the UI.
      if (status_.status == UPDATE_STATUS_UPDATED_NEED_REBOOT) {
        NotificationService::current()->Notify(
            NotificationType::UPGRADE_RECOMMENDED,
            Source<UpdateLibrary>(this),
            NotificationService::NoDetails());
      }
    }
  
    ObserverList<Observer> observers_;
  
    // A reference to the update api, to allow callbacks when the update
    // status changes.
    UpdateStatusConnection status_connection_;
  
    // The latest power status.
    Status status_;
  
    DISALLOW_COPY_AND_ASSIGN(UpdateLibraryImpl);
  };
  
  class UpdateLibraryStubImpl : public UpdateLibrary {
   public:
    UpdateLibraryStubImpl() {}
    ~UpdateLibraryStubImpl() {}
    void AddObserver(Observer* observer) {}
    void RemoveObserver(Observer* observer) {}
    bool HasObserver(Observer* observer) { return false; }
    void RequestUpdateCheck(chromeos::UpdateCallback callback, void* user_data) {
      if (callback)
        callback(user_data, UPDATE_RESULT_FAILED, "stub update");
    }
    bool RebootAfterUpdate() { return false; }
    void SetReleaseTrack(const std::string& track) { }
    void GetReleaseTrack(chromeos::UpdateTrackCallback callback,
                         void* user_data) {
      if (callback)
        callback(user_data, "beta-channel");
    }
    const UpdateLibrary::Status& status() const {
      return status_;
    }
  
   private:
    Status status_;
  
    DISALLOW_COPY_AND_ASSIGN(UpdateLibraryStubImpl);
  };
  
  // static
  UpdateLibrary* UpdateLibrary::GetImpl(bool stub) {
    if (stub)
      return new UpdateLibraryStubImpl();
    else
      return new UpdateLibraryImpl();
  }
  
  }  // namespace chromeos
  
  // Allows InvokeLater without adding refcounting. This class is a Singleton and
  // won't be deleted until it's last InvokeLater is run.
  DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::UpdateLibraryImpl);
  