[go: nahoru, domu]

blob: 7e5523959ac382a4653e1a4c911c5c3f9e0bd8e3 [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/system/phonehub/phone_hub_notification_controller.h"
#include "ash/constants/ash_features.h"
#include "ash/public/cpp/test/test_system_tray_client.h"
#include "ash/shell.h"
#include "ash/system/message_center/message_center_controller.h"
#include "ash/test/ash_test_base.h"
#include "base/containers/flat_set.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/components/phonehub/fake_feature_status_provider.h"
#include "chromeos/components/phonehub/fake_notification_manager.h"
#include "chromeos/components/phonehub/fake_phone_hub_manager.h"
#include "chromeos/components/phonehub/mutable_phone_model.h"
#include "chromeos/components/phonehub/notification.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/events/event.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/views/notification_view_md.h"
namespace ash {
const int64_t kPhoneHubNotificationId0 = 0;
const int64_t kPhoneHubNotificationId1 = 1;
const int64_t kPhoneHubNotificationId2 = 2;
const char kCrOSNotificationId0[] = "chrome://phonehub-0";
const char kCrOSNotificationId1[] = "chrome://phonehub-1";
const char kCrOSNotificationId2[] = "chrome://phonehub-2";
const char kAppName[] = "Test App";
const char kPackageName[] = "com.google.testapp";
const char kTitle[] = "Test notification";
const char kTextContent[] = "This is a test notification";
const char kNotificationCustomViewType[] = "phonehub";
// Time to wait until we enable the reply button
constexpr base::TimeDelta kWaitForEnableButton =
base::TimeDelta::FromSeconds(1);
chromeos::phonehub::Notification CreateNotification(int64_t id) {
return chromeos::phonehub::Notification(
id,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName,
/*icon=*/gfx::Image()),
base::Time::Now(), chromeos::phonehub::Notification::Importance::kDefault,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kOpenable,
base::UTF8ToUTF16(kTitle), base::UTF8ToUTF16(kTextContent));
}
class PhoneHubNotificationControllerTest : public AshTestBase {
public:
PhoneHubNotificationControllerTest()
: AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
~PhoneHubNotificationControllerTest() override = default;
// AshTestBase:
void SetUp() override {
feature_list_.InitWithFeatures(
{chromeos::features::kPhoneHub, chromeos::features::kEcheSWA}, {});
AshTestBase::SetUp();
feature_status_provider_ =
phone_hub_manager_.fake_feature_status_provider();
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kEnabledAndConnected);
message_center_ = message_center::MessageCenter::Get();
controller_ = Shell::Get()
->message_center_controller()
->phone_hub_notification_controller();
controller_->SetManager(&phone_hub_manager_);
notification_manager_ = phone_hub_manager_.fake_notification_manager();
fake_notifications_.insert(CreateNotification(kPhoneHubNotificationId0));
fake_notifications_.insert(CreateNotification(kPhoneHubNotificationId1));
fake_notifications_.insert(CreateNotification(kPhoneHubNotificationId2));
}
message_center::Notification* FindNotification(const std::string& cros_id) {
return message_center_->FindVisibleNotificationById(cros_id);
}
protected:
base::test::ScopedFeatureList feature_list_;
message_center::MessageCenter* message_center_;
chromeos::phonehub::FakePhoneHubManager phone_hub_manager_;
chromeos::phonehub::FakeNotificationManager* notification_manager_;
chromeos::phonehub::FakeFeatureStatusProvider* feature_status_provider_;
PhoneHubNotificationController* controller_;
base::flat_set<chromeos::phonehub::Notification> fake_notifications_;
};
TEST_F(PhoneHubNotificationControllerTest, AddNotifications) {
EXPECT_FALSE(message_center_->NotificationCount());
notification_manager_->SetNotificationsInternal(fake_notifications_);
EXPECT_EQ(3u, message_center_->NotificationCount());
ASSERT_TRUE(FindNotification(kCrOSNotificationId0));
ASSERT_TRUE(FindNotification(kCrOSNotificationId1));
ASSERT_TRUE(FindNotification(kCrOSNotificationId2));
auto* sample_notification = FindNotification(kCrOSNotificationId1);
EXPECT_EQ(base::UTF8ToUTF16(kTitle), sample_notification->title());
EXPECT_EQ(base::UTF8ToUTF16(kTextContent), sample_notification->message());
}
TEST_F(PhoneHubNotificationControllerTest, UpdateNotifications) {
EXPECT_FALSE(message_center_->NotificationCount());
notification_manager_->SetNotificationsInternal(fake_notifications_);
EXPECT_EQ(3u, message_center_->NotificationCount());
auto* notification = FindNotification(kCrOSNotificationId1);
EXPECT_EQ(base::UTF8ToUTF16(kTitle), notification->title());
EXPECT_EQ(base::UTF8ToUTF16(kTextContent), notification->message());
std::string kNewTitle = "New title";
std::string kNewTextContent = "New text content";
chromeos::phonehub::Notification updated_notification(
kPhoneHubNotificationId1,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName,
/*icon=*/gfx::Image()),
base::Time::Now(), chromeos::phonehub::Notification::Importance::kDefault,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kNone,
base::UTF8ToUTF16(kNewTitle), base::UTF8ToUTF16(kNewTextContent));
notification_manager_->SetNotification(updated_notification);
notification = FindNotification(kCrOSNotificationId1);
EXPECT_EQ(base::UTF8ToUTF16(kNewTitle), notification->title());
EXPECT_EQ(base::UTF8ToUTF16(kNewTextContent), notification->message());
}
TEST_F(PhoneHubNotificationControllerTest, RemoveNotifications) {
EXPECT_FALSE(message_center_->NotificationCount());
notification_manager_->SetNotificationsInternal(fake_notifications_);
EXPECT_EQ(3u, message_center_->NotificationCount());
notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
EXPECT_EQ(2u, message_center_->NotificationCount());
EXPECT_FALSE(FindNotification(kCrOSNotificationId0));
notification_manager_->RemoveNotificationsInternal(base::flat_set<int64_t>(
{kPhoneHubNotificationId1, kPhoneHubNotificationId2}));
EXPECT_FALSE(message_center_->NotificationCount());
// Attempt removing the same notifications again and expect nothing to happen.
notification_manager_->RemoveNotificationsInternal(base::flat_set<int64_t>(
{kPhoneHubNotificationId1, kPhoneHubNotificationId2}));
EXPECT_FALSE(message_center_->NotificationCount());
}
TEST_F(PhoneHubNotificationControllerTest, CloseByUser) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
EXPECT_EQ(3u, message_center_->NotificationCount());
message_center_->RemoveNotification(kCrOSNotificationId0, /*by_user=*/true);
message_center_->RemoveNotification(kCrOSNotificationId1, /*by_user=*/true);
message_center_->RemoveNotification(kCrOSNotificationId2, /*by_user=*/true);
EXPECT_EQ(
std::vector<int64_t>({kPhoneHubNotificationId0, kPhoneHubNotificationId1,
kPhoneHubNotificationId2}),
notification_manager_->dismissed_notification_ids());
}
TEST_F(PhoneHubNotificationControllerTest, InlineReply) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
const std::u16string kInlineReply0 = base::UTF8ToUTF16("inline reply 0");
const std::u16string kInlineReply1 = base::UTF8ToUTF16("inline reply 1");
message_center_->ClickOnNotificationButtonWithReply(kCrOSNotificationId0, 0,
kInlineReply0);
message_center_->ClickOnNotificationButtonWithReply(kCrOSNotificationId1, 0,
kInlineReply1);
auto inline_replies = notification_manager_->inline_replies();
EXPECT_EQ(kPhoneHubNotificationId0, inline_replies[0].notification_id);
EXPECT_EQ(kInlineReply0, inline_replies[0].inline_reply_text);
EXPECT_EQ(kPhoneHubNotificationId1, inline_replies[1].notification_id);
EXPECT_EQ(kInlineReply1, inline_replies[1].inline_reply_text);
}
TEST_F(PhoneHubNotificationControllerTest, HandleNotificationClick) {
chromeos::phonehub::FakeNotificationInteractionHandler* handler =
phone_hub_manager_.fake_notification_interaction_handler();
notification_manager_->SetNotificationsInternal(fake_notifications_);
message_center_->ClickOnNotification(kCrOSNotificationId0);
EXPECT_EQ(1u, handler->handled_notification_count());
message_center_->ClickOnNotification(kCrOSNotificationId1);
EXPECT_EQ(2u, handler->handled_notification_count());
}
TEST_F(PhoneHubNotificationControllerTest, ClickSettings) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
EXPECT_TRUE(FindNotification(kCrOSNotificationId0));
EXPECT_EQ(0, GetSystemTrayClient()->show_connected_devices_settings_count());
message_center_->ClickOnSettingsButton(kCrOSNotificationId0);
EXPECT_EQ(1, GetSystemTrayClient()->show_connected_devices_settings_count());
}
TEST_F(PhoneHubNotificationControllerTest, NotificationDataAndImages) {
base::Time timestamp = base::Time::FromJsTime(12345);
SkBitmap icon_bitmap;
icon_bitmap.allocN32Pixels(32, 32);
gfx::Image icon(gfx::ImageSkia::CreateFrom1xBitmap(icon_bitmap));
SkBitmap contact_image_bitmap;
contact_image_bitmap.allocN32Pixels(80, 80);
gfx::Image contact_image(
gfx::ImageSkia::CreateFrom1xBitmap(contact_image_bitmap));
SkBitmap shared_image_bitmap;
shared_image_bitmap.allocN32Pixels(400, 300);
gfx::Image shared_image(
gfx::ImageSkia::CreateFrom1xBitmap(shared_image_bitmap));
chromeos::phonehub::Notification fake_notification(
kPhoneHubNotificationId0,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName, icon),
timestamp, chromeos::phonehub::Notification::Importance::kHigh,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kNone,
base::UTF8ToUTF16(kTitle), base::UTF8ToUTF16(kTextContent), shared_image,
contact_image);
notification_manager_->SetNotification(fake_notification);
auto* cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(timestamp, cros_notification->timestamp());
EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
EXPECT_EQ(kTitle, base::UTF16ToUTF8(cros_notification->title()));
EXPECT_EQ(kAppName, base::UTF16ToUTF8(cros_notification->display_source()));
// Note that there's a slight discrepancy between the PhoneHub and
// notification image naming.
EXPECT_EQ(contact_image, cros_notification->icon());
EXPECT_EQ(icon, cros_notification->small_image());
EXPECT_EQ(shared_image, cros_notification->image());
}
TEST_F(PhoneHubNotificationControllerTest, NotificationHasCustomViewType) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
auto* notification = FindNotification(kCrOSNotificationId0);
// Notification should have a correct customize type.
EXPECT_EQ(kNotificationCustomViewType, notification->custom_view_type());
}
TEST_F(PhoneHubNotificationControllerTest, NotificationHasPhoneName) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
auto* notification = FindNotification(kCrOSNotificationId0);
const std::u16string expected_phone_name = base::UTF8ToUTF16("Phone name");
phone_hub_manager_.mutable_phone_model()->SetPhoneName(expected_phone_name);
auto notification_view =
PhoneHubNotificationController::CreateCustomNotificationView(
controller_->weak_ptr_factory_.GetWeakPtr(), *notification);
auto* notification_view_md =
static_cast<message_center::NotificationViewMD*>(notification_view.get());
views::Label* summary_text_label =
static_cast<views::Label*>(notification_view_md->GetViewByID(
message_center::NotificationViewMD::kSummaryTextView));
// Notification should contain phone name in the summary text.
EXPECT_EQ(expected_phone_name, summary_text_label->GetText());
}
TEST_F(PhoneHubNotificationControllerTest, ReplyBrieflyDisabled) {
notification_manager_->SetNotificationsInternal(fake_notifications_);
auto* notification = FindNotification(kCrOSNotificationId0);
auto notification_view =
PhoneHubNotificationController::CreateCustomNotificationView(
controller_->weak_ptr_factory_.GetWeakPtr(), *notification);
auto* notification_view_md =
static_cast<message_center::NotificationViewMD*>(notification_view.get());
views::View* action_buttons_row = notification_view_md->GetViewByID(
message_center::NotificationViewMD::kActionButtonsRow);
views::View* reply_button = action_buttons_row->children()[0];
// Initially, reply button should be disabled after replied.
const std::u16string kInlineReply0 = base::UTF8ToUTF16("inline reply 0");
notification_view_md->OnNotificationInputSubmit(0, kInlineReply0);
EXPECT_FALSE(reply_button->GetEnabled());
// After a brief moment, it should be enabled.
task_environment()->FastForwardBy(kWaitForEnableButton);
EXPECT_TRUE(reply_button->GetEnabled());
}
TEST_F(PhoneHubNotificationControllerTest, DoNotReshowPopupNotification) {
chromeos::phonehub::Notification fake_notification(
kPhoneHubNotificationId0,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName,
/*icon=*/gfx::Image()),
base::Time::Now(), chromeos::phonehub::Notification::Importance::kHigh,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kNone,
base::UTF8ToUTF16(kTitle), base::UTF8ToUTF16(kTextContent));
// Adding the notification for the first time shows a pop-up (MAX_PRIORITY).
notification_manager_->SetNotification(fake_notification);
auto* cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kEnabledButDisconnected);
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kEnabledAndConnecting);
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kUnavailableBluetoothOff);
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kLockOrSuspended);
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kEnabledAndConnected);
// Removing and readding the notification (e.g. across disconnects) should
// downgrade the priority so it doesn't pop-up again.
notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
ASSERT_FALSE(FindNotification(kCrOSNotificationId0));
notification_manager_->SetNotification(fake_notification);
cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(message_center::LOW_PRIORITY, cros_notification->priority());
// Disable the feature.
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kDisabled);
notification_manager_->RemoveNotification(kPhoneHubNotificationId0);
ASSERT_FALSE(FindNotification(kCrOSNotificationId0));
// Reconnect and notification should be reshown as a pop-up.
feature_status_provider_->SetStatus(
chromeos::phonehub::FeatureStatus::kEnabledAndConnected);
notification_manager_->SetNotification(fake_notification);
cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
// Update the notification with some new text, but keep the notification ID
// the same.
chromeos::phonehub::Notification modified_fake_notification(
kPhoneHubNotificationId0,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName,
/*icon=*/gfx::Image()),
base::Time::Now(), chromeos::phonehub::Notification::Importance::kHigh,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kNone,
base::UTF8ToUTF16(kTitle), base::UTF8ToUTF16("New text"));
// Update the existingt notification; the priority should be MAX_PRIORITY, and
// renotify should be true.
notification_manager_->SetNotification(modified_fake_notification);
cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
EXPECT_TRUE(cros_notification->renotify());
}
// Regression test for https://crbug.com/1165646.
TEST_F(PhoneHubNotificationControllerTest, MinPriorityNotification) {
chromeos::phonehub::Notification fake_notification(
kPhoneHubNotificationId0,
chromeos::phonehub::Notification::AppMetadata(base::UTF8ToUTF16(kAppName),
kPackageName,
/*icon=*/gfx::Image()),
base::Time::Now(), chromeos::phonehub::Notification::Importance::kMin,
/*inline_reply_id=*/0,
chromeos::phonehub::Notification::InteractionBehavior::kNone,
base::UTF8ToUTF16(kTitle), base::UTF8ToUTF16(kTextContent));
// Adding the notification for the first time shows a pop-up (MAX_PRIORITY),
// even though the notification itself is Importance::kMin.
notification_manager_->SetNotification(fake_notification);
auto* cros_notification = FindNotification(kCrOSNotificationId0);
ASSERT_TRUE(cros_notification);
EXPECT_EQ(message_center::MAX_PRIORITY, cros_notification->priority());
}
} // namespace ash