blob: 8884da8bcbf5b4d52cd1bf66ec0384fb397a9f52 [file] [log] [blame]
// Copyright 2013 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/chromeos/tray_display.h"
#include "ash/display/display_manager.h"
#include "ash/root_window_controller.h"
#include "ash/screen_ash.h"
#include "ash/shell.h"
#include "ash/system/tray/system_tray.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/test_system_tray_delegate.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/ash_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/display.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_list.h"
#include "ui/views/controls/label.h"
namespace ash {
namespace internal {
base::string16 GetTooltipText(const base::string16& headline,
const base::string16& name1,
const std::string& data1,
const base::string16& name2,
const std::string& data2) {
std::vector<base::string16> lines;
lines.push_back(headline);
if (data1.empty()) {
lines.push_back(name1);
} else {
lines.push_back(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
name1, UTF8ToUTF16(data1)));
}
if (!name2.empty()) {
lines.push_back(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
name2, UTF8ToUTF16(data2)));
}
return JoinString(lines, '\n');
}
base::string16 GetMirroredTooltipText(const base::string16& headline,
const base::string16& name,
const std::string& data) {
return GetTooltipText(headline, name, data, base::string16(), "");
}
base::string16 GetFirstDisplayName() {
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
return UTF8ToUTF16(display_manager->GetDisplayNameForId(
display_manager->first_display_id()));
}
base::string16 GetSecondDisplayName() {
return UTF8ToUTF16(
Shell::GetInstance()->display_manager()->GetDisplayNameForId(
ScreenAsh::GetSecondaryDisplay().id()));
}
base::string16 GetMirroredDisplayName() {
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
return UTF8ToUTF16(display_manager->GetDisplayNameForId(
display_manager->mirrored_display_id()));
}
class TrayDisplayTest : public ash::test::AshTestBase {
public:
TrayDisplayTest();
virtual ~TrayDisplayTest();
virtual void SetUp() OVERRIDE;
protected:
SystemTray* tray() { return tray_; }
TrayDisplay* tray_display() { return tray_display_; }
void CloseNotification();
bool IsDisplayVisibleInTray() const;
base::string16 GetTrayDisplayText() const;
base::string16 GetTrayDisplayTooltipText() const;
base::string16 GetDisplayNotificationText() const;
base::string16 GetDisplayNotificationAdditionalText() const;
private:
const message_center::Notification* GetDisplayNotification() const;
// Weak reference, owned by Shell.
SystemTray* tray_;
// Weak reference, owned by |tray_|.
TrayDisplay* tray_display_;
DISALLOW_COPY_AND_ASSIGN(TrayDisplayTest);
};
TrayDisplayTest::TrayDisplayTest() : tray_(NULL), tray_display_(NULL) {
}
TrayDisplayTest::~TrayDisplayTest() {
}
void TrayDisplayTest::SetUp() {
ash::test::AshTestBase::SetUp();
tray_ = Shell::GetPrimaryRootWindowController()->GetSystemTray();
tray_display_ = new TrayDisplay(tray_);
tray_->AddTrayItem(tray_display_);
}
void TrayDisplayTest::CloseNotification() {
message_center::MessageCenter::Get()->RemoveNotification(
TrayDisplay::kNotificationId, false);
RunAllPendingInMessageLoop();
}
bool TrayDisplayTest::IsDisplayVisibleInTray() const {
return tray_->HasSystemBubble() &&
tray_display_->default_view() &&
tray_display_->default_view()->visible();
}
base::string16 TrayDisplayTest::GetTrayDisplayText() const {
return tray_display_->GetDefaultViewMessage();
}
base::string16 TrayDisplayTest::GetTrayDisplayTooltipText() const {
if (!tray_display_->default_view())
return base::string16();
base::string16 tooltip;
if (!tray_display_->default_view()->GetTooltipText(gfx::Point(), &tooltip))
return base::string16();
return tooltip;
}
base::string16 TrayDisplayTest::GetDisplayNotificationText() const {
const message_center::Notification* notification = GetDisplayNotification();
return notification ? notification->title() : base::string16();
}
base::string16 TrayDisplayTest::GetDisplayNotificationAdditionalText() const {
const message_center::Notification* notification = GetDisplayNotification();
return notification ? notification->message() : base::string16();
}
const message_center::Notification* TrayDisplayTest::GetDisplayNotification()
const {
const message_center::NotificationList::Notifications notifications =
message_center::MessageCenter::Get()->GetVisibleNotifications();
for (message_center::NotificationList::Notifications::const_iterator iter =
notifications.begin(); iter != notifications.end(); ++iter) {
if ((*iter)->id() == TrayDisplay::kNotificationId)
return *iter;
}
return NULL;
}
TEST_F(TrayDisplayTest, NoInternalDisplay) {
UpdateDisplay("400x400");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_FALSE(IsDisplayVisibleInTray());
UpdateDisplay("400x400,200x200");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 expected = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL);
base::string16 first_name = GetFirstDisplayName();
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), "200x200"),
GetTrayDisplayTooltipText());
// mirroring
Shell::GetInstance()->display_manager()->SetSoftwareMirroring(true);
UpdateDisplay("400x400,200x200");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
expected = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING_NO_INTERNAL);
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"),
GetTrayDisplayTooltipText());
}
TEST_F(TrayDisplayTest, InternalDisplay) {
UpdateDisplay("400x400");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::SetInternalDisplayId(display_manager->first_display_id());
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_FALSE(IsDisplayVisibleInTray());
// Extended
UpdateDisplay("400x400,200x200");
string16 expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName());
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), "200x200"),
GetTrayDisplayTooltipText());
// Mirroring
display_manager->SetSoftwareMirroring(true);
UpdateDisplay("400x400,200x200");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName());
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"),
GetTrayDisplayTooltipText());
}
TEST_F(TrayDisplayTest, InternalDisplayResized) {
UpdateDisplay("400x400@1.5");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::SetInternalDisplayId(display_manager->first_display_id());
// Shows the tray_display even though there's a single-display.
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 internal_info = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
GetFirstDisplayName(), UTF8ToUTF16("600x600"));
EXPECT_EQ(internal_info, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(base::string16(), GetFirstDisplayName(), "600x600",
base::string16(), std::string()),
GetTrayDisplayTooltipText());
// Extended
UpdateDisplay("400x400@1.5,200x200");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName());
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "600x600",
GetSecondDisplayName(), "200x200"),
GetTrayDisplayTooltipText());
// Mirroring
display_manager->SetSoftwareMirroring(true);
UpdateDisplay("400x400@1.5,200x200");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName());
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "600x600"),
GetTrayDisplayTooltipText());
// Closed lid mode.
display_manager->SetSoftwareMirroring(false);
UpdateDisplay("400x400@1.5,200x200");
gfx::Display::SetInternalDisplayId(ScreenAsh::GetSecondaryDisplay().id());
UpdateDisplay("400x400@1.5");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
expected = l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED);
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(
GetTooltipText(
expected, GetFirstDisplayName(), "600x600", base::string16(), ""),
GetTrayDisplayTooltipText());
}
TEST_F(TrayDisplayTest, ExternalDisplayResized) {
UpdateDisplay("400x400");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::SetInternalDisplayId(display_manager->first_display_id());
// Shows the tray_display even though there's a single-display.
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_FALSE(IsDisplayVisibleInTray());
// Extended
UpdateDisplay("400x400,200x200@1.5");
const gfx::Display& secondary_display = ScreenAsh::GetSecondaryDisplay();
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED,
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
GetSecondDisplayName(),
UTF8ToUTF16(secondary_display.size().ToString())));
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), "300x300"),
GetTrayDisplayTooltipText());
// Mirroring
display_manager->SetSoftwareMirroring(true);
UpdateDisplay("400x400,200x200@1.5");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
expected = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName());
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetMirroredTooltipText(expected, GetFirstDisplayName(), "400x400"),
GetTrayDisplayTooltipText());
}
TEST_F(TrayDisplayTest, OverscanDisplay) {
UpdateDisplay("400x400,300x300/o");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::SetInternalDisplayId(display_manager->first_display_id());
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_TRUE(IsDisplayVisibleInTray());
// /o creates the default overscan, and if overscan is set, the annotation
// should be the size.
base::string16 overscan = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION_OVERSCAN);
base::string16 headline = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED,
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
GetSecondDisplayName(), UTF8ToUTF16("286x286")));
std::string second_data = l10n_util::GetStringFUTF8(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION,
UTF8ToUTF16("286x286"), overscan);
EXPECT_EQ(GetTooltipText(headline, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), second_data),
GetTrayDisplayTooltipText());
// reset the overscan.
display_manager->SetOverscanInsets(
ScreenAsh::GetSecondaryDisplay().id(), gfx::Insets());
headline = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED,
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATED_NAME,
GetSecondDisplayName(), overscan));
second_data = l10n_util::GetStringFUTF8(
IDS_ASH_STATUS_TRAY_DISPLAY_ANNOTATION,
UTF8ToUTF16("300x300"), overscan);
EXPECT_EQ(GetTooltipText(headline, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), second_data),
GetTrayDisplayTooltipText());
}
TEST_F(TrayDisplayTest, UpdateDuringDisplayConfigurationChange) {
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
EXPECT_FALSE(IsDisplayVisibleInTray());
UpdateDisplay("400x400@1.5");
EXPECT_TRUE(tray()->HasSystemBubble());
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 internal_info = l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_SINGLE_DISPLAY,
GetFirstDisplayName(), UTF8ToUTF16("600x600"));
EXPECT_EQ(internal_info, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(base::string16(), GetFirstDisplayName(), "600x600",
base::string16(), std::string()),
GetTrayDisplayTooltipText());
UpdateDisplay("400x400,200x200");
EXPECT_TRUE(tray()->HasSystemBubble());
EXPECT_TRUE(IsDisplayVisibleInTray());
base::string16 expected = l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL);
base::string16 first_name = GetFirstDisplayName();
EXPECT_EQ(expected, GetTrayDisplayText());
EXPECT_EQ(GetTooltipText(expected, GetFirstDisplayName(), "400x400",
GetSecondDisplayName(), "200x200"),
GetTrayDisplayTooltipText());
UpdateDisplay("400x400@1.5");
tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
// Back to the default state, the display tray item should disappear.
UpdateDisplay("400x400");
EXPECT_TRUE(tray()->HasSystemBubble());
EXPECT_FALSE(IsDisplayVisibleInTray());
}
TEST_F(TrayDisplayTest, DisplayNotifications) {
test::TestSystemTrayDelegate* tray_delegate =
static_cast<test::TestSystemTrayDelegate*>(
Shell::GetInstance()->system_tray_delegate());
tray_delegate->set_should_show_display_notification(true);
UpdateDisplay("400x400");
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
gfx::Display::SetInternalDisplayId(display_manager->first_display_id());
EXPECT_TRUE(GetDisplayNotificationText().empty());
// rotation.
UpdateDisplay("400x400/r");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(),
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
CloseNotification();
UpdateDisplay("400x400");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED, GetFirstDisplayName(),
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_STANDARD_ORIENTATION)),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// UI-scale
CloseNotification();
UpdateDisplay("400x400@1.5");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
GetFirstDisplayName(), UTF8ToUTF16("600x600")),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// UI-scale to 1.0
CloseNotification();
UpdateDisplay("400x400");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
GetFirstDisplayName(), UTF8ToUTF16("400x400")),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// No-update
CloseNotification();
UpdateDisplay("400x400");
EXPECT_TRUE(GetDisplayNotificationText().empty());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Extended.
CloseNotification();
UpdateDisplay("400x400,200x200");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Mirroring.
CloseNotification();
display_manager->SetSoftwareMirroring(true);
UpdateDisplay("400x400,200x200");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_MIRRORING, GetMirroredDisplayName()),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Back to extended.
CloseNotification();
display_manager->SetSoftwareMirroring(false);
UpdateDisplay("400x400,200x200");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED, GetSecondDisplayName()),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Resize the first display.
UpdateDisplay("400x400@1.5,200x200");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_RESOLUTION_CHANGED,
GetFirstDisplayName(), UTF8ToUTF16("600x600")),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Rotate the second.
UpdateDisplay("400x400@1.5,200x200/r");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED,
GetSecondDisplayName(),
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)),
GetDisplayNotificationText());
EXPECT_TRUE(GetDisplayNotificationAdditionalText().empty());
// Enters closed lid mode.
UpdateDisplay("400x400@1.5,200x200");
gfx::Display::SetInternalDisplayId(ScreenAsh::GetSecondaryDisplay().id());
UpdateDisplay("400x400@1.5");
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED),
GetDisplayNotificationText());
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISPLAY_DOCKED_DESCRIPTION),
GetDisplayNotificationAdditionalText());
}
TEST_F(TrayDisplayTest, DisplayConfigurationChangedTwice) {
test::TestSystemTrayDelegate* tray_delegate =
static_cast<test::TestSystemTrayDelegate*>(
Shell::GetInstance()->system_tray_delegate());
tray_delegate->set_should_show_display_notification(true);
UpdateDisplay("400x400,200x200");
EXPECT_EQ(
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL),
GetDisplayNotificationText());
// OnDisplayConfigurationChanged() may be called more than once for a single
// update display in case of primary is swapped or recovered from dock mode.
// Should not remove the notification in such case.
tray_display()->OnDisplayConfigurationChanged();
EXPECT_EQ(
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_EXTENDED_NO_INTERNAL),
GetDisplayNotificationText());
// Back to the single display. It SHOULD remove the notification since the
// information is stale.
UpdateDisplay("400x400");
EXPECT_TRUE(GetDisplayNotificationText().empty());
}
TEST_F(TrayDisplayTest, UpdateAfterSuppressDisplayNotification) {
UpdateDisplay("400x400,200x200");
test::TestSystemTrayDelegate* tray_delegate =
static_cast<test::TestSystemTrayDelegate*>(
Shell::GetInstance()->system_tray_delegate());
tray_delegate->set_should_show_display_notification(true);
// rotate the second.
UpdateDisplay("400x400,200x200/r");
EXPECT_EQ(
l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ROTATED,
GetSecondDisplayName(),
l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90)),
GetDisplayNotificationText());
}
} // namespace internal
} // namespace ash