blob: 458182ae4a96805b22e85bc1e4b23e17b869b430 [file] [log] [blame]
// Copyright 2020 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/ambient/test/ambient_ash_test_base.h"
#include <memory>
#include <utility>
#include <vector>
#include "ash/ambient/ambient_access_token_controller.h"
#include "ash/ambient/ambient_constants.h"
#include "ash/ambient/ambient_photo_controller.h"
#include "ash/ambient/test/ambient_ash_test_helper.h"
#include "ash/ambient/ui/ambient_background_image_view.h"
#include "ash/ambient/ui/ambient_container_view.h"
#include "ash/ambient/ui/ambient_view_ids.h"
#include "ash/ambient/ui/media_string_view.h"
#include "ash/ambient/ui/photo_view.h"
#include "ash/public/cpp/ambient/ambient_prefs.h"
#include "ash/public/cpp/ambient/ambient_ui_model.h"
#include "ash/public/cpp/ambient/fake_ambient_backend_controller_impl.h"
#include "ash/root_window_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/idle.pb.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "ui/views/controls/label.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
constexpr float kFastForwardFactor = 1.001;
} // namespace
class TestAmbientPhotoCacheImpl : public AmbientPhotoCache {
public:
TestAmbientPhotoCacheImpl() = default;
~TestAmbientPhotoCacheImpl() override = default;
// AmbientPhotoCache:
void DownloadPhoto(const std::string& url,
base::OnceCallback<void(std::unique_ptr<std::string>)>
callback) override {
// Reply with a unique string each time to avoid check to skip loading
// duplicate images.
std::unique_ptr<std::string> data = std::make_unique<std::string>(
download_data_ ? *download_data_
: base::StringPrintf("test_image_%i", download_count_));
download_count_++;
// Pretend to respond asynchronously.
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(std::move(callback), std::move(data)),
base::TimeDelta::FromMilliseconds(1));
}
void DownloadPhotoToFile(const std::string& url,
base::OnceCallback<void(base::FilePath)> callback,
const base::FilePath& file_path) override {
if (!download_data_) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::FilePath()));
return;
}
if (!WriteFile(file_path, *download_data_)) {
LOG(WARNING) << "error writing file to file_path: " << file_path;
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), base::FilePath()));
return;
}
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), file_path));
}
void DecodePhoto(
std::unique_ptr<std::string> data,
base::OnceCallback<void(const gfx::ImageSkia&)> callback) override {
gfx::ImageSkia image =
decoded_image_ ? *decoded_image_
: gfx::test::CreateImageSkia(decoded_size_.width(),
decoded_size_.height());
// Only use once.
decoded_image_.reset();
// Pretend to respond asynchronously.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), image));
}
void SetDownloadData(std::unique_ptr<std::string> download_data) {
download_data_ = std::move(download_data);
}
void SetDecodedPhotoSize(int width, int height) {
decoded_size_.set_width(width);
decoded_size_.set_height(height);
}
void SetDecodedPhoto(const gfx::ImageSkia& image) { decoded_image_ = image; }
private:
int download_count_ = 0;
// If not null, will return this data when downloading.
std::unique_ptr<std::string> download_data_;
// Width and height of test images.
gfx::Size decoded_size_{10, 20};
// If set, will replay this image.
base::Optional<gfx::ImageSkia> decoded_image_;
};
AmbientAshTestBase::AmbientAshTestBase()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
AmbientAshTestBase::~AmbientAshTestBase() = default;
void AmbientAshTestBase::SetUp() {
AshTestBase::SetUp();
// Need to reset first and then assign the TestPhotoClient because can only
// have one instance of AmbientBackendController.
ambient_controller()->set_backend_controller_for_testing(nullptr);
ambient_controller()->set_backend_controller_for_testing(
std::make_unique<FakeAmbientBackendControllerImpl>());
photo_controller()->set_photo_cache_for_testing(
std::make_unique<TestAmbientPhotoCacheImpl>());
token_controller()->SetTokenUsageBufferForTesting(
base::TimeDelta::FromSeconds(30));
SetAmbientModeEnabled(true);
base::RunLoop().RunUntilIdle();
}
void AmbientAshTestBase::TearDown() {
AshTestBase::TearDown();
}
void AmbientAshTestBase::SetAmbientModeEnabled(bool enabled) {
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
ambient::prefs::kAmbientModeEnabled, enabled);
}
void AmbientAshTestBase::ShowAmbientScreen() {
// The widget will be destroyed in |AshTestBase::TearDown()|.
ambient_controller()->ShowUi();
// The UI only shows when images are downloaded to avoid showing blank screen.
FastForwardToNextImage();
// Flush the message loop to finish all async calls.
base::RunLoop().RunUntilIdle();
}
void AmbientAshTestBase::HideAmbientScreen() {
ambient_controller()->ShowHiddenUi();
}
void AmbientAshTestBase::CloseAmbientScreen() {
ambient_controller()->CloseUi();
}
void AmbientAshTestBase::LockScreen() {
GetSessionControllerClient()->LockScreen();
}
void AmbientAshTestBase::UnlockScreen() {
GetSessionControllerClient()->UnlockScreen();
}
bool AmbientAshTestBase::IsLocked() {
return Shell::Get()->session_controller()->IsScreenLocked();
}
void AmbientAshTestBase::SimulateSystemSuspendAndWait(
power_manager::SuspendImminent::Reason reason) {
chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(reason);
base::RunLoop().RunUntilIdle();
}
void AmbientAshTestBase::SimulateSystemResumeAndWait() {
chromeos::FakePowerManagerClient::Get()->SendSuspendDone();
base::RunLoop().RunUntilIdle();
}
void AmbientAshTestBase::SetScreenIdleStateAndWait(bool is_screen_dimmed,
bool is_off) {
power_manager::ScreenIdleState screen_idle_state;
screen_idle_state.set_dimmed(is_screen_dimmed);
screen_idle_state.set_off(is_off);
chromeos::FakePowerManagerClient::Get()->SendScreenIdleStateChanged(
screen_idle_state);
base::RunLoop().RunUntilIdle();
}
std::vector<views::View*>
AmbientAshTestBase::GetMediaStringViewTextContainers() {
std::vector<views::View*> result;
for (auto* view : GetMediaStringViews())
result.push_back(view->media_text_container_for_testing());
return result;
}
views::View* AmbientAshTestBase::GetMediaStringViewTextContainer() {
return GetMediaStringView()->media_text_container_for_testing();
}
std::vector<views::Label*> AmbientAshTestBase::GetMediaStringViewTextLabels() {
std::vector<views::Label*> result;
for (auto* view : GetMediaStringViews())
result.push_back(view->media_text_label_for_testing());
return result;
}
views::Label* AmbientAshTestBase::GetMediaStringViewTextLabel() {
return GetMediaStringView()->media_text_label_for_testing();
}
void AmbientAshTestBase::SimulateMediaMetadataChanged(
media_session::MediaMetadata metadata) {
for (auto* view : GetMediaStringViews())
view->MediaSessionMetadataChanged(metadata);
}
void AmbientAshTestBase::SimulateMediaPlaybackStateChanged(
media_session::mojom::MediaPlaybackState state) {
for (auto* media_string_view : GetMediaStringViews()) {
// Creates media session info.
media_session::mojom::MediaSessionInfoPtr session_info(
media_session::mojom::MediaSessionInfo::New());
session_info->playback_state = state;
// Simulate media session info changed.
media_string_view->MediaSessionInfoChanged(std::move(session_info));
}
}
void AmbientAshTestBase::SetDecodedPhotoSize(int width, int height) {
auto* photo_cache = static_cast<TestAmbientPhotoCacheImpl*>(
photo_controller()->get_photo_cache_for_testing());
photo_cache->SetDecodedPhotoSize(width, height);
}
std::vector<AmbientBackgroundImageView*>
AmbientAshTestBase::GetAmbientBackgroundImageViews() {
std::vector<AmbientBackgroundImageView*> result;
for (auto* view : GetContainerViews()) {
auto* background_image_view =
view->GetViewByID(AmbientViewID::kAmbientBackgroundImageView);
result.push_back(
static_cast<AmbientBackgroundImageView*>(background_image_view));
}
return result;
}
AmbientBackgroundImageView*
AmbientAshTestBase::GetAmbientBackgroundImageView() {
return static_cast<AmbientBackgroundImageView*>(
GetContainerView()->GetViewByID(kAmbientBackgroundImageView));
}
std::vector<MediaStringView*> AmbientAshTestBase::GetMediaStringViews() {
std::vector<MediaStringView*> result;
for (auto* view : GetContainerViews()) {
auto* media_string_view = view->GetViewByID(kAmbientMediaStringView);
result.push_back(static_cast<MediaStringView*>(media_string_view));
}
return result;
}
MediaStringView* AmbientAshTestBase::GetMediaStringView() {
return static_cast<MediaStringView*>(
GetContainerView()->GetViewByID(kAmbientMediaStringView));
}
void AmbientAshTestBase::FastForwardToLockScreenTimeout() {
task_environment()->FastForwardBy(kFastForwardFactor *
ambient_controller()
->ambient_ui_model()
->lock_screen_inactivity_timeout());
}
void AmbientAshTestBase::FastForwardToNextImage() {
task_environment()->FastForwardBy(
kFastForwardFactor *
ambient_controller()->ambient_ui_model()->photo_refresh_interval());
}
void AmbientAshTestBase::FastForwardTiny() {
// `TestAmbientURLLoaderImpl` has a small delay (1ms) to fake download delay,
// here we fake plenty of time to download the image.
task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(10));
}
void AmbientAshTestBase::FastForwardToBackgroundLockScreenTimeout() {
task_environment()->FastForwardBy(kFastForwardFactor *
ambient_controller()
->ambient_ui_model()
->background_lock_screen_timeout());
}
void AmbientAshTestBase::FastForwardHalfLockScreenDelay() {
task_environment()->FastForwardBy(0.5 * kFastForwardFactor *
ambient_controller()
->ambient_ui_model()
->background_lock_screen_timeout());
}
void AmbientAshTestBase::SetPowerStateCharging() {
power_manager::PowerSupplyProperties proto;
proto.set_battery_state(
power_manager::PowerSupplyProperties_BatteryState_CHARGING);
proto.set_external_power(
power_manager::PowerSupplyProperties_ExternalPower_AC);
PowerStatus::Get()->SetProtoForTesting(proto);
ambient_controller()->OnPowerStatusChanged();
}
void AmbientAshTestBase::SetPowerStateDischarging() {
power_manager::PowerSupplyProperties proto;
proto.set_battery_state(
power_manager::PowerSupplyProperties_BatteryState_DISCHARGING);
proto.set_external_power(
power_manager::PowerSupplyProperties_ExternalPower_DISCONNECTED);
PowerStatus::Get()->SetProtoForTesting(proto);
ambient_controller()->OnPowerStatusChanged();
}
void AmbientAshTestBase::SetPowerStateFull() {
power_manager::PowerSupplyProperties proto;
proto.set_battery_state(
power_manager::PowerSupplyProperties_BatteryState_FULL);
proto.set_external_power(
power_manager::PowerSupplyProperties_ExternalPower_AC);
PowerStatus::Get()->SetProtoForTesting(proto);
ambient_controller()->OnPowerStatusChanged();
}
void AmbientAshTestBase::FastForwardToRefreshWeather() {
task_environment()->FastForwardBy(1.2 * kWeatherRefreshInterval);
}
int AmbientAshTestBase::GetNumOfActiveWakeLocks(
device::mojom::WakeLockType type) {
base::RunLoop run_loop;
int result_count = 0;
GetAmbientAshTestHelper()->wake_lock_provider()->GetActiveWakeLocksForTests(
type, base::BindOnce(
[](base::RunLoop* run_loop, int* result_count, int32_t count) {
*result_count = count;
run_loop->Quit();
},
&run_loop, &result_count));
run_loop.Run();
return result_count;
}
void AmbientAshTestBase::IssueAccessToken(const std::string& token,
bool with_error) {
GetAmbientAshTestHelper()->IssueAccessToken(token, with_error);
}
bool AmbientAshTestBase::IsAccessTokenRequestPending() {
return GetAmbientAshTestHelper()->IsAccessTokenRequestPending();
}
base::TimeDelta AmbientAshTestBase::GetRefreshTokenDelay() {
return token_controller()->GetTimeUntilReleaseForTesting();
}
AmbientController* AmbientAshTestBase::ambient_controller() {
return Shell::Get()->ambient_controller();
}
AmbientPhotoController* AmbientAshTestBase::photo_controller() {
return ambient_controller()->ambient_photo_controller();
}
std::vector<AmbientContainerView*> AmbientAshTestBase::GetContainerViews() {
std::vector<AmbientContainerView*> result;
for (auto* ctrl : RootWindowController::root_window_controllers()) {
auto* widget = ctrl->ambient_widget_for_testing();
if (widget) {
auto* view = widget->GetContentsView();
DCHECK(view && view->GetID() == kAmbientContainerView);
result.push_back(static_cast<AmbientContainerView*>(view));
}
}
return result;
}
AmbientContainerView* AmbientAshTestBase::GetContainerView() {
auto* widget =
Shell::GetPrimaryRootWindowController()->ambient_widget_for_testing();
if (widget) {
auto* container_view = widget->GetContentsView();
DCHECK(container_view && container_view->GetID() == kAmbientContainerView);
return static_cast<AmbientContainerView*>(container_view);
}
return nullptr;
}
AmbientAccessTokenController* AmbientAshTestBase::token_controller() {
return ambient_controller()->access_token_controller_for_testing();
}
FakeAmbientBackendControllerImpl* AmbientAshTestBase::backend_controller() {
return static_cast<FakeAmbientBackendControllerImpl*>(
ambient_controller()->ambient_backend_controller());
}
void AmbientAshTestBase::FetchTopics() {
photo_controller()->FetchTopicsForTesting();
}
void AmbientAshTestBase::FetchImage() {
photo_controller()->FetchImageForTesting();
}
void AmbientAshTestBase::FetchBackupImages() {
photo_controller()->FetchBackupImagesForTesting();
}
void AmbientAshTestBase::SetDownloadPhotoData(std::string data) {
auto* photo_cache = static_cast<TestAmbientPhotoCacheImpl*>(
photo_controller()->get_photo_cache_for_testing());
photo_cache->SetDownloadData(std::make_unique<std::string>(std::move(data)));
}
void AmbientAshTestBase::ClearDownloadPhotoData() {
auto* photo_cache = static_cast<TestAmbientPhotoCacheImpl*>(
photo_controller()->get_photo_cache_for_testing());
photo_cache->SetDownloadData(nullptr);
}
void AmbientAshTestBase::SetDecodePhotoImage(const gfx::ImageSkia& image) {
auto* photo_cache = static_cast<TestAmbientPhotoCacheImpl*>(
photo_controller()->get_photo_cache_for_testing());
photo_cache->SetDecodedPhoto(image);
}
} // namespace ash