root/chrome/browser/notifications/extension_welcome_notification.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. delegate_
  2. Display
  3. Error
  4. Close
  5. Click
  6. ButtonClick
  7. MarkAsDismissed
  8. OpenNotificationLearnMoreTab
  9. GetMessageCenter
  10. GetCurrentTime
  11. PostTask
  12. delegate_
  13. Create
  14. Create
  15. OnIsSyncingChanged
  16. ShowWelcomeNotificationIfNecessary
  17. RegisterProfilePrefs
  18. GetMessageCenter
  19. ShowWelcomeNotification
  20. HideWelcomeNotification
  21. OnWelcomeNotificationDismissedChanged
  22. StartExpirationTimer
  23. StopExpirationTimer
  24. ExpireWelcomeNotification
  25. GetExpirationTimestamp
  26. SetExpirationTimestampFromNow
  27. IsWelcomeNotificationExpired

// Copyright 2014 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/notifications/extension_welcome_notification.h"

#include "base/guid.h"
#include "base/lazy_instance.h"
#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/prefs/pref_service_syncable.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_delegate.h"
#include "ui/message_center/notification_types.h"

const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 1;

namespace {

class NotificationCallbacks
    : public message_center::NotificationDelegate {
 public:
  NotificationCallbacks(
      Profile* profile,
      ExtensionWelcomeNotification::Delegate* delegate)
      : profile_(profile),
        delegate_(delegate) {
  }

  // Overridden from NotificationDelegate:
  virtual void Display() OVERRIDE {}
  virtual void Error() OVERRIDE {}

  virtual void Close(bool by_user) OVERRIDE {
    if (by_user) {
      // Setting the preference here may cause the notification erasing
      // to reenter. Posting a task avoids this issue.
      delegate_->PostTask(
          FROM_HERE,
          base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
    }
  }

  virtual void Click() OVERRIDE {}
  virtual void ButtonClick(int index) OVERRIDE {
    DCHECK_EQ(index, 0);
    OpenNotificationLearnMoreTab();
  }

 private:
  void MarkAsDismissed() {
    profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed,
                                     true);
  }

  void OpenNotificationLearnMoreTab() {
    chrome::NavigateParams params(
        profile_,
        GURL(chrome::kNotificationWelcomeLearnMoreURL),
        content::PAGE_TRANSITION_LINK);
    params.disposition = NEW_FOREGROUND_TAB;
    params.window_action = chrome::NavigateParams::SHOW_WINDOW;
    chrome::Navigate(&params);
  }

  virtual ~NotificationCallbacks() {}

  Profile* const profile_;

  // Weak ref owned by ExtensionWelcomeNotification.
  ExtensionWelcomeNotification::Delegate* const delegate_;

  DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
};

class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
 public:
  DefaultDelegate() {}

  virtual message_center::MessageCenter* GetMessageCenter() OVERRIDE {
    return g_browser_process->message_center();
  }

  virtual base::Time GetCurrentTime() OVERRIDE {
    return base::Time::Now();
  }

  virtual void PostTask(
      const tracked_objects::Location& from_here,
      const base::Closure& task) OVERRIDE {
    base::MessageLoop::current()->PostTask(from_here, task);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
};

}  // namespace

ExtensionWelcomeNotification::ExtensionWelcomeNotification(
    const std::string& extension_id,
    Profile* const profile,
    ExtensionWelcomeNotification::Delegate* const delegate)
    : notifier_id_(message_center::NotifierId::APPLICATION, extension_id),
      profile_(profile),
      delegate_(delegate) {
  welcome_notification_dismissed_pref_.Init(
      prefs::kWelcomeNotificationDismissed,
      profile_->GetPrefs(),
      base::Bind(
          &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
          base::Unretained(this)));
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile) {
  return Create(extension_id, profile, new DefaultDelegate()).Pass();
}

// static
scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
    const std::string& extension_id,
    Profile* const profile,
    Delegate* const delegate) {
  return scoped_ptr<ExtensionWelcomeNotification>(
      new ExtensionWelcomeNotification(extension_id, profile, delegate)).Pass();
}

ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
  if (delayed_notification_) {
    delayed_notification_.reset();
    PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
  } else {
    HideWelcomeNotification();
  }
}

void ExtensionWelcomeNotification::OnIsSyncingChanged() {
  DCHECK(delayed_notification_);
  PrefServiceSyncable* const pref_service_syncable =
      PrefServiceSyncable::FromProfile(profile_);
  if (pref_service_syncable->IsSyncing()) {
    pref_service_syncable->RemoveObserver(this);
    scoped_ptr<Notification> previous_notification(
        delayed_notification_.release());
    ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
  }
}

void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
    const Notification& notification) {
  if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
    PrefServiceSyncable* const pref_service_syncable =
        PrefServiceSyncable::FromProfile(profile_);
    if (pref_service_syncable->IsSyncing()) {
      PrefService* const pref_service = profile_->GetPrefs();
      if (!pref_service->GetBoolean(prefs::kWelcomeNotificationDismissed)) {
        const PopUpRequest pop_up_request =
            pref_service->GetBoolean(
                prefs::kWelcomeNotificationPreviouslyPoppedUp)
                ? POP_UP_HIDDEN
                : POP_UP_SHOWN;
        if (pop_up_request == POP_UP_SHOWN) {
          pref_service->SetBoolean(
              prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
        }

        if (IsWelcomeNotificationExpired()) {
          ExpireWelcomeNotification();
        } else {
          ShowWelcomeNotification(
              notification.display_source(), pop_up_request);
        }
      }
    } else {
      delayed_notification_.reset(new Notification(notification));
      pref_service_syncable->AddObserver(this);
    }
  }
}

// static
void ExtensionWelcomeNotification::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* prefs) {
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
                             false,
                             user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
  prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
                             false,
                             user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
  prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp,
                           0,
                           user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

message_center::MessageCenter*
ExtensionWelcomeNotification::GetMessageCenter() const {
  return delegate_->GetMessageCenter();
}

void ExtensionWelcomeNotification::ShowWelcomeNotification(
    const base::string16& display_source,
    const PopUpRequest pop_up_request) {
  message_center::ButtonInfo learn_more(
      l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
  learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
      IDR_NOTIFICATION_WELCOME_LEARN_MORE);

  message_center::RichNotificationData rich_notification_data;
  rich_notification_data.priority = 2;
  rich_notification_data.buttons.push_back(learn_more);

  if (welcome_notification_id_.empty())
    welcome_notification_id_ = base::GenerateGUID();

  if (!welcome_notification_id_.empty()) {
    scoped_ptr<message_center::Notification> message_center_notification(
        new message_center::Notification(
            message_center::NOTIFICATION_TYPE_BASE_FORMAT,
            welcome_notification_id_,
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
            l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
            ui::ResourceBundle::GetSharedInstance().GetImageNamed(
                IDR_NOTIFICATION_WELCOME_ICON),
            display_source,
            notifier_id_,
            rich_notification_data,
            new NotificationCallbacks(profile_, delegate_.get())));

    if (pop_up_request == POP_UP_HIDDEN)
      message_center_notification->set_shown_as_popup(true);

    GetMessageCenter()->AddNotification(message_center_notification.Pass());
    StartExpirationTimer();
  }
}

void ExtensionWelcomeNotification::HideWelcomeNotification() {
  if (!welcome_notification_id_.empty() &&
      GetMessageCenter()->HasNotification(welcome_notification_id_)) {
    GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
    StopExpirationTimer();
  }
}

void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
  const bool welcome_notification_dismissed =
      profile_->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed);
  if (welcome_notification_dismissed)
    HideWelcomeNotification();
}

void ExtensionWelcomeNotification::StartExpirationTimer() {
  if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
    base::Time expiration_timestamp = GetExpirationTimestamp();
    if (expiration_timestamp.is_null()) {
      SetExpirationTimestampFromNow();
      expiration_timestamp = GetExpirationTimestamp();
      DCHECK(!expiration_timestamp.is_null());
    }
    expiration_timer_.reset(
        new base::OneShotTimer<ExtensionWelcomeNotification>());
    expiration_timer_->Start(
        FROM_HERE,
        expiration_timestamp - delegate_->GetCurrentTime(),
        this,
        &ExtensionWelcomeNotification::ExpireWelcomeNotification);
  }
}

void ExtensionWelcomeNotification::StopExpirationTimer() {
  if (expiration_timer_) {
    expiration_timer_->Stop();
    expiration_timer_.reset();
  }
}

void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
  DCHECK(IsWelcomeNotificationExpired());
  profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissed, true);
  HideWelcomeNotification();
}

base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
  PrefService* const pref_service = profile_->GetPrefs();
  const int64 expiration_timestamp =
      pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
  return (expiration_timestamp == 0)
      ? base::Time()
      : base::Time::FromInternalValue(expiration_timestamp);
}

void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
  PrefService* const pref_service = profile_->GetPrefs();
  pref_service->SetInt64(
      prefs::kWelcomeNotificationExpirationTimestamp,
      (delegate_->GetCurrentTime() +
          base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
}

bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
  const base::Time expiration_timestamp = GetExpirationTimestamp();
  return !expiration_timestamp.is_null() &&
         (expiration_timestamp <= delegate_->GetCurrentTime());
}

// C++ Readability Review Change Trigger

/* [<][>][^][v][top][bottom][index][help] */