chromium/ash/system/palette/palette_welcome_bubble.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/palette/palette_welcome_bubble.h"

#include <memory>

#include "ash/assistant/util/assistant_util.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/palette/palette_tray.h"
#include "base/command_line.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "ui/aura/window.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/layout/fill_layout.h"

namespace ash {

namespace {

// Width of the bubble content label size.
constexpr int kBubbleContentLabelPreferredWidthDp = 380;

}  // namespace

// Controlled by PaletteWelcomeBubble and anchored to a PaletteTray.
class PaletteWelcomeBubble::WelcomeBubbleView
    : public views::BubbleDialogDelegateView {
  METADATA_HEADER(WelcomeBubbleView, views::BubbleDialogDelegateView)

 public:
  WelcomeBubbleView(views::View* anchor, views::BubbleBorder::Arrow arrow)
      : views::BubbleDialogDelegateView(anchor, arrow) {
    SetTitle(
        l10n_util::GetStringUTF16(IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_TITLE));
    SetShowTitle(true);
    SetShowCloseButton(true);
    SetButtons(static_cast<int>(ui::mojom::DialogButton::kNone));
    set_close_on_deactivate(true);
    SetCanActivate(false);
    set_accept_events(true);
    set_parent_window(
        anchor_widget()->GetNativeWindow()->GetRootWindow()->GetChildById(
            kShellWindowId_SettingBubbleContainer));
    views::BubbleDialogDelegateView::CreateBubble(this);
  }

  WelcomeBubbleView(const WelcomeBubbleView&) = delete;
  WelcomeBubbleView& operator=(const WelcomeBubbleView&) = delete;

  ~WelcomeBubbleView() override = default;

  void Init() override {
    SetUseDefaultFillLayout(true);
    views::Builder<views::BubbleDialogDelegateView>(this)
        .AddChild(views::Builder<views::Label>()
                      .SetText(l10n_util::GetStringUTF16(
                          IDS_ASH_STYLUS_WARM_WELCOME_BUBBLE_DESCRIPTION))
                      .SetHorizontalAlignment(gfx::ALIGN_LEFT)
                      .SetMultiLine(true)
                      .SizeToFit(kBubbleContentLabelPreferredWidthDp))
        .BuildChildren();
  }
};

BEGIN_METADATA(PaletteWelcomeBubble, WelcomeBubbleView)
END_METADATA

PaletteWelcomeBubble::PaletteWelcomeBubble(PaletteTray* tray) : tray_(tray) {
  Shell::Get()->session_controller()->AddObserver(this);
}

PaletteWelcomeBubble::~PaletteWelcomeBubble() {
  DisconnectObservers();
  Shell::Get()->session_controller()->RemoveObserver(this);
  CHECK(!views::WidgetObserver::IsInObserverList());
}

// static
void PaletteWelcomeBubble::RegisterProfilePrefs(PrefRegistrySimple* registry) {
  registry->RegisterBooleanPref(prefs::kShownPaletteWelcomeBubble, false);
}

void PaletteWelcomeBubble::OnWidgetDestroying(views::Widget* widget) {
  DCHECK(bubble_view_ && bubble_view_->GetWidget() == widget);
  DisconnectObservers();
}

void PaletteWelcomeBubble::OnActiveUserPrefServiceChanged(
    PrefService* pref_service) {
  active_user_pref_service_ = pref_service;
}

void PaletteWelcomeBubble::ShowIfNeeded() {
  if (!active_user_pref_service_)
    return;

  // The buble may interfere with some integration tests.
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kAshNoNudges)) {
    return;
  }

  auto* session_controller = Shell::Get()->session_controller();
  if (session_controller->GetSessionState() !=
      session_manager::SessionState::ACTIVE) {
    return;
  }

  if (session_controller->IsRunningInAppMode()) {
    return;
  }

  std::optional<user_manager::UserType> user_type =
      session_controller->GetUserType();
  if (user_type && (*user_type == user_manager::UserType::kGuest ||
                    *user_type == user_manager::UserType::kPublicAccount)) {
    return;
  }

  if (!HasBeenShown())
    Show();
}

bool PaletteWelcomeBubble::HasBeenShown() const {
  return active_user_pref_service_ && active_user_pref_service_->GetBoolean(
                                          prefs::kShownPaletteWelcomeBubble);
}

void PaletteWelcomeBubble::MarkAsShown() {
  DCHECK(active_user_pref_service_);
  active_user_pref_service_->SetBoolean(prefs::kShownPaletteWelcomeBubble,
                                        true);
}

views::View* PaletteWelcomeBubble::GetBubbleViewForTesting() {
  return bubble_view_;
}

void PaletteWelcomeBubble::Show() {
  if (!bubble_view_) {
    DCHECK(tray_);
    bubble_view_ =
        new WelcomeBubbleView(tray_, views::BubbleBorder::BOTTOM_RIGHT);
  }
  MarkAsShown();
  bubble_view_->GetWidget()->Show();
  bubble_view_->GetWidget()->AddObserver(this);
  Shell::Get()->AddPreTargetHandler(this);
}

void PaletteWelcomeBubble::Hide() {
  if (bubble_view_) {
    bubble_view_->GetWidget()->Close();
    DisconnectObservers();
  }
}

void PaletteWelcomeBubble::DisconnectObservers() {
  if (bubble_view_) {
    bubble_view_->GetWidget()->RemoveObserver(this);
    bubble_view_ = nullptr;
  }
  Shell::Get()->RemovePreTargetHandler(this);
}

void PaletteWelcomeBubble::OnMouseEvent(ui::MouseEvent* event) {
  if (bubble_view_ && event->type() == ui::EventType::kMousePressed &&
      event->target() != bubble_view_->GetWidget()->GetNativeView()) {
    bubble_view_->GetWidget()->Close();
  }
}

void PaletteWelcomeBubble::OnTouchEvent(ui::TouchEvent* event) {
  if (bubble_view_ && event->type() == ui::EventType::kTouchPressed &&
      event->target() != bubble_view_->GetWidget()->GetNativeView()) {
    bubble_view_->GetWidget()->Close();
  }
}

}  // namespace ash