chromium/ash/lock_screen_action/lock_screen_action_background_view.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/lock_screen_action/lock_screen_action_background_view.h"

#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/i18n/rtl.h"
#include "base/memory/raw_ptr.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/animation/flood_fill_ink_drop_ripple.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/animation/ink_drop_host.h"
#include "ui/views/animation/ink_drop_impl.h"
#include "ui/views/animation/ink_drop_ripple.h"
#include "ui/views/animation/ink_drop_state.h"
#include "ui/views/animation/square_ink_drop_ripple.h"
#include "ui/views/layout/box_layout.h"

namespace ash {

class LockScreenActionBackgroundView::NoteBackground : public views::View {
  METADATA_HEADER(NoteBackground, views::View)

 public:
  explicit NoteBackground(views::InkDropObserver* observer)
      : observer_(observer) {
    DCHECK(observer);
    views::InkDrop::Install(this, std::make_unique<views::InkDropHost>(this));
    views::InkDrop::Get(this)->SetMode(
        views::InkDropHost::InkDropMode::ON_NO_GESTURE_HANDLER);
    views::InkDrop::Get(this)->SetCreateInkDropCallback(base::BindRepeating(
        [](NoteBackground* host) {
          std::unique_ptr<views::InkDrop> ink_drop =
              views::InkDrop::CreateInkDropWithoutAutoHighlight(
                  views::InkDrop::Get(host), /*highlight_on_hover=*/false);
          ink_drop->AddObserver(host->observer_);
          return ink_drop;
        },
        this));
    views::InkDrop::Get(this)->SetCreateRippleCallback(base::BindRepeating(
        [](NoteBackground* host) -> std::unique_ptr<views::InkDropRipple> {
          const gfx::Point center = base::i18n::IsRTL()
                                        ? host->GetLocalBounds().origin()
                                        : host->GetLocalBounds().top_right();
          auto ink_drop_ripple =
              std::make_unique<views::FloodFillInkDropRipple>(
                  views::InkDrop::Get(host), host->size(), gfx::Insets(),
                  center, views::InkDrop::Get(host)->GetBaseColor(), 1);
          ink_drop_ripple->set_use_hide_transform_duration_for_hide_fade_out(
              true);
          ink_drop_ripple->set_duration_factor(1.5);
          return ink_drop_ripple;
        },
        this));
    views::InkDrop::Get(this)->SetBaseColor(SK_ColorBLACK);
  }

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

  ~NoteBackground() override = default;

 private:
  raw_ptr<views::InkDropObserver> observer_;
};

BEGIN_METADATA(LockScreenActionBackgroundView, NoteBackground)
END_METADATA

LockScreenActionBackgroundView::LockScreenActionBackgroundView() {
  SetCanMaximize(true);
  SetCanFullscreen(true);

  auto layout_manager = std::make_unique<views::BoxLayout>(
      views::BoxLayout::Orientation::kVertical);
  layout_manager->set_cross_axis_alignment(
      views::BoxLayout::CrossAxisAlignment::kStretch);
  auto* layout_ptr = SetLayoutManager(std::move(layout_manager));

  background_ = new NoteBackground(this);
  AddChildView(background_.get());
  // Make background view flexible - the constant does not really matter given
  // that |background_| is the only child, as long as it's greater than 0.
  layout_ptr->SetFlexForView(background_, 1 /*flex_weight*/);
}

LockScreenActionBackgroundView::~LockScreenActionBackgroundView() = default;

void LockScreenActionBackgroundView::AnimateShow(base::OnceClosure done) {
  animation_end_callback_ = std::move(done);
  animating_to_state_ = views::InkDropState::ACTIVATED;

  views::InkDrop::Get(background_)
      ->AnimateToState(views::InkDropState::ACTIVATED, nullptr);
}

void LockScreenActionBackgroundView::AnimateHide(base::OnceClosure done) {
  animation_end_callback_ = std::move(done);
  animating_to_state_ = views::InkDropState::HIDDEN;

  views::InkDrop::Get(background_)
      ->AnimateToState(views::InkDropState::HIDDEN, nullptr);
}

void LockScreenActionBackgroundView::InkDropAnimationStarted() {}

void LockScreenActionBackgroundView::InkDropRippleAnimationEnded(
    views::InkDropState state) {
  // In case |AnimateShow| or |AnimateHide| is called before previous state
  // animation ends, this might get called with the previous target state
  // as the animation is aborted - ignore the event if the |state| does not
  // match the current target state.
  if (animation_end_callback_.is_null() || state != animating_to_state_)
    return;

  std::move(animation_end_callback_).Run();
}

bool LockScreenActionBackgroundView::CanActivate() const {
  return false;
}

views::View* LockScreenActionBackgroundView::GetBackgroundView() {
  return background_;
}

BEGIN_METADATA(LockScreenActionBackgroundView)
END_METADATA

}  // namespace ash