blob: a91bb746182d4dd9b79ef03c6213a9d260801479 [file] [log] [blame]
// Copyright 2016 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 "ash/system/toast/toast_manager.h"
#include <algorithm>
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/threading/thread_task_runner_handle.h"
namespace ash {
namespace {
// Minimum duration for a toast to be visible (in millisecond).
const int32_t kMinimumDurationMs = 200;
} // anonymous namespace
ToastManager::ToastManager()
: locked_(Shell::Get()->session_controller()->IsScreenLocked()),
weak_ptr_factory_(this) {}
ToastManager::~ToastManager() = default;
void ToastManager::Show(const ToastData& data) {
const std::string& id = data.id;
DCHECK(!id.empty());
if (current_toast_data_ && current_toast_data_->id == id) {
// TODO(yoshiki): Replaces the visible toast.
return;
}
auto existing_toast =
std::find_if(queue_.begin(), queue_.end(),
[&id](const ToastData& data) { return data.id == id; });
if (existing_toast == queue_.end()) {
queue_.emplace_back(data);
} else {
*existing_toast = data;
}
if (queue_.size() == 1 && overlay_ == nullptr)
ShowLatest();
}
void ToastManager::Cancel(const std::string& id) {
if (current_toast_data_ && current_toast_data_->id == id) {
overlay_->Show(false);
return;
}
auto cancelled_toast =
std::find_if(queue_.begin(), queue_.end(),
[&id](const ToastData& data) { return data.id == id; });
if (cancelled_toast != queue_.end())
queue_.erase(cancelled_toast);
}
void ToastManager::OnClosed() {
overlay_.reset();
current_toast_data_.reset();
// Show the next toast if available.
// Note that don't show during the lock state is changing, since we reshow
// manually after the state is changed. See OnLockStateChanged.
if (!queue_.empty())
ShowLatest();
}
void ToastManager::ShowLatest() {
DCHECK(!overlay_);
DCHECK(!current_toast_data_);
auto it = locked_ ? std::find_if(queue_.begin(), queue_.end(),
[](const auto& data) {
return data.visible_on_lock_screen;
})
: queue_.begin();
if (it == queue_.end())
return;
current_toast_data_ = *it;
queue_.erase(it);
serial_++;
overlay_ = std::make_unique<ToastOverlay>(
this, current_toast_data_->text, current_toast_data_->dismiss_text,
current_toast_data_->visible_on_lock_screen && locked_);
overlay_->Show(true);
if (current_toast_data_->duration_ms != ToastData::kInfiniteDuration) {
int32_t duration_ms =
std::max(current_toast_data_->duration_ms, kMinimumDurationMs);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&ToastManager::OnDurationPassed,
weak_ptr_factory_.GetWeakPtr(), serial_),
base::TimeDelta::FromMilliseconds(duration_ms));
}
}
void ToastManager::OnDurationPassed(int toast_number) {
if (overlay_ && serial_ == toast_number)
overlay_->Show(false);
}
void ToastManager::OnSessionStateChanged(session_manager::SessionState state) {
const bool locked = state != session_manager::SessionState::ACTIVE;
if ((locked != locked_) && current_toast_data_) {
// Re-queue the currently visible toast which is not for lock screen.
queue_.push_front(*current_toast_data_);
current_toast_data_.reset();
// Hide the currently visible toast without any animation.
overlay_.reset();
}
locked_ = locked;
if (!queue_.empty()) {
// Try to reshow a queued toast from a previous OnSessionStateChanged.
ShowLatest();
}
}
} // namespace ash